std\backtrace\src\symbolize\gimli/
coff.rs1use super::mystd::path::Path;
2use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash};
3use alloc::sync::Arc;
4use alloc::vec::Vec;
5use core::convert::TryFrom;
6use object::pe::{ImageDosHeader, ImageSymbol};
7use object::read::coff::ImageSymbol as _;
8use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable};
9use object::read::StringTable;
10use object::LittleEndian as LE;
11
12#[cfg(target_pointer_width = "32")]
13type Pe = object::pe::ImageNtHeaders32;
14#[cfg(target_pointer_width = "64")]
15type Pe = object::pe::ImageNtHeaders64;
16
17impl Mapping {
18 pub fn new(path: &Path) -> Option<Mapping> {
19 let map = super::mmap(path)?;
20 Mapping::mk(map, |data, stash| {
21 Context::new(stash, Object::parse(data)?, None, None)
22 })
23 }
24}
25
26pub struct Object<'a> {
27 data: &'a [u8],
28 sections: SectionTable<'a>,
29 symbols: Vec<(usize, &'a ImageSymbol)>,
30 strings: StringTable<'a>,
31}
32
33pub fn get_image_base(data: &[u8]) -> Option<usize> {
34 let dos_header = ImageDosHeader::parse(data).ok()?;
35 let mut offset = dos_header.nt_headers_offset().into();
36 let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?;
37 usize::try_from(nt_headers.optional_header().image_base()).ok()
38}
39
40impl<'a> Object<'a> {
41 fn parse(data: &'a [u8]) -> Option<Object<'a>> {
42 let dos_header = ImageDosHeader::parse(data).ok()?;
43 let mut offset = dos_header.nt_headers_offset().into();
44 let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?;
45 let sections = nt_headers.sections(data, offset).ok()?;
46 let symtab = nt_headers.symbols(data).ok()?;
47 let strings = symtab.strings();
48 let image_base = usize::try_from(nt_headers.optional_header().image_base()).ok()?;
49
50 let mut symbols = Vec::new();
56 for (_, sym) in symtab.iter() {
57 if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION {
58 continue;
59 }
60 let Some(section_index) = sym.section() else {
61 continue;
62 };
63 let addr = usize::try_from(sym.value.get(LE)).ok()?;
64 let section = sections.section(section_index).ok()?;
65 let va = usize::try_from(section.virtual_address.get(LE)).ok()?;
66 symbols.push((addr + va + image_base, sym));
67 }
68 symbols.sort_unstable_by_key(|x| x.0);
69 Some(Object {
70 data,
71 sections,
72 strings,
73 symbols,
74 })
75 }
76
77 pub fn section(&self, _: &Stash, name: &str) -> Option<&'a [u8]> {
78 Some(
79 self.sections
80 .section_by_name(self.strings, name.as_bytes())?
81 .1
82 .pe_data(self.data)
83 .ok()?,
84 )
85 }
86
87 pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> {
88 let addr = usize::try_from(addr).ok()?;
95 let i = match self.symbols.binary_search_by_key(&addr, |p| p.0) {
96 Ok(i) => i,
97 Err(i) => i.checked_sub(1)?,
101 };
102 self.symbols[i].1.name(self.strings).ok()
103 }
104
105 pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> {
106 None
107 }
108}
109
110pub(super) fn handle_split_dwarf<'data>(
111 _package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
112 _stash: &'data Stash,
113 _load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
114) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
115 None
116}