1 | use alloc::fmt; |
2 | use alloc::vec::Vec; |
3 | use core::convert::TryInto; |
4 | use core::fmt::Debug; |
5 | use core::str; |
6 | |
7 | use super::{CoffCommon, CoffHeader, SectionTable}; |
8 | use crate::endian::{LittleEndian as LE, U32Bytes}; |
9 | use crate::pe; |
10 | use crate::pod::{bytes_of, bytes_of_slice, Pod}; |
11 | use crate::read::util::StringTable; |
12 | use crate::read::{ |
13 | self, Bytes, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex, |
14 | SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolMapEntry, SymbolScope, SymbolSection, |
15 | }; |
16 | |
17 | /// A table of symbol entries in a COFF or PE file. |
18 | /// |
19 | /// Also includes the string table used for the symbol names. |
20 | /// |
21 | /// Returned by [`CoffHeader::symbols`] and |
22 | /// [`ImageNtHeaders::symbols`](crate::read::pe::ImageNtHeaders::symbols). |
23 | #[derive (Debug)] |
24 | pub struct SymbolTable<'data, R = &'data [u8], Coff = pe::ImageFileHeader> |
25 | where |
26 | R: ReadRef<'data>, |
27 | Coff: CoffHeader, |
28 | { |
29 | symbols: &'data [Coff::ImageSymbolBytes], |
30 | strings: StringTable<'data, R>, |
31 | } |
32 | |
33 | impl<'data, R: ReadRef<'data>, Coff: CoffHeader> Default for SymbolTable<'data, R, Coff> { |
34 | fn default() -> Self { |
35 | Self { |
36 | symbols: &[], |
37 | strings: StringTable::default(), |
38 | } |
39 | } |
40 | } |
41 | |
42 | impl<'data, R: ReadRef<'data>, Coff: CoffHeader> SymbolTable<'data, R, Coff> { |
43 | /// Read the symbol table. |
44 | pub fn parse(header: &Coff, data: R) -> Result<Self> { |
45 | // The symbol table may not be present. |
46 | let mut offset = header.pointer_to_symbol_table().into(); |
47 | let (symbols, strings) = if offset != 0 { |
48 | let symbols = data |
49 | .read_slice(&mut offset, header.number_of_symbols() as usize) |
50 | .read_error("Invalid COFF symbol table offset or size" )?; |
51 | |
52 | // Note: don't update data when reading length; the length includes itself. |
53 | let length = data |
54 | .read_at::<U32Bytes<_>>(offset) |
55 | .read_error("Missing COFF string table" )? |
56 | .get(LE); |
57 | let str_end = offset |
58 | .checked_add(length as u64) |
59 | .read_error("Invalid COFF string table length" )?; |
60 | let strings = StringTable::new(data, offset, str_end); |
61 | |
62 | (symbols, strings) |
63 | } else { |
64 | (&[][..], StringTable::default()) |
65 | }; |
66 | |
67 | Ok(SymbolTable { symbols, strings }) |
68 | } |
69 | |
70 | /// Return the string table used for the symbol names. |
71 | #[inline ] |
72 | pub fn strings(&self) -> StringTable<'data, R> { |
73 | self.strings |
74 | } |
75 | |
76 | /// Return true if the symbol table is empty. |
77 | #[inline ] |
78 | pub fn is_empty(&self) -> bool { |
79 | self.symbols.is_empty() |
80 | } |
81 | |
82 | /// The number of symbol table entries. |
83 | /// |
84 | /// This includes auxiliary symbol table entries. |
85 | #[inline ] |
86 | pub fn len(&self) -> usize { |
87 | self.symbols.len() |
88 | } |
89 | |
90 | /// Iterate over the symbols. |
91 | #[inline ] |
92 | pub fn iter<'table>(&'table self) -> SymbolIterator<'data, 'table, R, Coff> { |
93 | SymbolIterator { |
94 | symbols: self, |
95 | index: SymbolIndex(0), |
96 | } |
97 | } |
98 | |
99 | /// Return the symbol table entry at the given index. |
100 | #[inline ] |
101 | pub fn symbol(&self, index: SymbolIndex) -> Result<&'data Coff::ImageSymbol> { |
102 | self.get::<Coff::ImageSymbol>(index, 0) |
103 | } |
104 | |
105 | /// Return the auxiliary function symbol for the symbol table entry at the given index. |
106 | /// |
107 | /// Note that the index is of the symbol, not the first auxiliary record. |
108 | #[inline ] |
109 | pub fn aux_function(&self, index: SymbolIndex) -> Result<&'data pe::ImageAuxSymbolFunction> { |
110 | self.get::<pe::ImageAuxSymbolFunction>(index, 1) |
111 | } |
112 | |
113 | /// Return the auxiliary section symbol for the symbol table entry at the given index. |
114 | /// |
115 | /// Note that the index is of the symbol, not the first auxiliary record. |
116 | #[inline ] |
117 | pub fn aux_section(&self, index: SymbolIndex) -> Result<&'data pe::ImageAuxSymbolSection> { |
118 | self.get::<pe::ImageAuxSymbolSection>(index, 1) |
119 | } |
120 | |
121 | /// Return the auxiliary file name for the symbol table entry at the given index. |
122 | /// |
123 | /// Note that the index is of the symbol, not the first auxiliary record. |
124 | pub fn aux_file_name(&self, index: SymbolIndex, aux_count: u8) -> Result<&'data [u8]> { |
125 | let entries = index |
126 | .0 |
127 | .checked_add(1) |
128 | .and_then(|x| Some(x..x.checked_add(aux_count.into())?)) |
129 | .and_then(|x| self.symbols.get(x)) |
130 | .read_error("Invalid COFF symbol index" )?; |
131 | let bytes = bytes_of_slice(entries); |
132 | // The name is padded with nulls. |
133 | Ok(match memchr::memchr(b' \0' , bytes) { |
134 | Some(end) => &bytes[..end], |
135 | None => bytes, |
136 | }) |
137 | } |
138 | |
139 | /// Return the symbol table entry or auxiliary record at the given index and offset. |
140 | pub fn get<T: Pod>(&self, index: SymbolIndex, offset: usize) -> Result<&'data T> { |
141 | let bytes = index |
142 | .0 |
143 | .checked_add(offset) |
144 | .and_then(|x| self.symbols.get(x)) |
145 | .read_error("Invalid COFF symbol index" )?; |
146 | Bytes(bytes_of(bytes)) |
147 | .read() |
148 | .read_error("Invalid COFF symbol data" ) |
149 | } |
150 | |
151 | /// Construct a map from addresses to a user-defined map entry. |
152 | pub fn map<Entry: SymbolMapEntry, F: Fn(&'data Coff::ImageSymbol) -> Option<Entry>>( |
153 | &self, |
154 | f: F, |
155 | ) -> SymbolMap<Entry> { |
156 | let mut symbols = Vec::with_capacity(self.symbols.len()); |
157 | for (_, symbol) in self.iter() { |
158 | if !symbol.is_definition() { |
159 | continue; |
160 | } |
161 | if let Some(entry) = f(symbol) { |
162 | symbols.push(entry); |
163 | } |
164 | } |
165 | SymbolMap::new(symbols) |
166 | } |
167 | } |
168 | |
169 | /// An iterator for symbol entries in a COFF or PE file. |
170 | /// |
171 | /// Yields the index and symbol structure for each symbol. |
172 | #[derive (Debug)] |
173 | pub struct SymbolIterator<'data, 'table, R = &'data [u8], Coff = pe::ImageFileHeader> |
174 | where |
175 | R: ReadRef<'data>, |
176 | Coff: CoffHeader, |
177 | { |
178 | symbols: &'table SymbolTable<'data, R, Coff>, |
179 | index: SymbolIndex, |
180 | } |
181 | |
182 | impl<'data, 'table, R: ReadRef<'data>, Coff: CoffHeader> Iterator |
183 | for SymbolIterator<'data, 'table, R, Coff> |
184 | { |
185 | type Item = (SymbolIndex, &'data Coff::ImageSymbol); |
186 | |
187 | fn next(&mut self) -> Option<Self::Item> { |
188 | let index: SymbolIndex = self.index; |
189 | let symbol: &'data ::ImageSymbol = self.symbols.symbol(index).ok()?; |
190 | self.index.0 += 1 + symbol.number_of_aux_symbols() as usize; |
191 | Some((index, symbol)) |
192 | } |
193 | } |
194 | |
195 | /// A symbol table in a [`CoffBigFile`](super::CoffBigFile). |
196 | pub type CoffBigSymbolTable<'data, 'file, R = &'data [u8]> = |
197 | CoffSymbolTable<'data, 'file, R, pe::AnonObjectHeaderBigobj>; |
198 | |
199 | /// A symbol table in a [`CoffFile`](super::CoffFile) |
200 | /// or [`PeFile`](crate::read::pe::PeFile). |
201 | #[derive (Debug, Clone, Copy)] |
202 | pub struct CoffSymbolTable<'data, 'file, R = &'data [u8], Coff = pe::ImageFileHeader> |
203 | where |
204 | R: ReadRef<'data>, |
205 | Coff: CoffHeader, |
206 | { |
207 | pub(crate) file: &'file CoffCommon<'data, R, Coff>, |
208 | } |
209 | |
210 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed |
211 | for CoffSymbolTable<'data, 'file, R, Coff> |
212 | { |
213 | } |
214 | |
215 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbolTable<'data> |
216 | for CoffSymbolTable<'data, 'file, R, Coff> |
217 | { |
218 | type Symbol = CoffSymbol<'data, 'file, R, Coff>; |
219 | type SymbolIterator = CoffSymbolIterator<'data, 'file, R, Coff>; |
220 | |
221 | fn symbols(&self) -> Self::SymbolIterator { |
222 | CoffSymbolIterator::new(self.file) |
223 | } |
224 | |
225 | fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol> { |
226 | let symbol: &'data ::ImageSymbol = self.file.symbols.symbol(index)?; |
227 | Ok(CoffSymbol { |
228 | file: self.file, |
229 | index, |
230 | symbol, |
231 | }) |
232 | } |
233 | } |
234 | |
235 | /// An iterator for the symbols in a [`CoffBigFile`](super::CoffBigFile). |
236 | pub type CoffBigSymbolIterator<'data, 'file, R = &'data [u8]> = |
237 | CoffSymbolIterator<'data, 'file, R, pe::AnonObjectHeaderBigobj>; |
238 | |
239 | /// An iterator for the symbols in a [`CoffFile`](super::CoffFile) |
240 | /// or [`PeFile`](crate::read::pe::PeFile). |
241 | pub struct CoffSymbolIterator<'data, 'file, R = &'data [u8], Coff = pe::ImageFileHeader> |
242 | where |
243 | R: ReadRef<'data>, |
244 | Coff: CoffHeader, |
245 | { |
246 | file: &'file CoffCommon<'data, R, Coff>, |
247 | index: SymbolIndex, |
248 | } |
249 | |
250 | impl<'data, 'file, R, Coff> CoffSymbolIterator<'data, 'file, R, Coff> |
251 | where |
252 | R: ReadRef<'data>, |
253 | Coff: CoffHeader, |
254 | { |
255 | pub(crate) fn new(file: &'file CoffCommon<'data, R, Coff>) -> Self { |
256 | Self { |
257 | file, |
258 | index: SymbolIndex(0), |
259 | } |
260 | } |
261 | |
262 | pub(crate) fn empty(file: &'file CoffCommon<'data, R, Coff>) -> Self { |
263 | Self { |
264 | file, |
265 | index: SymbolIndex(file.symbols.len()), |
266 | } |
267 | } |
268 | } |
269 | |
270 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> fmt::Debug |
271 | for CoffSymbolIterator<'data, 'file, R, Coff> |
272 | { |
273 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
274 | f.debug_struct(name:"CoffSymbolIterator" ).finish() |
275 | } |
276 | } |
277 | |
278 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> Iterator |
279 | for CoffSymbolIterator<'data, 'file, R, Coff> |
280 | { |
281 | type Item = CoffSymbol<'data, 'file, R, Coff>; |
282 | |
283 | fn next(&mut self) -> Option<Self::Item> { |
284 | let index: SymbolIndex = self.index; |
285 | let symbol: &'data ::ImageSymbol = self.file.symbols.symbol(index).ok()?; |
286 | self.index.0 += 1 + symbol.number_of_aux_symbols() as usize; |
287 | Some(CoffSymbol { |
288 | file: self.file, |
289 | index, |
290 | symbol, |
291 | }) |
292 | } |
293 | } |
294 | |
295 | /// A symbol in a [`CoffBigFile`](super::CoffBigFile). |
296 | /// |
297 | /// Most functionality is provided by the [`ObjectSymbol`] trait implementation. |
298 | pub type CoffBigSymbol<'data, 'file, R = &'data [u8]> = |
299 | CoffSymbol<'data, 'file, R, pe::AnonObjectHeaderBigobj>; |
300 | |
301 | /// A symbol in a [`CoffFile`](super::CoffFile) or [`PeFile`](crate::read::pe::PeFile). |
302 | /// |
303 | /// Most functionality is provided by the [`ObjectSymbol`] trait implementation. |
304 | #[derive (Debug, Clone, Copy)] |
305 | pub struct CoffSymbol<'data, 'file, R = &'data [u8], Coff = pe::ImageFileHeader> |
306 | where |
307 | R: ReadRef<'data>, |
308 | Coff: CoffHeader, |
309 | { |
310 | pub(crate) file: &'file CoffCommon<'data, R, Coff>, |
311 | pub(crate) index: SymbolIndex, |
312 | pub(crate) symbol: &'data Coff::ImageSymbol, |
313 | } |
314 | |
315 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> CoffSymbol<'data, 'file, R, Coff> { |
316 | #[inline ] |
317 | /// Get the raw `ImageSymbol` struct. |
318 | #[deprecated (note = "Use `coff_symbol` instead" )] |
319 | pub fn raw_symbol(&self) -> &'data Coff::ImageSymbol { |
320 | self.symbol |
321 | } |
322 | |
323 | /// Get the raw `ImageSymbol` struct. |
324 | pub fn coff_symbol(&self) -> &'data Coff::ImageSymbol { |
325 | self.symbol |
326 | } |
327 | } |
328 | |
329 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> read::private::Sealed |
330 | for CoffSymbol<'data, 'file, R, Coff> |
331 | { |
332 | } |
333 | |
334 | impl<'data, 'file, R: ReadRef<'data>, Coff: CoffHeader> ObjectSymbol<'data> |
335 | for CoffSymbol<'data, 'file, R, Coff> |
336 | { |
337 | #[inline ] |
338 | fn index(&self) -> SymbolIndex { |
339 | self.index |
340 | } |
341 | |
342 | fn name_bytes(&self) -> read::Result<&'data [u8]> { |
343 | if self.symbol.has_aux_file_name() { |
344 | self.file |
345 | .symbols |
346 | .aux_file_name(self.index, self.symbol.number_of_aux_symbols()) |
347 | } else { |
348 | self.symbol.name(self.file.symbols.strings()) |
349 | } |
350 | } |
351 | |
352 | fn name(&self) -> read::Result<&'data str> { |
353 | let name = self.name_bytes()?; |
354 | str::from_utf8(name) |
355 | .ok() |
356 | .read_error("Non UTF-8 COFF symbol name" ) |
357 | } |
358 | |
359 | fn address(&self) -> u64 { |
360 | self.symbol |
361 | .address(self.file.image_base, &self.file.sections) |
362 | .unwrap_or(None) |
363 | .unwrap_or(0) |
364 | } |
365 | |
366 | fn size(&self) -> u64 { |
367 | match self.symbol.storage_class() { |
368 | pe::IMAGE_SYM_CLASS_STATIC => { |
369 | // Section symbols may duplicate the size from the section table. |
370 | if self.symbol.has_aux_section() { |
371 | if let Ok(aux) = self.file.symbols.aux_section(self.index) { |
372 | u64::from(aux.length.get(LE)) |
373 | } else { |
374 | 0 |
375 | } |
376 | } else { |
377 | 0 |
378 | } |
379 | } |
380 | pe::IMAGE_SYM_CLASS_EXTERNAL => { |
381 | if self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED { |
382 | // For undefined symbols, symbol.value is 0 and the size is 0. |
383 | // For common data, symbol.value is the size. |
384 | u64::from(self.symbol.value()) |
385 | } else if self.symbol.has_aux_function() { |
386 | // Function symbols may have a size. |
387 | if let Ok(aux) = self.file.symbols.aux_function(self.index) { |
388 | u64::from(aux.total_size.get(LE)) |
389 | } else { |
390 | 0 |
391 | } |
392 | } else { |
393 | 0 |
394 | } |
395 | } |
396 | // Most symbols don't have sizes. |
397 | _ => 0, |
398 | } |
399 | } |
400 | |
401 | fn kind(&self) -> SymbolKind { |
402 | let derived_kind = if self.symbol.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION { |
403 | SymbolKind::Text |
404 | } else { |
405 | SymbolKind::Data |
406 | }; |
407 | match self.symbol.storage_class() { |
408 | pe::IMAGE_SYM_CLASS_STATIC => { |
409 | if self.symbol.has_aux_section() { |
410 | SymbolKind::Section |
411 | } else { |
412 | derived_kind |
413 | } |
414 | } |
415 | pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => derived_kind, |
416 | pe::IMAGE_SYM_CLASS_SECTION => SymbolKind::Section, |
417 | pe::IMAGE_SYM_CLASS_FILE => SymbolKind::File, |
418 | pe::IMAGE_SYM_CLASS_LABEL => SymbolKind::Label, |
419 | _ => SymbolKind::Unknown, |
420 | } |
421 | } |
422 | |
423 | fn section(&self) -> SymbolSection { |
424 | match self.symbol.section_number() { |
425 | pe::IMAGE_SYM_UNDEFINED => { |
426 | if self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_EXTERNAL { |
427 | if self.symbol.value() == 0 { |
428 | SymbolSection::Undefined |
429 | } else { |
430 | SymbolSection::Common |
431 | } |
432 | } else if self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_SECTION { |
433 | SymbolSection::Undefined |
434 | } else { |
435 | SymbolSection::Unknown |
436 | } |
437 | } |
438 | pe::IMAGE_SYM_ABSOLUTE => SymbolSection::Absolute, |
439 | pe::IMAGE_SYM_DEBUG => { |
440 | if self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_FILE { |
441 | SymbolSection::None |
442 | } else { |
443 | SymbolSection::Unknown |
444 | } |
445 | } |
446 | index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)), |
447 | _ => SymbolSection::Unknown, |
448 | } |
449 | } |
450 | |
451 | #[inline ] |
452 | fn is_undefined(&self) -> bool { |
453 | self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_EXTERNAL |
454 | && self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED |
455 | && self.symbol.value() == 0 |
456 | } |
457 | |
458 | #[inline ] |
459 | fn is_definition(&self) -> bool { |
460 | self.symbol.is_definition() |
461 | } |
462 | |
463 | #[inline ] |
464 | fn is_common(&self) -> bool { |
465 | self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_EXTERNAL |
466 | && self.symbol.section_number() == pe::IMAGE_SYM_UNDEFINED |
467 | && self.symbol.value() != 0 |
468 | } |
469 | |
470 | #[inline ] |
471 | fn is_weak(&self) -> bool { |
472 | self.symbol.storage_class() == pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL |
473 | } |
474 | |
475 | #[inline ] |
476 | fn scope(&self) -> SymbolScope { |
477 | match self.symbol.storage_class() { |
478 | pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => { |
479 | // TODO: determine if symbol is exported |
480 | SymbolScope::Linkage |
481 | } |
482 | _ => SymbolScope::Compilation, |
483 | } |
484 | } |
485 | |
486 | #[inline ] |
487 | fn is_global(&self) -> bool { |
488 | match self.symbol.storage_class() { |
489 | pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true, |
490 | _ => false, |
491 | } |
492 | } |
493 | |
494 | #[inline ] |
495 | fn is_local(&self) -> bool { |
496 | !self.is_global() |
497 | } |
498 | |
499 | fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> { |
500 | if self.symbol.has_aux_section() { |
501 | if let Ok(aux) = self.file.symbols.aux_section(self.index) { |
502 | let number = if Coff::is_type_bigobj() { |
503 | u32::from(aux.number.get(LE)) | (u32::from(aux.high_number.get(LE)) << 16) |
504 | } else { |
505 | u32::from(aux.number.get(LE)) |
506 | }; |
507 | return SymbolFlags::CoffSection { |
508 | selection: aux.selection, |
509 | associative_section: if number == 0 { |
510 | None |
511 | } else { |
512 | Some(SectionIndex(number as usize)) |
513 | }, |
514 | }; |
515 | } |
516 | } |
517 | SymbolFlags::None |
518 | } |
519 | } |
520 | |
521 | /// A trait for generic access to [`pe::ImageSymbol`] and [`pe::ImageSymbolEx`]. |
522 | #[allow (missing_docs)] |
523 | pub trait ImageSymbol: Debug + Pod { |
524 | fn raw_name(&self) -> &[u8; 8]; |
525 | fn value(&self) -> u32; |
526 | fn section_number(&self) -> i32; |
527 | fn typ(&self) -> u16; |
528 | fn storage_class(&self) -> u8; |
529 | fn number_of_aux_symbols(&self) -> u8; |
530 | |
531 | /// Parse a COFF symbol name. |
532 | /// |
533 | /// `strings` must be the string table used for symbol names. |
534 | fn name<'data, R: ReadRef<'data>>( |
535 | &'data self, |
536 | strings: StringTable<'data, R>, |
537 | ) -> Result<&'data [u8]> { |
538 | let name = self.raw_name(); |
539 | if name[0] == 0 { |
540 | // If the name starts with 0 then the last 4 bytes are a string table offset. |
541 | let offset = u32::from_le_bytes(name[4..8].try_into().unwrap()); |
542 | strings |
543 | .get(offset) |
544 | .read_error("Invalid COFF symbol name offset" ) |
545 | } else { |
546 | // The name is inline and padded with nulls. |
547 | Ok(match memchr::memchr(b' \0' , name) { |
548 | Some(end) => &name[..end], |
549 | None => &name[..], |
550 | }) |
551 | } |
552 | } |
553 | |
554 | /// Return the symbol address. |
555 | /// |
556 | /// This takes into account the image base and the section address, |
557 | /// and only returns an address for symbols that have an address. |
558 | fn address(&self, image_base: u64, sections: &SectionTable<'_>) -> Result<Option<u64>> { |
559 | // Only return an address for storage classes that we know use an address. |
560 | match self.storage_class() { |
561 | pe::IMAGE_SYM_CLASS_STATIC |
562 | | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL |
563 | | pe::IMAGE_SYM_CLASS_LABEL |
564 | | pe::IMAGE_SYM_CLASS_EXTERNAL => {} |
565 | _ => return Ok(None), |
566 | } |
567 | let Some(section_index) = self.section() else { |
568 | return Ok(None); |
569 | }; |
570 | let section = sections.section(section_index)?; |
571 | let virtual_address = u64::from(section.virtual_address.get(LE)); |
572 | let value = u64::from(self.value()); |
573 | Ok(Some(image_base + virtual_address + value)) |
574 | } |
575 | |
576 | /// Return the section index for the symbol. |
577 | fn section(&self) -> Option<SectionIndex> { |
578 | let section_number = self.section_number(); |
579 | if section_number > 0 { |
580 | Some(SectionIndex(section_number as usize)) |
581 | } else { |
582 | None |
583 | } |
584 | } |
585 | |
586 | /// Return true if the symbol is a definition of a function or data object. |
587 | fn is_definition(&self) -> bool { |
588 | if self.section_number() <= 0 { |
589 | return false; |
590 | } |
591 | match self.storage_class() { |
592 | pe::IMAGE_SYM_CLASS_STATIC => !self.has_aux_section(), |
593 | pe::IMAGE_SYM_CLASS_EXTERNAL | pe::IMAGE_SYM_CLASS_WEAK_EXTERNAL => true, |
594 | _ => false, |
595 | } |
596 | } |
597 | |
598 | /// Return true if the symbol has an auxiliary file name. |
599 | fn has_aux_file_name(&self) -> bool { |
600 | self.number_of_aux_symbols() > 0 && self.storage_class() == pe::IMAGE_SYM_CLASS_FILE |
601 | } |
602 | |
603 | /// Return true if the symbol has an auxiliary function symbol. |
604 | fn has_aux_function(&self) -> bool { |
605 | self.number_of_aux_symbols() > 0 && self.derived_type() == pe::IMAGE_SYM_DTYPE_FUNCTION |
606 | } |
607 | |
608 | /// Return true if the symbol has an auxiliary section symbol. |
609 | fn has_aux_section(&self) -> bool { |
610 | self.number_of_aux_symbols() > 0 |
611 | && self.storage_class() == pe::IMAGE_SYM_CLASS_STATIC |
612 | && self.typ() == 0 |
613 | } |
614 | |
615 | fn base_type(&self) -> u16 { |
616 | self.typ() & pe::N_BTMASK |
617 | } |
618 | |
619 | fn derived_type(&self) -> u16 { |
620 | (self.typ() & pe::N_TMASK) >> pe::N_BTSHFT |
621 | } |
622 | } |
623 | |
624 | impl ImageSymbol for pe::ImageSymbol { |
625 | fn raw_name(&self) -> &[u8; 8] { |
626 | &self.name |
627 | } |
628 | fn value(&self) -> u32 { |
629 | self.value.get(LE) |
630 | } |
631 | fn section_number(&self) -> i32 { |
632 | let section_number = self.section_number.get(LE); |
633 | if section_number >= pe::IMAGE_SYM_SECTION_MAX { |
634 | (section_number as i16) as i32 |
635 | } else { |
636 | section_number as i32 |
637 | } |
638 | } |
639 | fn typ(&self) -> u16 { |
640 | self.typ.get(LE) |
641 | } |
642 | fn storage_class(&self) -> u8 { |
643 | self.storage_class |
644 | } |
645 | fn number_of_aux_symbols(&self) -> u8 { |
646 | self.number_of_aux_symbols |
647 | } |
648 | } |
649 | |
650 | impl ImageSymbol for pe::ImageSymbolEx { |
651 | fn raw_name(&self) -> &[u8; 8] { |
652 | &self.name |
653 | } |
654 | fn value(&self) -> u32 { |
655 | self.value.get(LE) |
656 | } |
657 | fn section_number(&self) -> i32 { |
658 | self.section_number.get(LE) |
659 | } |
660 | fn typ(&self) -> u16 { |
661 | self.typ.get(LE) |
662 | } |
663 | fn storage_class(&self) -> u8 { |
664 | self.storage_class |
665 | } |
666 | fn number_of_aux_symbols(&self) -> u8 { |
667 | self.number_of_aux_symbols |
668 | } |
669 | } |
670 | |