8 use crate::endian
::{self, Endianness}
;
9 use crate::pod
::{Bytes, Pod}
;
10 use crate::read
::util
::StringTable
;
12 self, ObjectSymbol
, ObjectSymbolTable
, ReadError
, SectionIndex
, SymbolFlags
, SymbolIndex
,
13 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
> {
24 symbols
: &'data
[Elf
::Sym
],
25 strings
: StringTable
<'data
>,
29 impl<'data
, Elf
: FileHeader
> Default
for SymbolTable
<'data
, Elf
> {
30 fn default() -> Self {
34 strings
: Default
::default(),
40 impl<'data
, Elf
: FileHeader
> SymbolTable
<'data
, Elf
> {
41 /// Parse the symbol table of the given section type.
43 /// Returns an empty symbol table if the symbol table does not exist.
47 sections
: &SectionTable
<Elf
>,
49 ) -> read
::Result
<SymbolTable
<'data
, Elf
>> {
50 debug_assert
!(sh_type
== elf
::SHT_DYNSYM
|| sh_type
== elf
::SHT_SYMTAB
);
52 let (section
, symtab
) = match sections
55 .find(|s
| s
.1.sh_type(endian
) == sh_type
)
58 None
=> return Ok(SymbolTable
::default()),
61 .data_as_array(endian
, data
)
62 .read_error("Invalid ELF symbol table data")?
;
64 let strtab
= sections
.section(symtab
.sh_link(endian
) as usize)?
;
65 let strtab_data
= strtab
67 .read_error("Invalid ELF string table data")?
;
68 let strings
= StringTable
::new(strtab_data
);
73 s
.sh_type(endian
) == elf
::SHT_SYMTAB_SHNDX
&& s
.sh_link(endian
) as usize == section
77 .data_as_array(endian
, data
)
78 .read_error("Invalid ELF symtab_shndx data")
91 /// Return the section index of this symbol table.
93 pub fn section(&self) -> usize {
97 /// Return the string table used for the symbol names.
99 pub fn strings(&self) -> StringTable
<'data
> {
103 /// Iterate over the symbols.
105 pub fn iter(&self) -> slice
::Iter
<'data
, Elf
::Sym
> {
109 /// Return true if the symbol table is empty.
111 pub fn is_empty(&self) -> bool
{
112 self.symbols
.is_empty()
115 /// The number of symbols.
117 pub fn len(&self) -> usize {
121 /// Return the symbol at the given index.
122 pub fn symbol(&self, index
: usize) -> read
::Result
<&'data Elf
::Sym
> {
125 .read_error("Invalid ELF symbol index")
128 /// Return the extended section index for the given symbol if present.
130 pub fn shndx(&self, index
: usize) -> Option
<u32> {
131 self.shndx
.get(index
).cloned()
134 /// Construct a map from addresses to a user-defined map entry.
135 pub fn map
<Entry
: SymbolMapEntry
, F
: Fn(&'data Elf
::Sym
) -> Option
<Entry
>>(
139 ) -> SymbolMap
<Entry
> {
140 let mut symbols
= Vec
::with_capacity(self.symbols
.len());
141 for symbol
in self.symbols
{
142 if !symbol
.is_definition(endian
) {
145 if let Some(entry
) = f(symbol
) {
149 SymbolMap
::new(symbols
)
153 /// A symbol table of an `ElfFile32`.
154 pub type ElfSymbolTable32
<'data
, 'file
, Endian
= Endianness
> =
155 ElfSymbolTable
<'data
, 'file
, elf
::FileHeader32
<Endian
>>;
156 /// A symbol table of an `ElfFile32`.
157 pub type ElfSymbolTable64
<'data
, 'file
, Endian
= Endianness
> =
158 ElfSymbolTable
<'data
, 'file
, elf
::FileHeader64
<Endian
>>;
160 /// A symbol table of an `ElfFile`.
161 #[derive(Debug, Clone, Copy)]
162 pub struct ElfSymbolTable
<'data
, 'file
, Elf
>
167 pub(super) endian
: Elf
::Endian
,
168 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
>,
171 impl<'data
, 'file
, Elf
: FileHeader
> read
::private
::Sealed
for ElfSymbolTable
<'data
, 'file
, Elf
> {}
173 impl<'data
, 'file
, Elf
: FileHeader
> ObjectSymbolTable
<'data
> for ElfSymbolTable
<'data
, 'file
, Elf
> {
174 type Symbol
= ElfSymbol
<'data
, 'file
, Elf
>;
175 type SymbolIterator
= ElfSymbolIterator
<'data
, 'file
, Elf
>;
177 fn symbols(&self) -> Self::SymbolIterator
{
180 symbols
: self.symbols
,
185 fn symbol_by_index(&self, index
: SymbolIndex
) -> read
::Result
<Self::Symbol
> {
186 let symbol
= self.symbols
.symbol(index
.0)?
;
189 symbols
: self.symbols
,
196 /// An iterator over the symbols of an `ElfFile32`.
197 pub type ElfSymbolIterator32
<'data
, 'file
, Endian
= Endianness
> =
198 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader32
<Endian
>>;
199 /// An iterator over the symbols of an `ElfFile64`.
200 pub type ElfSymbolIterator64
<'data
, 'file
, Endian
= Endianness
> =
201 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader64
<Endian
>>;
203 /// An iterator over the symbols of an `ElfFile`.
204 pub struct ElfSymbolIterator
<'data
, 'file
, Elf
>
209 pub(super) endian
: Elf
::Endian
,
210 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
>,
211 pub(super) index
: usize,
214 impl<'data
, 'file
, Elf
: FileHeader
> fmt
::Debug
for ElfSymbolIterator
<'data
, 'file
, Elf
> {
215 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
216 f
.debug_struct("ElfSymbolIterator").finish()
220 impl<'data
, 'file
, Elf
: FileHeader
> Iterator
for ElfSymbolIterator
<'data
, 'file
, Elf
> {
221 type Item
= ElfSymbol
<'data
, 'file
, Elf
>;
223 fn next(&mut self) -> Option
<Self::Item
> {
224 let index
= self.index
;
225 let symbol
= self.symbols
.symbols
.get(index
)?
;
229 symbols
: self.symbols
,
230 index
: SymbolIndex(index
),
236 /// A symbol of an `ElfFile32`.
237 pub type ElfSymbol32
<'data
, 'file
, Endian
= Endianness
> =
238 ElfSymbol
<'data
, 'file
, elf
::FileHeader32
<Endian
>>;
239 /// A symbol of an `ElfFile64`.
240 pub type ElfSymbol64
<'data
, 'file
, Endian
= Endianness
> =
241 ElfSymbol
<'data
, 'file
, elf
::FileHeader64
<Endian
>>;
243 /// A symbol of an `ElfFile`.
244 #[derive(Debug, Clone, Copy)]
245 pub struct ElfSymbol
<'data
, 'file
, Elf
>
250 pub(super) endian
: Elf
::Endian
,
251 pub(super) symbols
: &'file SymbolTable
<'data
, Elf
>,
252 pub(super) index
: SymbolIndex
,
253 pub(super) symbol
: &'data Elf
::Sym
,
256 impl<'data
, 'file
, Elf
: FileHeader
> read
::private
::Sealed
for ElfSymbol
<'data
, 'file
, Elf
> {}
258 impl<'data
, 'file
, Elf
: FileHeader
> ObjectSymbol
<'data
> for ElfSymbol
<'data
, 'file
, Elf
> {
260 fn index(&self) -> SymbolIndex
{
264 fn name(&self) -> read
::Result
<&'data
str> {
265 let name
= self.symbol
.name(self.endian
, self.symbols
.strings())?
;
268 .read_error("Non UTF-8 ELF symbol name")
272 fn address(&self) -> u64 {
273 self.symbol
.st_value(self.endian
).into()
277 fn size(&self) -> u64 {
278 self.symbol
.st_size(self.endian
).into()
281 fn kind(&self) -> SymbolKind
{
282 match self.symbol
.st_type() {
283 elf
::STT_NOTYPE
if self.index
.0 == 0 => SymbolKind
::Null
,
284 elf
::STT_OBJECT
| elf
::STT_COMMON
=> SymbolKind
::Data
,
285 elf
::STT_FUNC
=> SymbolKind
::Text
,
286 elf
::STT_SECTION
=> SymbolKind
::Section
,
287 elf
::STT_FILE
=> SymbolKind
::File
,
288 elf
::STT_TLS
=> SymbolKind
::Tls
,
289 _
=> SymbolKind
::Unknown
,
293 fn section(&self) -> SymbolSection
{
294 match self.symbol
.st_shndx(self.endian
) {
295 elf
::SHN_UNDEF
=> SymbolSection
::Undefined
,
297 if self.symbol
.st_type() == elf
::STT_FILE
{
300 SymbolSection
::Absolute
303 elf
::SHN_COMMON
=> SymbolSection
::Common
,
304 elf
::SHN_XINDEX
=> match self.symbols
.shndx(self.index
.0) {
305 Some(index
) => SymbolSection
::Section(SectionIndex(index
as usize)),
306 None
=> SymbolSection
::Unknown
,
308 index
if index
< elf
::SHN_LORESERVE
=> {
309 SymbolSection
::Section(SectionIndex(index
as usize))
311 _
=> SymbolSection
::Unknown
,
316 fn is_undefined(&self) -> bool
{
317 self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
321 fn is_definition(&self) -> bool
{
322 self.symbol
.is_definition(self.endian
)
326 fn is_common(&self) -> bool
{
327 self.symbol
.st_shndx(self.endian
) == elf
::SHN_COMMON
331 fn is_weak(&self) -> bool
{
332 self.symbol
.st_bind() == elf
::STB_WEAK
335 fn scope(&self) -> SymbolScope
{
336 if self.symbol
.st_shndx(self.endian
) == elf
::SHN_UNDEF
{
339 match self.symbol
.st_bind() {
340 elf
::STB_LOCAL
=> SymbolScope
::Compilation
,
341 elf
::STB_GLOBAL
| elf
::STB_WEAK
=> {
342 if self.symbol
.st_visibility() == elf
::STV_HIDDEN
{
348 _
=> SymbolScope
::Unknown
,
354 fn is_global(&self) -> bool
{
355 self.symbol
.st_bind() != elf
::STB_LOCAL
359 fn is_local(&self) -> bool
{
360 self.symbol
.st_bind() == elf
::STB_LOCAL
364 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
366 st_info
: self.symbol
.st_info(),
367 st_other
: self.symbol
.st_other(),
372 /// A trait for generic access to `Sym32` and `Sym64`.
373 #[allow(missing_docs)]
374 pub trait Sym
: Debug
+ Pod
{
375 type Word
: Into
<u64>;
376 type Endian
: endian
::Endian
;
378 fn st_name(&self, endian
: Self::Endian
) -> u32;
379 fn st_info(&self) -> u8;
380 fn st_bind(&self) -> u8;
381 fn st_type(&self) -> u8;
382 fn st_other(&self) -> u8;
383 fn st_visibility(&self) -> u8;
384 fn st_shndx(&self, endian
: Self::Endian
) -> u16;
385 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
;
386 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
;
388 /// Parse the symbol name from the string table.
391 endian
: Self::Endian
,
392 strings
: StringTable
<'data
>,
393 ) -> read
::Result
<&'data
[u8]> {
395 .get(self.st_name(endian
))
396 .read_error("Invalid ELF symbol name offset")
399 /// Return true if the symbol is a definition of a function or data object.
400 fn is_definition(&self, endian
: Self::Endian
) -> bool
{
401 let st_type
= self.st_type();
402 (st_type
== elf
::STT_NOTYPE
|| st_type
== elf
::STT_FUNC
|| st_type
== elf
::STT_OBJECT
)
403 && self.st_shndx(endian
) != elf
::SHN_UNDEF
407 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym32
<Endian
> {
409 type Endian
= Endian
;
412 fn st_name(&self, endian
: Self::Endian
) -> u32 {
413 self.st_name
.get(endian
)
417 fn st_info(&self) -> u8 {
422 fn st_bind(&self) -> u8 {
427 fn st_type(&self) -> u8 {
432 fn st_other(&self) -> u8 {
437 fn st_visibility(&self) -> u8 {
442 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
443 self.st_shndx
.get(endian
)
447 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
448 self.st_value
.get(endian
)
452 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
453 self.st_size
.get(endian
)
457 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym64
<Endian
> {
459 type Endian
= Endian
;
462 fn st_name(&self, endian
: Self::Endian
) -> u32 {
463 self.st_name
.get(endian
)
467 fn st_info(&self) -> u8 {
472 fn st_bind(&self) -> u8 {
477 fn st_type(&self) -> u8 {
482 fn st_other(&self) -> u8 {
487 fn st_visibility(&self) -> u8 {
492 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
493 self.st_shndx
.get(endian
)
497 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
498 self.st_value
.get(endian
)
502 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
503 self.st_size
.get(endian
)