7 use crate::endian
::{self, Endianness}
;
8 use crate::pod
::{Bytes, Pod}
;
9 use crate::read
::util
::StringTable
;
11 self, ReadError
, SectionIndex
, Symbol
, SymbolFlags
, SymbolIndex
, SymbolKind
, SymbolScope
,
15 use super::{ElfFile, FileHeader, SectionHeader, SectionTable}
;
17 /// A table of symbol entries in an ELF file.
19 /// Also includes the string table used for the symbol names.
20 #[derive(Debug, Clone, Copy)]
21 pub struct SymbolTable
<'data
, Elf
: FileHeader
> {
23 symbols
: &'data
[Elf
::Sym
],
24 strings
: StringTable
<'data
>,
28 impl<'data
, Elf
: FileHeader
> Default
for SymbolTable
<'data
, Elf
> {
29 fn default() -> Self {
33 strings
: Default
::default(),
39 impl<'data
, Elf
: FileHeader
> SymbolTable
<'data
, Elf
> {
40 /// Parse the symbol table of the given section type.
42 /// Returns an empty symbol table if the symbol table does not exist.
46 sections
: &SectionTable
<Elf
>,
48 ) -> read
::Result
<SymbolTable
<'data
, Elf
>> {
49 debug_assert
!(sh_type
== elf
::SHT_DYNSYM
|| sh_type
== elf
::SHT_SYMTAB
);
51 let (section
, symtab
) = match sections
54 .find(|s
| s
.1.sh_type(endian
) == sh_type
)
57 None
=> return Ok(SymbolTable
::default()),
60 .data_as_array(endian
, data
)
61 .read_error("Invalid ELF symbol table data")?
;
63 let strtab
= sections
.section(symtab
.sh_link(endian
) as usize)?
;
64 let strtab_data
= strtab
66 .read_error("Invalid ELF string table data")?
;
67 let strings
= StringTable
::new(strtab_data
);
72 s
.sh_type(endian
) == elf
::SHT_SYMTAB_SHNDX
&& s
.sh_link(endian
) as usize == section
76 .data_as_array(endian
, data
)
77 .read_error("Invalid ELF symtab_shndx data")
90 /// Return the section index of this symbol table.
92 pub fn section(&self) -> usize {
96 /// Return the string table used for the symbol names.
98 pub fn strings(&self) -> StringTable
<'data
> {
102 /// Iterate over the symbols.
104 pub fn iter(&self) -> slice
::Iter
<'data
, Elf
::Sym
> {
108 /// Return true if the symbol table is empty.
110 pub fn is_empty(&self) -> bool
{
111 self.symbols
.is_empty()
114 /// Return the symbol at the given index.
115 pub fn symbol(&self, index
: usize) -> read
::Result
<&'data Elf
::Sym
> {
118 .read_error("Invalid ELF symbol index")
121 /// Return the extended section index for the given symbol if present.
123 pub fn shndx(&self, index
: usize) -> Option
<u32> {
124 self.shndx
.get(index
).cloned()
128 /// An iterator over the symbols of an `ElfFile32`.
129 pub type ElfSymbolIterator32
<'data
, 'file
, Endian
= Endianness
> =
130 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader32
<Endian
>>;
131 /// An iterator over the symbols of an `ElfFile64`.
132 pub type ElfSymbolIterator64
<'data
, 'file
, Endian
= Endianness
> =
133 ElfSymbolIterator
<'data
, 'file
, elf
::FileHeader64
<Endian
>>;
135 /// An iterator over the symbols of an `ElfFile`.
136 pub struct ElfSymbolIterator
<'data
, 'file
, Elf
>
141 pub(super) file
: &'file ElfFile
<'data
, Elf
>,
142 pub(super) symbols
: SymbolTable
<'data
, Elf
>,
143 pub(super) index
: usize,
146 impl<'data
, 'file
, Elf
: FileHeader
> fmt
::Debug
for ElfSymbolIterator
<'data
, 'file
, Elf
> {
147 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
148 f
.debug_struct("ElfSymbolIterator").finish()
152 impl<'data
, 'file
, Elf
: FileHeader
> Iterator
for ElfSymbolIterator
<'data
, 'file
, Elf
> {
153 type Item
= (SymbolIndex
, Symbol
<'data
>);
155 fn next(&mut self) -> Option
<Self::Item
> {
156 let index
= self.index
;
157 let shndx
= self.symbols
.shndx(index
);
158 self.symbols
.symbols
.get(index
).map(|symbol
| {
160 let name
= symbol
.name(self.file
.endian
, self.symbols
.strings()).ok();
163 parse_symbol
::<Elf
>(self.file
.endian
, index
, symbol
, name
, shndx
),
169 pub(super) fn parse_symbol
<'data
, Elf
: FileHeader
>(
173 name
: Option
<&'data
[u8]>,
176 let name
= name
.and_then(|s
| str::from_utf8(s
).ok());
177 let kind
= match symbol
.st_type() {
178 elf
::STT_NOTYPE
if index
== 0 => SymbolKind
::Null
,
179 elf
::STT_OBJECT
| elf
::STT_COMMON
=> SymbolKind
::Data
,
180 elf
::STT_FUNC
=> SymbolKind
::Text
,
181 elf
::STT_SECTION
=> SymbolKind
::Section
,
182 elf
::STT_FILE
=> SymbolKind
::File
,
183 elf
::STT_TLS
=> SymbolKind
::Tls
,
184 _
=> SymbolKind
::Unknown
,
186 let section
= match symbol
.st_shndx(endian
) {
187 elf
::SHN_UNDEF
=> SymbolSection
::Undefined
,
189 if kind
== SymbolKind
::File
{
192 SymbolSection
::Absolute
195 elf
::SHN_COMMON
=> SymbolSection
::Common
,
196 elf
::SHN_XINDEX
=> match shndx
{
197 Some(index
) => SymbolSection
::Section(SectionIndex(index
as usize)),
198 None
=> SymbolSection
::Unknown
,
200 index
if index
< elf
::SHN_LORESERVE
=> SymbolSection
::Section(SectionIndex(index
as usize)),
201 _
=> SymbolSection
::Unknown
,
203 let weak
= symbol
.st_bind() == elf
::STB_WEAK
;
204 let scope
= match symbol
.st_bind() {
205 _
if section
== SymbolSection
::Undefined
=> SymbolScope
::Unknown
,
206 elf
::STB_LOCAL
=> SymbolScope
::Compilation
,
207 elf
::STB_GLOBAL
| elf
::STB_WEAK
=> {
208 if symbol
.st_visibility() == elf
::STV_HIDDEN
{
214 _
=> SymbolScope
::Unknown
,
216 let flags
= SymbolFlags
::Elf
{
217 st_info
: symbol
.st_info(),
218 st_other
: symbol
.st_other(),
222 address
: symbol
.st_value(endian
).into(),
223 size
: symbol
.st_size(endian
).into(),
232 /// A trait for generic access to `Sym32` and `Sym64`.
233 #[allow(missing_docs)]
234 pub trait Sym
: Debug
+ Pod
{
235 type Word
: Into
<u64>;
236 type Endian
: endian
::Endian
;
238 fn st_name(&self, endian
: Self::Endian
) -> u32;
239 fn st_info(&self) -> u8;
240 fn st_bind(&self) -> u8;
241 fn st_type(&self) -> u8;
242 fn st_other(&self) -> u8;
243 fn st_visibility(&self) -> u8;
244 fn st_shndx(&self, endian
: Self::Endian
) -> u16;
245 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
;
246 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
;
248 /// Parse the symbol name from the string table.
251 endian
: Self::Endian
,
252 strings
: StringTable
<'data
>,
253 ) -> read
::Result
<&'data
[u8]> {
255 .get(self.st_name(endian
))
256 .read_error("Invalid ELF symbol name offset")
260 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym32
<Endian
> {
262 type Endian
= Endian
;
265 fn st_name(&self, endian
: Self::Endian
) -> u32 {
266 self.st_name
.get(endian
)
270 fn st_info(&self) -> u8 {
275 fn st_bind(&self) -> u8 {
280 fn st_type(&self) -> u8 {
285 fn st_other(&self) -> u8 {
290 fn st_visibility(&self) -> u8 {
295 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
296 self.st_shndx
.get(endian
)
300 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
301 self.st_value
.get(endian
)
305 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
306 self.st_size
.get(endian
)
310 impl<Endian
: endian
::Endian
> Sym
for elf
::Sym64
<Endian
> {
312 type Endian
= Endian
;
315 fn st_name(&self, endian
: Self::Endian
) -> u32 {
316 self.st_name
.get(endian
)
320 fn st_info(&self) -> u8 {
325 fn st_bind(&self) -> u8 {
330 fn st_type(&self) -> u8 {
335 fn st_other(&self) -> u8 {
340 fn st_visibility(&self) -> u8 {
345 fn st_shndx(&self, endian
: Self::Endian
) -> u16 {
346 self.st_shndx
.get(endian
)
350 fn st_value(&self, endian
: Self::Endian
) -> Self::Word
{
351 self.st_value
.get(endian
)
355 fn st_size(&self, endian
: Self::Endian
) -> Self::Word
{
356 self.st_size
.get(endian
)