3 use core
::convert
::TryInto
;
6 use super::{CoffCommon, SectionTable}
;
7 use crate::endian
::{LittleEndian as LE, U32Bytes}
;
9 use crate::pod
::{bytes_of_slice, Pod}
;
10 use crate::read
::util
::StringTable
;
12 self, Bytes
, ObjectSymbol
, ObjectSymbolTable
, ReadError
, ReadRef
, Result
, SectionIndex
,
13 SymbolFlags
, SymbolIndex
, SymbolKind
, SymbolMap
, SymbolMapEntry
, SymbolScope
, SymbolSection
,
16 /// A table of symbol entries in a COFF or PE file.
18 /// Also includes the string table used for the symbol names.
20 pub struct SymbolTable
<'data
, R
= &'data
[u8]>
24 symbols
: &'data
[pe
::ImageSymbolBytes
],
25 strings
: StringTable
<'data
, R
>,
28 impl<'data
, R
: ReadRef
<'data
>> Default
for SymbolTable
<'data
, R
> {
29 fn default() -> Self {
32 strings
: StringTable
::default(),
37 impl<'data
, R
: ReadRef
<'data
>> SymbolTable
<'data
, R
> {
38 /// Read the symbol table.
39 pub fn parse(header
: &pe
::ImageFileHeader
, data
: R
) -> Result
<Self> {
40 // The symbol table may not be present.
41 let mut offset
= header
.pointer_to_symbol_table
.get(LE
).into();
42 let (symbols
, strings
) = if offset
!= 0 {
44 .read_slice(&mut offset
, header
.number_of_symbols
.get(LE
) as usize)
45 .read_error("Invalid COFF symbol table offset or size")?
;
47 // Note: don't update data when reading length; the length includes itself.
49 .read_at
::<U32Bytes
<_
>>(offset
)
50 .read_error("Missing COFF string table")?
53 .checked_add(length
as u64)
54 .read_error("Invalid COFF string table length")?
;
55 let strings
= StringTable
::new(data
, offset
, str_end
);
59 (&[][..], StringTable
::default())
62 Ok(SymbolTable { symbols, strings }
)
65 /// Return the string table used for the symbol names.
67 pub fn strings(&self) -> StringTable
<'data
, R
> {
71 /// Return true if the symbol table is empty.
73 pub fn is_empty(&self) -> bool
{
74 self.symbols
.is_empty()
77 /// The number of symbol table entries.
79 /// This includes auxiliary symbol table entries.
81 pub fn len(&self) -> usize {
85 /// Iterate over the symbols.
87 pub fn iter
<'table
>(&'table
self) -> SymbolIterator
<'data
, 'table
, R
> {
94 /// Return the symbol table entry at the given index.
96 pub fn symbol(&self, index
: usize) -> Result
<&'data pe
::ImageSymbol
> {
97 self.get
::<pe
::ImageSymbol
>(index
, 0)
100 /// Return the auxiliary function symbol for the symbol table entry at the given index.
102 /// Note that the index is of the symbol, not the first auxiliary record.
104 pub fn aux_function(&self, index
: usize) -> Result
<&'data pe
::ImageAuxSymbolFunction
> {
105 self.get
::<pe
::ImageAuxSymbolFunction
>(index
, 1)
108 /// Return the auxiliary section symbol for the symbol table entry at the given index.
110 /// Note that the index is of the symbol, not the first auxiliary record.
112 pub fn aux_section(&self, index
: usize) -> Result
<&'data pe
::ImageAuxSymbolSection
> {
113 self.get
::<pe
::ImageAuxSymbolSection
>(index
, 1)
116 /// Return the auxiliary file name for the symbol table entry at the given index.
118 /// Note that the index is of the symbol, not the first auxiliary record.
119 pub fn aux_file_name(&self, index
: usize, aux_count
: u8) -> Result
<&'data
[u8]> {
122 .and_then(|x
| Some(x
..x
.checked_add(aux_count
.into())?
))
123 .and_then(|x
| self.symbols
.get(x
))
124 .read_error("Invalid COFF symbol index")?
;
125 let bytes
= bytes_of_slice(entries
);
126 // The name is padded with nulls.
127 Ok(match memchr
::memchr(b'
\0'
, bytes
) {
128 Some(end
) => &bytes
[..end
],
133 /// Return the symbol table entry or auxiliary record at the given index and offset.
134 pub fn get
<T
: Pod
>(&self, index
: usize, offset
: usize) -> Result
<&'data T
> {
137 .and_then(|x
| self.symbols
.get(x
))
138 .read_error("Invalid COFF symbol index")?
;
141 .read_error("Invalid COFF symbol data")
144 /// Construct a map from addresses to a user-defined map entry.
145 pub fn map
<Entry
: SymbolMapEntry
, F
: Fn(&'data pe
::ImageSymbol
) -> Option
<Entry
>>(
148 ) -> SymbolMap
<Entry
> {
149 let mut symbols
= Vec
::with_capacity(self.symbols
.len());
150 for (_
, symbol
) in self.iter() {
151 if !symbol
.is_definition() {
154 if let Some(entry
) = f(symbol
) {
158 SymbolMap
::new(symbols
)
162 /// An iterator for symbol entries in a COFF or PE file.
164 /// Yields the index and symbol structure for each symbol.
166 pub struct SymbolIterator
<'data
, 'table
, R
= &'data
[u8]>
170 symbols
: &'table SymbolTable
<'data
, R
>,
174 impl<'data
, 'table
, R
: ReadRef
<'data
>> Iterator
for SymbolIterator
<'data
, 'table
, R
> {
175 type Item
= (usize, &'data pe
::ImageSymbol
);
177 fn next(&mut self) -> Option
<Self::Item
> {
178 let index
= self.index
;
179 let symbol
= self.symbols
.symbol(index
).ok()?
;
180 self.index
+= 1 + symbol
.number_of_aux_symbols
as usize;
181 Some((index
, symbol
))
185 impl pe
::ImageSymbol
{
186 /// Parse a COFF symbol name.
188 /// `strings` must be the string table used for symbol names.
189 pub fn name
<'data
, R
: ReadRef
<'data
>>(
191 strings
: StringTable
<'data
, R
>,
192 ) -> Result
<&'data
[u8]> {
193 if self.name
[0] == 0 {
194 // If the name starts with 0 then the last 4 bytes are a string table offset.
195 let offset
= u32::from_le_bytes(self.name
[4..8].try_into().unwrap());
198 .read_error("Invalid COFF symbol name offset")
200 // The name is inline and padded with nulls.
201 Ok(match memchr
::memchr(b'
\0'
, &self.name
) {
202 Some(end
) => &self.name
[..end
],
203 None
=> &self.name
[..],
208 /// Return the symbol address.
210 /// This takes into account the image base and the section address.
211 pub fn address(&self, image_base
: u64, sections
: &SectionTable
) -> Result
<u64> {
212 let section_number
= self.section_number
.get(LE
) as usize;
213 let section
= sections
.section(section_number
)?
;
214 let virtual_address
= u64::from(section
.virtual_address
.get(LE
));
215 let value
= u64::from(self.value
.get(LE
));
216 Ok(image_base
+ virtual_address
+ value
)
219 /// Return true if the symbol is a definition of a function or data object.
220 pub fn is_definition(&self) -> bool
{
221 let section_number
= self.section_number
.get(LE
);
222 if section_number
== pe
::IMAGE_SYM_UNDEFINED
{
225 match self.storage_class
{
226 pe
::IMAGE_SYM_CLASS_STATIC
=> {
227 // Exclude section symbols.
228 !(self.value
.get(LE
) == 0 && self.number_of_aux_symbols
> 0)
230 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> true,
235 /// Return true if the symbol has an auxiliary file name.
236 pub fn has_aux_file_name(&self) -> bool
{
237 self.number_of_aux_symbols
> 0 && self.storage_class
== pe
::IMAGE_SYM_CLASS_FILE
240 /// Return true if the symbol has an auxiliary function symbol.
241 pub fn has_aux_function(&self) -> bool
{
242 self.number_of_aux_symbols
> 0 && self.derived_type() == pe
::IMAGE_SYM_DTYPE_FUNCTION
245 /// Return true if the symbol has an auxiliary section symbol.
246 pub fn has_aux_section(&self) -> bool
{
247 self.number_of_aux_symbols
> 0
248 && self.storage_class
== pe
::IMAGE_SYM_CLASS_STATIC
249 && self.value
.get(LE
) == 0
253 /// A symbol table of a `CoffFile`.
254 #[derive(Debug, Clone, Copy)]
255 pub struct CoffSymbolTable
<'data
, 'file
, R
= &'data
[u8]>
259 pub(crate) file
: &'file CoffCommon
<'data
, R
>,
262 impl<'data
, 'file
, R
: ReadRef
<'data
>> read
::private
::Sealed
for CoffSymbolTable
<'data
, 'file
, R
> {}
264 impl<'data
, 'file
, R
: ReadRef
<'data
>> ObjectSymbolTable
<'data
>
265 for CoffSymbolTable
<'data
, 'file
, R
>
267 type Symbol
= CoffSymbol
<'data
, 'file
, R
>;
268 type SymbolIterator
= CoffSymbolIterator
<'data
, 'file
, R
>;
270 fn symbols(&self) -> Self::SymbolIterator
{
277 fn symbol_by_index(&self, index
: SymbolIndex
) -> Result
<Self::Symbol
> {
278 let symbol
= self.file
.symbols
.symbol(index
.0)?
;
287 /// An iterator over the symbols of a `CoffFile`.
288 pub struct CoffSymbolIterator
<'data
, 'file
, R
= &'data
[u8]>
292 pub(crate) file
: &'file CoffCommon
<'data
, R
>,
293 pub(crate) index
: usize,
296 impl<'data
, 'file
, R
: ReadRef
<'data
>> fmt
::Debug
for CoffSymbolIterator
<'data
, 'file
, R
> {
297 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
298 f
.debug_struct("CoffSymbolIterator").finish()
302 impl<'data
, 'file
, R
: ReadRef
<'data
>> Iterator
for CoffSymbolIterator
<'data
, 'file
, R
> {
303 type Item
= CoffSymbol
<'data
, 'file
, R
>;
305 fn next(&mut self) -> Option
<Self::Item
> {
306 let index
= self.index
;
307 let symbol
= self.file
.symbols
.symbol(index
).ok()?
;
308 self.index
+= 1 + symbol
.number_of_aux_symbols
as usize;
311 index
: SymbolIndex(index
),
317 /// A symbol of a `CoffFile`.
318 #[derive(Debug, Clone, Copy)]
319 pub struct CoffSymbol
<'data
, 'file
, R
= &'data
[u8]>
323 pub(crate) file
: &'file CoffCommon
<'data
, R
>,
324 pub(crate) index
: SymbolIndex
,
325 pub(crate) symbol
: &'data pe
::ImageSymbol
,
328 impl<'data
, 'file
, R
: ReadRef
<'data
>> read
::private
::Sealed
for CoffSymbol
<'data
, 'file
, R
> {}
330 impl<'data
, 'file
, R
: ReadRef
<'data
>> ObjectSymbol
<'data
> for CoffSymbol
<'data
, 'file
, R
> {
332 fn index(&self) -> SymbolIndex
{
336 fn name_bytes(&self) -> read
::Result
<&'data
[u8]> {
337 if self.symbol
.has_aux_file_name() {
340 .aux_file_name(self.index
.0, self.symbol
.number_of_aux_symbols
)
342 self.symbol
.name(self.file
.symbols
.strings())
346 fn name(&self) -> read
::Result
<&'data
str> {
347 let name
= self.name_bytes()?
;
350 .read_error("Non UTF-8 COFF symbol name")
353 fn address(&self) -> u64 {
354 // Only return an address for storage classes that we know use an address.
355 match self.symbol
.storage_class
{
356 pe
::IMAGE_SYM_CLASS_STATIC
357 | pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
358 | pe
::IMAGE_SYM_CLASS_LABEL
=> {}
359 pe
::IMAGE_SYM_CLASS_EXTERNAL
=> {
360 if self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
{
361 // Undefined or common data, neither of which have an address.
368 .address(self.file
.image_base
, &self.file
.sections
)
372 fn size(&self) -> u64 {
373 match self.symbol
.storage_class
{
374 pe
::IMAGE_SYM_CLASS_STATIC
=> {
375 // Section symbols may duplicate the size from the section table.
376 if self.symbol
.has_aux_section() {
377 if let Ok(aux
) = self.file
.symbols
.aux_section(self.index
.0) {
378 u64::from(aux
.length
.get(LE
))
386 pe
::IMAGE_SYM_CLASS_EXTERNAL
=> {
387 if self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
{
388 // For undefined symbols, symbol.value is 0 and the size is 0.
389 // For common data, symbol.value is the size.
390 u64::from(self.symbol
.value
.get(LE
))
391 } else if self.symbol
.has_aux_function() {
392 // Function symbols may have a size.
393 if let Ok(aux
) = self.file
.symbols
.aux_function(self.index
.0) {
394 u64::from(aux
.total_size
.get(LE
))
402 // Most symbols don't have sizes.
407 fn kind(&self) -> SymbolKind
{
408 let derived_kind
= if self.symbol
.derived_type() == pe
::IMAGE_SYM_DTYPE_FUNCTION
{
413 match self.symbol
.storage_class
{
414 pe
::IMAGE_SYM_CLASS_STATIC
=> {
415 if self.symbol
.value
.get(LE
) == 0 && self.symbol
.number_of_aux_symbols
> 0 {
421 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> derived_kind
,
422 pe
::IMAGE_SYM_CLASS_SECTION
=> SymbolKind
::Section
,
423 pe
::IMAGE_SYM_CLASS_FILE
=> SymbolKind
::File
,
424 pe
::IMAGE_SYM_CLASS_LABEL
=> SymbolKind
::Label
,
425 _
=> SymbolKind
::Unknown
,
429 fn section(&self) -> SymbolSection
{
430 match self.symbol
.section_number
.get(LE
) {
431 pe
::IMAGE_SYM_UNDEFINED
=> {
432 if self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_EXTERNAL
433 && self.symbol
.value
.get(LE
) == 0
435 SymbolSection
::Undefined
437 SymbolSection
::Common
440 pe
::IMAGE_SYM_ABSOLUTE
=> SymbolSection
::Absolute
,
441 pe
::IMAGE_SYM_DEBUG
=> {
442 if self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_FILE
{
445 SymbolSection
::Unknown
448 index
if index
> 0 => SymbolSection
::Section(SectionIndex(index
.into())),
449 _
=> SymbolSection
::Unknown
,
454 fn is_undefined(&self) -> bool
{
455 self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_EXTERNAL
456 && self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
457 && self.symbol
.value
.get(LE
) == 0
461 fn is_definition(&self) -> bool
{
462 self.symbol
.is_definition()
466 fn is_common(&self) -> bool
{
467 self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_EXTERNAL
468 && self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
469 && self.symbol
.value
.get(LE
) != 0
473 fn is_weak(&self) -> bool
{
474 self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
478 fn scope(&self) -> SymbolScope
{
479 match self.symbol
.storage_class
{
480 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> {
481 // TODO: determine if symbol is exported
484 _
=> SymbolScope
::Compilation
,
489 fn is_global(&self) -> bool
{
490 match self.symbol
.storage_class
{
491 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> true,
497 fn is_local(&self) -> bool
{
501 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
502 if self.symbol
.has_aux_section() {
503 if let Ok(aux
) = self.file
.symbols
.aux_section(self.index
.0) {
504 // TODO: use high_number for bigobj
505 let number
= aux
.number
.get(LE
) as usize;
506 return SymbolFlags
::CoffSection
{
507 selection
: aux
.selection
,
508 associative_section
: if number
== 0 {
511 Some(SectionIndex(number
))