1 use super::{Context, Mapping, Path, Stash, Vec}
;
2 use core
::convert
::TryFrom
;
3 use object
::pe
::{ImageDosHeader, ImageSymbol}
;
4 use object
::read
::pe
::{ImageNtHeaders, ImageOptionalHeader, SectionTable}
;
5 use object
::read
::StringTable
;
6 use object
::LittleEndian
as LE
;
8 #[cfg(target_pointer_width = "32")]
9 type Pe
= object
::pe
::ImageNtHeaders32
;
10 #[cfg(target_pointer_width = "64")]
11 type Pe
= object
::pe
::ImageNtHeaders64
;
14 pub fn new(path
: &Path
) -> Option
<Mapping
> {
15 let map
= super::mmap(path
)?
;
16 Mapping
::mk(map
, |data
, stash
| {
17 Context
::new(stash
, Object
::parse(data
)?
, None
)
22 pub struct Object
<'a
> {
24 sections
: SectionTable
<'a
>,
25 symbols
: Vec
<(usize, &'a ImageSymbol
)>,
26 strings
: StringTable
<'a
>,
29 pub fn get_image_base(data
: &[u8]) -> Option
<usize> {
30 let dos_header
= ImageDosHeader
::parse(data
).ok()?
;
31 let mut offset
= dos_header
.nt_headers_offset().into();
32 let (nt_headers
, _
) = Pe
::parse(data
, &mut offset
).ok()?
;
33 usize::try_from(nt_headers
.optional_header().image_base()).ok()
37 fn parse(data
: &'a
[u8]) -> Option
<Object
<'a
>> {
38 let dos_header
= ImageDosHeader
::parse(data
).ok()?
;
39 let mut offset
= dos_header
.nt_headers_offset().into();
40 let (nt_headers
, _
) = Pe
::parse(data
, &mut offset
).ok()?
;
41 let sections
= nt_headers
.sections(data
, offset
).ok()?
;
42 let symtab
= nt_headers
.symbols(data
).ok()?
;
43 let strings
= symtab
.strings();
44 let image_base
= usize::try_from(nt_headers
.optional_header().image_base()).ok()?
;
46 // Collect all the symbols into a local vector which is sorted
47 // by address and contains enough data to learn about the symbol
48 // name. Note that we only look at function symbols and also
49 // note that the sections are 1-indexed because the zero section
50 // is special (apparently).
51 let mut symbols
= Vec
::new();
53 let len
= symtab
.len();
55 let sym
= symtab
.symbol(i
).ok()?
;
56 i
+= 1 + sym
.number_of_aux_symbols
as usize;
57 let section_number
= sym
.section_number
.get(LE
);
58 if sym
.derived_type() != object
::pe
::IMAGE_SYM_DTYPE_FUNCTION
|| section_number
== 0 {
61 let addr
= usize::try_from(sym
.value
.get(LE
)).ok()?
;
62 let section
= sections
63 .section(usize::try_from(section_number
).ok()?
)
65 let va
= usize::try_from(section
.virtual_address
.get(LE
)).ok()?
;
66 symbols
.push((addr
+ va
+ image_base
, sym
));
68 symbols
.sort_unstable_by_key(|x
| x
.0);
77 pub fn section(&self, _
: &Stash
, name
: &str) -> Option
<&'a
[u8]> {
80 .section_by_name(self.strings
, name
.as_bytes())?
87 pub fn search_symtab
<'b
>(&'b
self, addr
: u64) -> Option
<&'b
[u8]> {
88 // Note that unlike other formats COFF doesn't embed the size of
89 // each symbol. As a last ditch effort search for the *closest*
90 // symbol to a particular address and return that one. This gets
91 // really wonky once symbols start getting removed because the
92 // symbols returned here can be totally incorrect, but we have
93 // no idea of knowing how to detect that.
94 let addr
= usize::try_from(addr
).ok()?
;
95 let i
= match self.symbols
.binary_search_by_key(&addr
, |p
| p
.0) {
97 // typically `addr` isn't in the array, but `i` is where
98 // we'd insert it, so the previous position must be the
99 // greatest less than `addr`
100 Err(i
) => i
.checked_sub(1)?
,
102 self.symbols
[i
].1.name(self.strings
).ok()
105 pub(super) fn search_object_map(&self, _addr
: u64) -> Option
<(&Context
<'_
>, u64)> {