7 use crate::endian
::{self, Endianness}
;
9 use crate::read
::util
::StringTable
;
11 self, ObjectSymbol
, ObjectSymbolTable
, ReadError
, ReadRef
, SectionIndex
, SymbolFlags
,
12 SymbolIndex
, SymbolKind
, SymbolMap
, SymbolMapEntry
, SymbolScope
, SymbolSection
,
14 use crate::{elf, U32}
;
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
>,
31 shndx
: &'data
[U32
<Elf
::Endian
>],
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, endian
: Elf
::Endian
, index
: usize) -> Option
<u32> {
149 self.shndx
.get(index
).map(|x
| x
.get(endian
))
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
164 .shndx(endian
, index
)
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_NOTYPE
=> SymbolKind
::Label
,
353 elf
::STT_OBJECT
| elf
::STT_COMMON
=> SymbolKind
::Data
,
354 elf
::STT_FUNC
| elf
::STT_GNU_IFUNC
=> SymbolKind
::Text
,
355 elf
::STT_SECTION
=> SymbolKind
::Section
,
356 elf
::STT_FILE
=> SymbolKind
::File
,
357 elf
::STT_TLS
=> SymbolKind
::Tls
,
358 _
=> SymbolKind
::Unknown
,
362 fn section(&self) -> SymbolSection
{
363 match self.symbol
.st_shndx(self.endian
) {
364 elf
::SHN_UNDEF
=> SymbolSection
::Undefined
,
366 if self.symbol
.st_type() == elf
::STT_FILE
{
369 SymbolSection
::Absolute
372 elf
::SHN_COMMON
=> SymbolSection
::Common
,
373 elf
::SHN_XINDEX
=> match self.symbols
.shndx(self.endian
, self.index
.0) {
374 Some(index
) => SymbolSection
::Section(SectionIndex(index
as usize)),
375 None
=> SymbolSection
::Unknown
,
377 index
if index
< elf
::SHN_LORESERVE
=> {
378 SymbolSection
::Section(SectionIndex(index
as usize))
380 _
=> SymbolSection
::Unknown
,
385 fn is_undefined(&self) -> bool
{
386 self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
390 fn is_definition(&self) -> bool
{
391 self.symbol
.is_definition(self.endian
)
395 fn is_common(&self) -> bool
{
396 self.symbol
.st_shndx(self.endian
) == elf
::SHN_COMMON
400 fn is_weak(&self) -> bool
{
401 self.symbol
.st_bind() == elf
::STB_WEAK
404 fn scope(&self) -> SymbolScope
{
405 if self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
{
408 match self.symbol
.st_bind() {
409 elf
::STB_LOCAL
=> SymbolScope
::Compilation
,
410 elf
::STB_GLOBAL
| elf
::STB_WEAK
=> {
411 if self.symbol
.st_visibility() == elf
::STV_HIDDEN
{
417 _
=> SymbolScope
::Unknown
,
423 fn is_global(&self) -> bool
{
424 self.symbol
.st_bind() != elf
::STB_LOCAL
428 fn is_local(&self) -> bool
{
429 self.symbol
.st_bind() == elf
::STB_LOCAL
433 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
435 st_info
: self.symbol
.st_info(),
436 st_other
: self.symbol
.st_other(),
441 /// A trait for generic access to `Sym32` and `Sym64`.
442 #[allow(missing_docs)]
443 pub trait Sym
: Debug
+ Pod
{
444 type Word
: Into
<u64>;
445 type Endian
: endian
::Endian
;
447 fn st_name(&self, endian
: Self::Endian
) -> u32;
448 fn st_info(&self) -> u8;
449 fn st_bind(&self) -> u8;
450 fn st_type(&self) -> u8;
451 fn st_other(&self) -> u8;
452 fn st_visibility(&self) -> u8;
453 fn st_shndx(&self, endian
: Self::Endian
) -> u16;
454 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
;
455 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
;
457 /// Parse the symbol name from the string table.
458 fn name
<'data
, R
: ReadRef
<'data
>>(
460 endian
: Self::Endian
,
461 strings
: StringTable
<'data
, R
>,
462 ) -> read
::Result
<&'data
[u8]> {
464 .get(self.st_name(endian
))
465 .read_error("Invalid ELF symbol name offset")
468 /// Return true if the symbol is undefined.
470 fn is_undefined(&self, endian
: Self::Endian
) -> bool
{
471 self.st_shndx(endian
) == elf
::SHN_UNDEF
474 /// Return true if the symbol is a definition of a function or data object.
475 fn is_definition(&self, endian
: Self::Endian
) -> bool
{
476 let st_type
= self.st_type();
477 (st_type
== elf
::STT_NOTYPE
|| st_type
== elf
::STT_FUNC
|| st_type
== elf
::STT_OBJECT
)
478 && self.st_shndx(endian
) != elf
::SHN_UNDEF
482 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym32
<Endian
> {
484 type Endian
= Endian
;
487 fn st_name(&self, endian
: Self::Endian
) -> u32 {
488 self.st_name
.get(endian
)
492 fn st_info(&self) -> u8 {
497 fn st_bind(&self) -> u8 {
502 fn st_type(&self) -> u8 {
507 fn st_other(&self) -> u8 {
512 fn st_visibility(&self) -> u8 {
517 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
518 self.st_shndx
.get(endian
)
522 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
523 self.st_value
.get(endian
)
527 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
528 self.st_size
.get(endian
)
532 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym64
<Endian
> {
534 type Endian
= Endian
;
537 fn st_name(&self, endian
: Self::Endian
) -> u32 {
538 self.st_name
.get(endian
)
542 fn st_info(&self) -> u8 {
547 fn st_bind(&self) -> u8 {
552 fn st_type(&self) -> u8 {
557 fn st_other(&self) -> u8 {
562 fn st_visibility(&self) -> u8 {
567 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
568 self.st_shndx
.get(endian
)
572 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
573 self.st_value
.get(endian
)
577 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
578 self.st_size
.get(endian
)