8 use crate::endian
::{self, Endianness}
;
10 use crate::read
::util
::StringTable
;
12 self, ObjectSymbol
, ObjectSymbolTable
, ReadError
, ReadRef
, SectionIndex
, SymbolFlags
,
13 SymbolIndex
, SymbolKind
, SymbolMap
, SymbolMapEntry
, SymbolScope
, SymbolSection
,
16 use super::{FileHeader, SectionHeader, SectionTable}
;
18 /// A table of symbol entries in an ELF file.
20 /// Also includes the string table used for the symbol names.
21 #[derive(Debug, Clone, Copy)]
22 pub struct SymbolTable
<'data
, Elf
: FileHeader
, R
= &'data
[u8]>
27 symbols
: &'data
[Elf
::Sym
],
28 strings
: StringTable
<'data
, R
>,
32 impl<'data
, Elf
: FileHeader
, R
: ReadRef
<'data
>> Default
for SymbolTable
<'data
, Elf
, R
> {
33 fn default() -> Self {
37 strings
: Default
::default(),
43 impl<'data
, Elf
: FileHeader
, R
: ReadRef
<'data
>> SymbolTable
<'data
, Elf
, R
> {
44 /// Parse the given symbol table section.
48 sections
: &SectionTable
<'data
, Elf
, R
>,
50 section
: &Elf
::SectionHeader
,
51 ) -> read
::Result
<SymbolTable
<'data
, Elf
, R
>> {
53 section
.sh_type(endian
) == elf
::SHT_DYNSYM
54 || section
.sh_type(endian
) == elf
::SHT_SYMTAB
58 .data_as_array(endian
, data
)
59 .read_error("Invalid ELF symbol table data")?
;
61 let strtab
= sections
.section(section
.sh_link(endian
) as usize)?
;
62 let strings
= if let Some((str_offset
, str_size
)) = strtab
.file_range(endian
) {
63 let str_end
= str_offset
64 .checked_add(str_size
)
65 .read_error("Invalid str_size")?
;
66 StringTable
::new(data
, str_offset
, str_end
)
68 StringTable
::default()
74 s
.sh_type(endian
) == elf
::SHT_SYMTAB_SHNDX
75 && s
.sh_link(endian
) as usize == section_index
79 .data_as_array(endian
, data
)
80 .read_error("Invalid ELF symtab_shndx data")
86 section
: section_index
,
93 /// Return the section index of this symbol table.
95 pub fn section(&self) -> usize {
99 /// Return the string table used for the symbol names.
101 pub fn strings(&self) -> StringTable
<'data
, R
> {
105 /// Return the symbol table.
107 pub fn symbols(&self) -> &'data
[Elf
::Sym
] {
111 /// Iterate over the symbols.
113 pub fn iter(&self) -> slice
::Iter
<'data
, Elf
::Sym
> {
117 /// Return true if the symbol table is empty.
119 pub fn is_empty(&self) -> bool
{
120 self.symbols
.is_empty()
123 /// The number of symbols.
125 pub fn len(&self) -> usize {
129 /// Return the symbol at the given index.
130 pub fn symbol(&self, index
: usize) -> read
::Result
<&'data Elf
::Sym
> {
133 .read_error("Invalid ELF symbol index")
136 /// Return the extended section index for the given symbol if present.
138 pub fn shndx(&self, index
: usize) -> Option
<u32> {
139 self.shndx
.get(index
).cloned()
142 /// Return the symbol name for the given symbol.
146 symbol
: &'data Elf
::Sym
,
147 ) -> read
::Result
<&'data
[u8]> {
148 symbol
.name(endian
, self.strings
)
151 /// Construct a map from addresses to a user-defined map entry.
152 pub fn map
<Entry
: SymbolMapEntry
, F
: Fn(&'data Elf
::Sym
) -> Option
<Entry
>>(
156 ) -> SymbolMap
<Entry
> {
157 let mut symbols
= Vec
::with_capacity(self.symbols
.len());
158 for symbol
in self.symbols
{
159 if !symbol
.is_definition(endian
) {
162 if let Some(entry
) = f(symbol
) {
166 SymbolMap
::new(symbols
)
170 /// A symbol table of an `ElfFile32`.
171 pub type ElfSymbolTable32
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
172 ElfSymbolTable
<'data
, 'file
, elf
::FileHeader32
<Endian
>, R
>;
173 /// A symbol table of an `ElfFile32`.
174 pub type ElfSymbolTable64
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
175 ElfSymbolTable
<'data
, 'file
, elf
::FileHeader64
<Endian
>, R
>;
177 /// A symbol table of an `ElfFile`.
178 #[derive(Debug, Clone, Copy)]
179 pub struct ElfSymbolTable
<'data
, 'file
, Elf
, R
= &'data
[u8]>
185 pub(super) endian
: Elf
::Endian
,
186 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
, R
>,
189 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> read
::private
::Sealed
190 for ElfSymbolTable
<'data
, 'file
, Elf
, R
>
194 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> ObjectSymbolTable
<'data
>
195 for ElfSymbolTable
<'data
, 'file
, Elf
, R
>
197 type Symbol
= ElfSymbol
<'data
, 'file
, Elf
, R
>;
198 type SymbolIterator
= ElfSymbolIterator
<'data
, 'file
, Elf
, R
>;
200 fn symbols(&self) -> Self::SymbolIterator
{
203 symbols
: self.symbols
,
208 fn symbol_by_index(&self, index
: SymbolIndex
) -> read
::Result
<Self::Symbol
> {
209 let symbol
= self.symbols
.symbol(index
.0)?
;
212 symbols
: self.symbols
,
219 /// An iterator over the symbols of an `ElfFile32`.
220 pub type ElfSymbolIterator32
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
221 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader32
<Endian
>, R
>;
222 /// An iterator over the symbols of an `ElfFile64`.
223 pub type ElfSymbolIterator64
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
224 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader64
<Endian
>, R
>;
226 /// An iterator over the symbols of an `ElfFile`.
227 pub struct ElfSymbolIterator
<'data
, 'file
, Elf
, R
= &'data
[u8]>
233 pub(super) endian
: Elf
::Endian
,
234 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
, R
>,
235 pub(super) index
: usize,
238 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> fmt
::Debug
239 for ElfSymbolIterator
<'data
, 'file
, Elf
, R
>
241 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
242 f
.debug_struct("ElfSymbolIterator").finish()
246 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> Iterator
247 for ElfSymbolIterator
<'data
, 'file
, Elf
, R
>
249 type Item
= ElfSymbol
<'data
, 'file
, Elf
, R
>;
251 fn next(&mut self) -> Option
<Self::Item
> {
252 let index
= self.index
;
253 let symbol
= self.symbols
.symbols
.get(index
)?
;
257 symbols
: self.symbols
,
258 index
: SymbolIndex(index
),
264 /// A symbol of an `ElfFile32`.
265 pub type ElfSymbol32
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
266 ElfSymbol
<'data
, 'file
, elf
::FileHeader32
<Endian
>, R
>;
267 /// A symbol of an `ElfFile64`.
268 pub type ElfSymbol64
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
269 ElfSymbol
<'data
, 'file
, elf
::FileHeader64
<Endian
>, R
>;
271 /// A symbol of an `ElfFile`.
272 #[derive(Debug, Clone, Copy)]
273 pub struct ElfSymbol
<'data
, 'file
, Elf
, R
= &'data
[u8]>
279 pub(super) endian
: Elf
::Endian
,
280 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
, R
>,
281 pub(super) index
: SymbolIndex
,
282 pub(super) symbol
: &'data Elf
::Sym
,
285 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> read
::private
::Sealed
286 for ElfSymbol
<'data
, 'file
, Elf
, R
>
290 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> ObjectSymbol
<'data
>
291 for ElfSymbol
<'data
, 'file
, Elf
, R
>
294 fn index(&self) -> SymbolIndex
{
298 fn name(&self) -> read
::Result
<&'data
str> {
299 let name
= self.symbol
.name(self.endian
, self.symbols
.strings())?
;
302 .read_error("Non UTF-8 ELF symbol name")
306 fn address(&self) -> u64 {
307 self.symbol
.st_value(self.endian
).into()
311 fn size(&self) -> u64 {
312 self.symbol
.st_size(self.endian
).into()
315 fn kind(&self) -> SymbolKind
{
316 match self.symbol
.st_type() {
317 elf
::STT_NOTYPE
if self.index
.0 == 0 => SymbolKind
::Null
,
318 elf
::STT_OBJECT
| elf
::STT_COMMON
=> SymbolKind
::Data
,
319 elf
::STT_FUNC
=> SymbolKind
::Text
,
320 elf
::STT_SECTION
=> SymbolKind
::Section
,
321 elf
::STT_FILE
=> SymbolKind
::File
,
322 elf
::STT_TLS
=> SymbolKind
::Tls
,
323 _
=> SymbolKind
::Unknown
,
327 fn section(&self) -> SymbolSection
{
328 match self.symbol
.st_shndx(self.endian
) {
329 elf
::SHN_UNDEF
=> SymbolSection
::Undefined
,
331 if self.symbol
.st_type() == elf
::STT_FILE
{
334 SymbolSection
::Absolute
337 elf
::SHN_COMMON
=> SymbolSection
::Common
,
338 elf
::SHN_XINDEX
=> match self.symbols
.shndx(self.index
.0) {
339 Some(index
) => SymbolSection
::Section(SectionIndex(index
as usize)),
340 None
=> SymbolSection
::Unknown
,
342 index
if index
< elf
::SHN_LORESERVE
=> {
343 SymbolSection
::Section(SectionIndex(index
as usize))
345 _
=> SymbolSection
::Unknown
,
350 fn is_undefined(&self) -> bool
{
351 self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
355 fn is_definition(&self) -> bool
{
356 self.symbol
.is_definition(self.endian
)
360 fn is_common(&self) -> bool
{
361 self.symbol
.st_shndx(self.endian
) == elf
::SHN_COMMON
365 fn is_weak(&self) -> bool
{
366 self.symbol
.st_bind() == elf
::STB_WEAK
369 fn scope(&self) -> SymbolScope
{
370 if self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
{
373 match self.symbol
.st_bind() {
374 elf
::STB_LOCAL
=> SymbolScope
::Compilation
,
375 elf
::STB_GLOBAL
| elf
::STB_WEAK
=> {
376 if self.symbol
.st_visibility() == elf
::STV_HIDDEN
{
382 _
=> SymbolScope
::Unknown
,
388 fn is_global(&self) -> bool
{
389 self.symbol
.st_bind() != elf
::STB_LOCAL
393 fn is_local(&self) -> bool
{
394 self.symbol
.st_bind() == elf
::STB_LOCAL
398 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
400 st_info
: self.symbol
.st_info(),
401 st_other
: self.symbol
.st_other(),
406 /// A trait for generic access to `Sym32` and `Sym64`.
407 #[allow(missing_docs)]
408 pub trait Sym
: Debug
+ Pod
{
409 type Word
: Into
<u64>;
410 type Endian
: endian
::Endian
;
412 fn st_name(&self, endian
: Self::Endian
) -> u32;
413 fn st_info(&self) -> u8;
414 fn st_bind(&self) -> u8;
415 fn st_type(&self) -> u8;
416 fn st_other(&self) -> u8;
417 fn st_visibility(&self) -> u8;
418 fn st_shndx(&self, endian
: Self::Endian
) -> u16;
419 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
;
420 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
;
422 /// Parse the symbol name from the string table.
423 fn name
<'data
, R
: ReadRef
<'data
>>(
425 endian
: Self::Endian
,
426 strings
: StringTable
<'data
, R
>,
427 ) -> read
::Result
<&'data
[u8]> {
429 .get(self.st_name(endian
))
430 .read_error("Invalid ELF symbol name offset")
433 /// Return true if the symbol is undefined.
435 fn is_undefined(&self, endian
: Self::Endian
) -> bool
{
436 self.st_shndx(endian
) == elf
::SHN_UNDEF
439 /// Return true if the symbol is a definition of a function or data object.
440 fn is_definition(&self, endian
: Self::Endian
) -> bool
{
441 let st_type
= self.st_type();
442 (st_type
== elf
::STT_NOTYPE
|| st_type
== elf
::STT_FUNC
|| st_type
== elf
::STT_OBJECT
)
443 && self.st_shndx(endian
) != elf
::SHN_UNDEF
447 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym32
<Endian
> {
449 type Endian
= Endian
;
452 fn st_name(&self, endian
: Self::Endian
) -> u32 {
453 self.st_name
.get(endian
)
457 fn st_info(&self) -> u8 {
462 fn st_bind(&self) -> u8 {
467 fn st_type(&self) -> u8 {
472 fn st_other(&self) -> u8 {
477 fn st_visibility(&self) -> u8 {
482 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
483 self.st_shndx
.get(endian
)
487 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
488 self.st_value
.get(endian
)
492 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
493 self.st_size
.get(endian
)
497 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym64
<Endian
> {
499 type Endian
= Endian
;
502 fn st_name(&self, endian
: Self::Endian
) -> u32 {
503 self.st_name
.get(endian
)
507 fn st_info(&self) -> u8 {
512 fn st_bind(&self) -> u8 {
517 fn st_type(&self) -> u8 {
522 fn st_other(&self) -> u8 {
527 fn st_visibility(&self) -> u8 {
532 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
533 self.st_shndx
.get(endian
)
537 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
538 self.st_value
.get(endian
)
542 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
543 self.st_size
.get(endian
)