3 use core
::convert
::TryInto
;
6 use super::{CoffCommon, SectionTable}
;
7 use crate::endian
::{LittleEndian as LE, U32Bytes}
;
9 use crate::pod
::{Bytes, Pod}
;
10 use crate::read
::util
::StringTable
;
12 self, ObjectSymbol
, ObjectSymbolTable
, ReadError
, Result
, SectionIndex
, SymbolFlags
,
13 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
> {
21 symbols
: &'data
[pe
::ImageSymbolBytes
],
22 strings
: StringTable
<'data
>,
25 impl<'data
> SymbolTable
<'data
> {
26 /// Read the symbol table.
27 pub fn parse(header
: &pe
::ImageFileHeader
, mut data
: Bytes
<'data
>) -> Result
<Self> {
28 // The symbol table may not be present.
29 let symbol_offset
= header
.pointer_to_symbol_table
.get(LE
) as usize;
30 let (symbols
, strings
) = if symbol_offset
!= 0 {
31 data
.skip(symbol_offset
)
32 .read_error("Invalid COFF symbol table offset")?
;
34 .read_slice(header
.number_of_symbols
.get(LE
) as usize)
35 .read_error("Invalid COFF symbol table size")?
;
37 // Note: don't update data when reading length; the length includes itself.
39 .read_at
::<U32Bytes
<_
>>(0)
40 .read_error("Missing COFF string table")?
43 .read_bytes(length
as usize)
44 .read_error("Invalid COFF string table length")?
;
53 strings
: StringTable
::new(strings
),
57 /// Return the string table used for the symbol names.
59 pub fn strings(&self) -> StringTable
<'data
> {
63 /// Return true if the symbol table is empty.
65 pub fn is_empty(&self) -> bool
{
66 self.symbols
.is_empty()
69 /// The number of symbols.
71 pub fn len(&self) -> usize {
75 /// Return the symbol table entry at the given index.
77 pub fn symbol(&self, index
: usize) -> Result
<&'data pe
::ImageSymbol
> {
78 self.get
::<pe
::ImageSymbol
>(index
)
81 /// Return the symbol table entry or auxiliary record at the given index.
82 pub fn get
<T
: Pod
>(&self, index
: usize) -> Result
<&'data T
> {
86 .read_error("Invalid COFF symbol index")?
;
89 .read_error("Invalid COFF symbol data")
92 /// Construct a map from addresses to a user-defined map entry.
93 pub fn map
<Entry
: SymbolMapEntry
, F
: Fn(&'data pe
::ImageSymbol
) -> Option
<Entry
>>(
96 ) -> SymbolMap
<Entry
> {
97 let mut symbols
= Vec
::with_capacity(self.symbols
.len());
99 while let Ok(symbol
) = self.symbol(i
) {
100 i
+= 1 + symbol
.number_of_aux_symbols
as usize;
101 if !symbol
.is_definition() {
104 if let Some(entry
) = f(symbol
) {
108 SymbolMap
::new(symbols
)
112 impl pe
::ImageSymbol
{
113 /// Parse a COFF symbol name.
115 /// `strings` must be the string table used for symbol names.
116 pub fn name
<'data
>(&'data
self, strings
: StringTable
<'data
>) -> Result
<&'data
[u8]> {
117 if self.name
[0] == 0 {
118 // If the name starts with 0 then the last 4 bytes are a string table offset.
119 let offset
= u32::from_le_bytes(self.name
[4..8].try_into().unwrap());
122 .read_error("Invalid COFF symbol name offset")
124 // The name is inline and padded with nulls.
125 Ok(match self.name
.iter().position(|&x
| x
== 0) {
126 Some(end
) => &self.name
[..end
],
127 None
=> &self.name
[..],
132 /// Return the symbol address.
134 /// This takes into account the image base and the section address.
135 pub fn address(&self, image_base
: u64, sections
: &SectionTable
) -> Result
<u64> {
136 let section_number
= self.section_number
.get(LE
) as usize;
137 let section
= sections
.section(section_number
)?
;
138 let virtual_address
= u64::from(section
.virtual_address
.get(LE
));
139 let value
= u64::from(self.value
.get(LE
));
140 Ok(image_base
+ virtual_address
+ value
)
143 /// Return true if the symbol is a definition of a function or data object.
144 pub fn is_definition(&self) -> bool
{
145 let section_number
= self.section_number
.get(LE
);
146 if section_number
== pe
::IMAGE_SYM_UNDEFINED
{
149 match self.storage_class
{
150 pe
::IMAGE_SYM_CLASS_STATIC
=> {
151 if self.value
.get(LE
) == 0 && self.number_of_aux_symbols
> 0 {
152 // This is a section symbol.
158 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> true,
164 /// A symbol table of a `CoffFile`.
165 #[derive(Debug, Clone, Copy)]
166 pub struct CoffSymbolTable
<'data
, 'file
>
170 pub(crate) file
: &'file CoffCommon
<'data
>,
173 impl<'data
, 'file
> read
::private
::Sealed
for CoffSymbolTable
<'data
, 'file
> {}
175 impl<'data
, 'file
> ObjectSymbolTable
<'data
> for CoffSymbolTable
<'data
, 'file
> {
176 type Symbol
= CoffSymbol
<'data
, 'file
>;
177 type SymbolIterator
= CoffSymbolIterator
<'data
, 'file
>;
179 fn symbols(&self) -> Self::SymbolIterator
{
186 fn symbol_by_index(&self, index
: SymbolIndex
) -> Result
<Self::Symbol
> {
187 let symbol
= self.file
.symbols
.symbol(index
.0)?
;
196 /// An iterator over the symbols of a `CoffFile`.
197 pub struct CoffSymbolIterator
<'data
, 'file
>
201 pub(crate) file
: &'file CoffCommon
<'data
>,
202 pub(crate) index
: usize,
205 impl<'data
, 'file
> fmt
::Debug
for CoffSymbolIterator
<'data
, 'file
> {
206 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
207 f
.debug_struct("CoffSymbolIterator").finish()
211 impl<'data
, 'file
> Iterator
for CoffSymbolIterator
<'data
, 'file
> {
212 type Item
= CoffSymbol
<'data
, 'file
>;
214 fn next(&mut self) -> Option
<Self::Item
> {
215 let index
= self.index
;
216 let symbol
= self.file
.symbols
.symbol(index
).ok()?
;
217 self.index
+= 1 + symbol
.number_of_aux_symbols
as usize;
220 index
: SymbolIndex(index
),
226 /// A symbol of a `CoffFile`.
227 #[derive(Debug, Clone, Copy)]
228 pub struct CoffSymbol
<'data
, 'file
>
232 pub(crate) file
: &'file CoffCommon
<'data
>,
233 pub(crate) index
: SymbolIndex
,
234 pub(crate) symbol
: &'data pe
::ImageSymbol
,
237 impl<'data
, 'file
> read
::private
::Sealed
for CoffSymbol
<'data
, 'file
> {}
239 impl<'data
, 'file
> ObjectSymbol
<'data
> for CoffSymbol
<'data
, 'file
> {
241 fn index(&self) -> SymbolIndex
{
245 fn name(&self) -> read
::Result
<&'data
str> {
246 let name
= if self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_FILE
{
247 // The file name is in the following auxiliary symbol.
248 if self.symbol
.number_of_aux_symbols
> 0 {
252 .get
::<pe
::ImageSymbolBytes
>(self.index
.0 + 1)?
;
253 // The name is padded with nulls.
254 match s
.0.iter
().position(|&x
| x
== 0) {
255 Some(end
) => &s
.0[..end
],
262 self.symbol
.name(self.file
.symbols
.strings())?
266 .read_error("Non UTF-8 COFF symbol name")
269 fn address(&self) -> u64 {
270 // Only return an address for storage classes that we know use an address.
271 match self.symbol
.storage_class
{
272 pe
::IMAGE_SYM_CLASS_STATIC
273 | pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
274 | pe
::IMAGE_SYM_CLASS_LABEL
=> {}
275 pe
::IMAGE_SYM_CLASS_EXTERNAL
=> {
276 if self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
{
277 // Undefined or common data, neither of which have an address.
284 .address(self.file
.image_base
, &self.file
.sections
)
288 fn size(&self) -> u64 {
289 match self.symbol
.storage_class
{
290 pe
::IMAGE_SYM_CLASS_STATIC
=> {
291 // Section symbols may duplicate the size from the section table.
292 if self.symbol
.value
.get(LE
) == 0 && self.symbol
.number_of_aux_symbols
> 0 {
293 if let Ok(aux
) = self
296 .get
::<pe
::ImageAuxSymbolSection
>(self.index
.0 + 1)
298 u64::from(aux
.length
.get(LE
))
306 pe
::IMAGE_SYM_CLASS_EXTERNAL
=> {
307 if self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
{
308 // For undefined symbols, symbol.value is 0 and the size is 0.
309 // For common data, symbol.value is the size.
310 u64::from(self.symbol
.value
.get(LE
))
311 } else if self.symbol
.derived_type() == pe
::IMAGE_SYM_DTYPE_FUNCTION
312 && self.symbol
.number_of_aux_symbols
> 0
314 // Function symbols may have a size.
315 if let Ok(aux
) = self
318 .get
::<pe
::ImageAuxSymbolFunction
>(self.index
.0 + 1)
320 u64::from(aux
.total_size
.get(LE
))
328 // Most symbols don't have sizes.
333 fn kind(&self) -> SymbolKind
{
334 let derived_kind
= if self.symbol
.derived_type() == pe
::IMAGE_SYM_DTYPE_FUNCTION
{
339 match self.symbol
.storage_class
{
340 pe
::IMAGE_SYM_CLASS_STATIC
=> {
341 if self.symbol
.value
.get(LE
) == 0 && self.symbol
.number_of_aux_symbols
> 0 {
347 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> derived_kind
,
348 pe
::IMAGE_SYM_CLASS_SECTION
=> SymbolKind
::Section
,
349 pe
::IMAGE_SYM_CLASS_FILE
=> SymbolKind
::File
,
350 pe
::IMAGE_SYM_CLASS_LABEL
=> SymbolKind
::Label
,
351 _
=> SymbolKind
::Unknown
,
355 fn section(&self) -> SymbolSection
{
356 match self.symbol
.section_number
.get(LE
) {
357 pe
::IMAGE_SYM_UNDEFINED
=> {
358 if self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_EXTERNAL
359 && self.symbol
.value
.get(LE
) == 0
361 SymbolSection
::Undefined
363 SymbolSection
::Common
366 pe
::IMAGE_SYM_ABSOLUTE
=> SymbolSection
::Absolute
,
367 pe
::IMAGE_SYM_DEBUG
=> {
368 if self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_FILE
{
371 SymbolSection
::Unknown
374 index
if index
> 0 => SymbolSection
::Section(SectionIndex(index
as usize)),
375 _
=> SymbolSection
::Unknown
,
380 fn is_undefined(&self) -> bool
{
381 self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_EXTERNAL
382 && self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
383 && self.symbol
.value
.get(LE
) == 0
387 fn is_definition(&self) -> bool
{
388 self.symbol
.is_definition()
392 fn is_common(&self) -> bool
{
393 self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_EXTERNAL
394 && self.symbol
.section_number
.get(LE
) == pe
::IMAGE_SYM_UNDEFINED
395 && self.symbol
.value
.get(LE
) != 0
399 fn is_weak(&self) -> bool
{
400 self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
404 fn scope(&self) -> SymbolScope
{
405 match self.symbol
.storage_class
{
406 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> {
407 // TODO: determine if symbol is exported
410 _
=> SymbolScope
::Compilation
,
415 fn is_global(&self) -> bool
{
416 match self.symbol
.storage_class
{
417 pe
::IMAGE_SYM_CLASS_EXTERNAL
| pe
::IMAGE_SYM_CLASS_WEAK_EXTERNAL
=> true,
423 fn is_local(&self) -> bool
{
427 fn flags(&self) -> SymbolFlags
<SectionIndex
> {
428 if self.symbol
.storage_class
== pe
::IMAGE_SYM_CLASS_STATIC
429 && self.symbol
.value
.get(LE
) == 0
430 && self.symbol
.number_of_aux_symbols
> 0
432 if let Ok(aux
) = self
435 .get
::<pe
::ImageAuxSymbolSection
>(self.index
.0 + 1)
437 // TODO: use high_number for bigobj
438 let number
= aux
.number
.get(LE
) as usize;
439 return SymbolFlags
::CoffSection
{
440 selection
: aux
.selection
,
441 associative_section
: if number
== 0 {
444 Some(SectionIndex(number
))