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