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]>
26 section
: SectionIndex
,
27 string_section
: SectionIndex
,
28 shndx_section
: SectionIndex
,
29 symbols
: &'data
[Elf
::Sym
],
30 strings
: StringTable
<'data
, R
>,
34 impl<'data
, Elf
: FileHeader
, R
: ReadRef
<'data
>> Default
for SymbolTable
<'data
, Elf
, R
> {
35 fn default() -> Self {
37 section
: SectionIndex(0),
38 string_section
: SectionIndex(0),
39 shndx_section
: SectionIndex(0),
41 strings
: Default
::default(),
47 impl<'data
, Elf
: FileHeader
, R
: ReadRef
<'data
>> SymbolTable
<'data
, Elf
, R
> {
48 /// Parse the given symbol table section.
52 sections
: &SectionTable
<'data
, Elf
, R
>,
53 section_index
: SectionIndex
,
54 section
: &Elf
::SectionHeader
,
55 ) -> read
::Result
<SymbolTable
<'data
, Elf
, R
>> {
57 section
.sh_type(endian
) == elf
::SHT_DYNSYM
58 || section
.sh_type(endian
) == elf
::SHT_SYMTAB
62 .data_as_array(endian
, data
)
63 .read_error("Invalid ELF symbol table data")?
;
65 let link
= SectionIndex(section
.sh_link(endian
) as usize);
66 let strings
= sections
.strings(endian
, data
, link
)?
;
68 let mut shndx_section
= SectionIndex(0);
69 let mut shndx
= &[][..];
70 for (i
, s
) in sections
.iter().enumerate() {
71 if s
.sh_type(endian
) == elf
::SHT_SYMTAB_SHNDX
72 && s
.sh_link(endian
) as usize == section_index
.0
74 shndx_section
= SectionIndex(i
);
76 .data_as_array(endian
, data
)
77 .read_error("Invalid ELF symtab_shndx data")?
;
82 section
: section_index
,
91 /// Return the section index of this symbol table.
93 pub fn section(&self) -> SectionIndex
{
97 /// Return the section index of the shndx table.
99 pub fn shndx_section(&self) -> SectionIndex
{
103 /// Return the section index of the linked string table.
105 pub fn string_section(&self) -> SectionIndex
{
109 /// Return the string table used for the symbol names.
111 pub fn strings(&self) -> StringTable
<'data
, R
> {
115 /// Return the symbol table.
117 pub fn symbols(&self) -> &'data
[Elf
::Sym
] {
121 /// Iterate over the symbols.
123 pub fn iter(&self) -> slice
::Iter
<'data
, Elf
::Sym
> {
127 /// Return true if the symbol table is empty.
129 pub fn is_empty(&self) -> bool
{
130 self.symbols
.is_empty()
133 /// The number of symbols.
135 pub fn len(&self) -> usize {
139 /// Return the symbol at the given index.
140 pub fn symbol(&self, index
: usize) -> read
::Result
<&'data Elf
::Sym
> {
143 .read_error("Invalid ELF symbol index")
146 /// Return the extended section index for the given symbol if present.
148 pub fn shndx(&self, index
: usize) -> Option
<u32> {
149 self.shndx
.get(index
).copied()
152 /// Return the section index for the given symbol.
154 /// This uses the extended section index if present.
155 pub fn symbol_section(
158 symbol
: &'data Elf
::Sym
,
160 ) -> read
::Result
<Option
<SectionIndex
>> {
161 match symbol
.st_shndx(endian
) {
162 elf
::SHN_UNDEF
=> Ok(None
),
163 elf
::SHN_XINDEX
=> self
165 .read_error("Missing ELF symbol extended index")
166 .map(|index
| Some(SectionIndex(index
as usize))),
167 shndx
if shndx
< elf
::SHN_LORESERVE
=> Ok(Some(SectionIndex(shndx
.into()))),
172 /// Return the symbol name for the given symbol.
176 symbol
: &'data Elf
::Sym
,
177 ) -> read
::Result
<&'data
[u8]> {
178 symbol
.name(endian
, self.strings
)
181 /// Construct a map from addresses to a user-defined map entry.
182 pub fn map
<Entry
: SymbolMapEntry
, F
: Fn(&'data Elf
::Sym
) -> Option
<Entry
>>(
186 ) -> SymbolMap
<Entry
> {
187 let mut symbols
= Vec
::with_capacity(self.symbols
.len());
188 for symbol
in self.symbols
{
189 if !symbol
.is_definition(endian
) {
192 if let Some(entry
) = f(symbol
) {
196 SymbolMap
::new(symbols
)
200 /// A symbol table of an `ElfFile32`.
201 pub type ElfSymbolTable32
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
202 ElfSymbolTable
<'data
, 'file
, elf
::FileHeader32
<Endian
>, R
>;
203 /// A symbol table of an `ElfFile32`.
204 pub type ElfSymbolTable64
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
205 ElfSymbolTable
<'data
, 'file
, elf
::FileHeader64
<Endian
>, R
>;
207 /// A symbol table of an `ElfFile`.
208 #[derive(Debug, Clone, Copy)]
209 pub struct ElfSymbolTable
<'data
, 'file
, Elf
, R
= &'data
[u8]>
215 pub(super) endian
: Elf
::Endian
,
216 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
, R
>,
219 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> read
::private
::Sealed
220 for ElfSymbolTable
<'data
, 'file
, Elf
, R
>
224 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> ObjectSymbolTable
<'data
>
225 for ElfSymbolTable
<'data
, 'file
, Elf
, R
>
227 type Symbol
= ElfSymbol
<'data
, 'file
, Elf
, R
>;
228 type SymbolIterator
= ElfSymbolIterator
<'data
, 'file
, Elf
, R
>;
230 fn symbols(&self) -> Self::SymbolIterator
{
233 symbols
: self.symbols
,
238 fn symbol_by_index(&self, index
: SymbolIndex
) -> read
::Result
<Self::Symbol
> {
239 let symbol
= self.symbols
.symbol(index
.0)?
;
242 symbols
: self.symbols
,
249 /// An iterator over the symbols of an `ElfFile32`.
250 pub type ElfSymbolIterator32
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
251 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader32
<Endian
>, R
>;
252 /// An iterator over the symbols of an `ElfFile64`.
253 pub type ElfSymbolIterator64
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
254 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader64
<Endian
>, R
>;
256 /// An iterator over the symbols of an `ElfFile`.
257 pub struct ElfSymbolIterator
<'data
, 'file
, Elf
, R
= &'data
[u8]>
263 pub(super) endian
: Elf
::Endian
,
264 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
, R
>,
265 pub(super) index
: usize,
268 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> fmt
::Debug
269 for ElfSymbolIterator
<'data
, 'file
, Elf
, R
>
271 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
272 f
.debug_struct("ElfSymbolIterator").finish()
276 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> Iterator
277 for ElfSymbolIterator
<'data
, 'file
, Elf
, R
>
279 type Item
= ElfSymbol
<'data
, 'file
, Elf
, R
>;
281 fn next(&mut self) -> Option
<Self::Item
> {
282 let index
= self.index
;
283 let symbol
= self.symbols
.symbols
.get(index
)?
;
287 symbols
: self.symbols
,
288 index
: SymbolIndex(index
),
294 /// A symbol of an `ElfFile32`.
295 pub type ElfSymbol32
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
296 ElfSymbol
<'data
, 'file
, elf
::FileHeader32
<Endian
>, R
>;
297 /// A symbol of an `ElfFile64`.
298 pub type ElfSymbol64
<'data
, 'file
, Endian
= Endianness
, R
= &'data
[u8]> =
299 ElfSymbol
<'data
, 'file
, elf
::FileHeader64
<Endian
>, R
>;
301 /// A symbol of an `ElfFile`.
302 #[derive(Debug, Clone, Copy)]
303 pub struct ElfSymbol
<'data
, 'file
, Elf
, R
= &'data
[u8]>
309 pub(super) endian
: Elf
::Endian
,
310 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
, R
>,
311 pub(super) index
: SymbolIndex
,
312 pub(super) symbol
: &'data Elf
::Sym
,
315 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> read
::private
::Sealed
316 for ElfSymbol
<'data
, 'file
, Elf
, R
>
320 impl<'data
, 'file
, Elf
: FileHeader
, R
: ReadRef
<'data
>> ObjectSymbol
<'data
>
321 for ElfSymbol
<'data
, 'file
, Elf
, R
>
324 fn index(&self) -> SymbolIndex
{
328 fn name_bytes(&self) -> read
::Result
<&'data
[u8]> {
329 self.symbol
.name(self.endian
, self.symbols
.strings())
332 fn name(&self) -> read
::Result
<&'data
str> {
333 let name
= self.name_bytes()?
;
336 .read_error("Non UTF-8 ELF symbol name")
340 fn address(&self) -> u64 {
341 self.symbol
.st_value(self.endian
).into()
345 fn size(&self) -> u64 {
346 self.symbol
.st_size(self.endian
).into()
349 fn kind(&self) -> SymbolKind
{
350 match self.symbol
.st_type() {
351 elf
::STT_NOTYPE
if self.index
.0 == 0 => SymbolKind
::Null
,
352 elf
::STT_OBJECT
| elf
::STT_COMMON
=> SymbolKind
::Data
,
353 elf
::STT_FUNC
=> SymbolKind
::Text
,
354 elf
::STT_SECTION
=> SymbolKind
::Section
,
355 elf
::STT_FILE
=> SymbolKind
::File
,
356 elf
::STT_TLS
=> SymbolKind
::Tls
,
357 _
=> SymbolKind
::Unknown
,
361 fn section(&self) -> SymbolSection
{
362 match self.symbol
.st_shndx(self.endian
) {
363 elf
::SHN_UNDEF
=> SymbolSection
::Undefined
,
365 if self.symbol
.st_type() == elf
::STT_FILE
{
368 SymbolSection
::Absolute
371 elf
::SHN_COMMON
=> SymbolSection
::Common
,
372 elf
::SHN_XINDEX
=> match self.symbols
.shndx(self.index
.0) {
373 Some(index
) => SymbolSection
::Section(SectionIndex(index
as usize)),
374 None
=> SymbolSection
::Unknown
,
376 index
if index
< elf
::SHN_LORESERVE
=> {
377 SymbolSection
::Section(SectionIndex(index
as usize))
379 _
=> SymbolSection
::Unknown
,
384 fn is_undefined(&self) -> bool
{
385 self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
389 fn is_definition(&self) -> bool
{
390 self.symbol
.is_definition(self.endian
)
394 fn is_common(&self) -> bool
{
395 self.symbol
.st_shndx(self.endian
) == elf
::SHN_COMMON
399 fn is_weak(&self) -> bool
{
400 self.symbol
.st_bind() == elf
::STB_WEAK
403 fn scope(&self) -> SymbolScope
{
404 if self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
{
407 match self.symbol
.st_bind() {
408 elf
::STB_LOCAL
=> SymbolScope
::Compilation
,
409 elf
::STB_GLOBAL
| elf
::STB_WEAK
=> {
410 if self.symbol
.st_visibility() == elf
::STV_HIDDEN
{
416 _
=> SymbolScope
::Unknown
,
422 fn is_global(&self) -> bool
{
423 self.symbol
.st_bind() != elf
::STB_LOCAL
427 fn is_local(&self) -> bool
{
428 self.symbol
.st_bind() == elf
::STB_LOCAL
432 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
434 st_info
: self.symbol
.st_info(),
435 st_other
: self.symbol
.st_other(),
440 /// A trait for generic access to `Sym32` and `Sym64`.
441 #[allow(missing_docs)]
442 pub trait Sym
: Debug
+ Pod
{
443 type Word
: Into
<u64>;
444 type Endian
: endian
::Endian
;
446 fn st_name(&self, endian
: Self::Endian
) -> u32;
447 fn st_info(&self) -> u8;
448 fn st_bind(&self) -> u8;
449 fn st_type(&self) -> u8;
450 fn st_other(&self) -> u8;
451 fn st_visibility(&self) -> u8;
452 fn st_shndx(&self, endian
: Self::Endian
) -> u16;
453 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
;
454 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
;
456 /// Parse the symbol name from the string table.
457 fn name
<'data
, R
: ReadRef
<'data
>>(
459 endian
: Self::Endian
,
460 strings
: StringTable
<'data
, R
>,
461 ) -> read
::Result
<&'data
[u8]> {
463 .get(self.st_name(endian
))
464 .read_error("Invalid ELF symbol name offset")
467 /// Return true if the symbol is undefined.
469 fn is_undefined(&self, endian
: Self::Endian
) -> bool
{
470 self.st_shndx(endian
) == elf
::SHN_UNDEF
473 /// Return true if the symbol is a definition of a function or data object.
474 fn is_definition(&self, endian
: Self::Endian
) -> bool
{
475 let st_type
= self.st_type();
476 (st_type
== elf
::STT_NOTYPE
|| st_type
== elf
::STT_FUNC
|| st_type
== elf
::STT_OBJECT
)
477 && self.st_shndx(endian
) != elf
::SHN_UNDEF
481 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym32
<Endian
> {
483 type Endian
= Endian
;
486 fn st_name(&self, endian
: Self::Endian
) -> u32 {
487 self.st_name
.get(endian
)
491 fn st_info(&self) -> u8 {
496 fn st_bind(&self) -> u8 {
501 fn st_type(&self) -> u8 {
506 fn st_other(&self) -> u8 {
511 fn st_visibility(&self) -> u8 {
516 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
517 self.st_shndx
.get(endian
)
521 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
522 self.st_value
.get(endian
)
526 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
527 self.st_size
.get(endian
)
531 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym64
<Endian
> {
533 type Endian
= Endian
;
536 fn st_name(&self, endian
: Self::Endian
) -> u32 {
537 self.st_name
.get(endian
)
541 fn st_info(&self) -> u8 {
546 fn st_bind(&self) -> u8 {
551 fn st_type(&self) -> u8 {
556 fn st_other(&self) -> u8 {
561 fn st_visibility(&self) -> u8 {
566 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
567 self.st_shndx
.get(endian
)
571 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
572 self.st_value
.get(endian
)
576 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
577 self.st_size
.get(endian
)