]> git.proxmox.com Git - rustc.git/blame - library/backtrace/src/symbolize/gimli/coff.rs
New upstream version 1.50.0+dfsg1
[rustc.git] / library / backtrace / src / symbolize / gimli / coff.rs
CommitLineData
fc512014 1use super::{Context, Mapping, Path, Stash, Vec};
3dfed10e 2use core::convert::TryFrom;
f035d41b
XL
3use object::pe::{ImageDosHeader, ImageSymbol};
4use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable};
5use object::read::StringTable;
6use object::{Bytes, LittleEndian as LE};
7
8#[cfg(target_pointer_width = "32")]
9type Pe = object::pe::ImageNtHeaders32;
10#[cfg(target_pointer_width = "64")]
11type Pe = object::pe::ImageNtHeaders64;
f035d41b
XL
12
13impl 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
20pub struct Object<'a> {
21 data: Bytes<'a>,
22 sections: SectionTable<'a>,
23 symbols: Vec<(usize, &'a ImageSymbol)>,
24 strings: StringTable<'a>,
25}
26
27pub 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
34impl<'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}