From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- library/backtrace/src/symbolize/gimli/coff.rs | 108 ++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 library/backtrace/src/symbolize/gimli/coff.rs (limited to 'library/backtrace/src/symbolize/gimli/coff.rs') diff --git a/library/backtrace/src/symbolize/gimli/coff.rs b/library/backtrace/src/symbolize/gimli/coff.rs new file mode 100644 index 000000000..84d334207 --- /dev/null +++ b/library/backtrace/src/symbolize/gimli/coff.rs @@ -0,0 +1,108 @@ +use super::{Context, Mapping, Path, Stash, Vec}; +use core::convert::TryFrom; +use object::pe::{ImageDosHeader, ImageSymbol}; +use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable}; +use object::read::StringTable; +use object::LittleEndian as LE; + +#[cfg(target_pointer_width = "32")] +type Pe = object::pe::ImageNtHeaders32; +#[cfg(target_pointer_width = "64")] +type Pe = object::pe::ImageNtHeaders64; + +impl Mapping { + pub fn new(path: &Path) -> Option { + let map = super::mmap(path)?; + Mapping::mk(map, |data, stash| { + Context::new(stash, Object::parse(data)?, None) + }) + } +} + +pub struct Object<'a> { + data: &'a [u8], + sections: SectionTable<'a>, + symbols: Vec<(usize, &'a ImageSymbol)>, + strings: StringTable<'a>, +} + +pub fn get_image_base(data: &[u8]) -> Option { + let dos_header = ImageDosHeader::parse(data).ok()?; + let mut offset = dos_header.nt_headers_offset().into(); + let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?; + usize::try_from(nt_headers.optional_header().image_base()).ok() +} + +impl<'a> Object<'a> { + fn parse(data: &'a [u8]) -> Option> { + let dos_header = ImageDosHeader::parse(data).ok()?; + let mut offset = dos_header.nt_headers_offset().into(); + let (nt_headers, _) = Pe::parse(data, &mut offset).ok()?; + let sections = nt_headers.sections(data, offset).ok()?; + let symtab = nt_headers.symbols(data).ok()?; + let strings = symtab.strings(); + let image_base = usize::try_from(nt_headers.optional_header().image_base()).ok()?; + + // Collect all the symbols into a local vector which is sorted + // by address and contains enough data to learn about the symbol + // name. Note that we only look at function symbols and also + // note that the sections are 1-indexed because the zero section + // is special (apparently). + let mut symbols = Vec::new(); + let mut i = 0; + let len = symtab.len(); + while i < len { + let sym = symtab.symbol(i).ok()?; + i += 1 + sym.number_of_aux_symbols as usize; + let section_number = sym.section_number.get(LE); + if sym.derived_type() != object::pe::IMAGE_SYM_DTYPE_FUNCTION || section_number == 0 { + continue; + } + let addr = usize::try_from(sym.value.get(LE)).ok()?; + let section = sections + .section(usize::try_from(section_number).ok()?) + .ok()?; + let va = usize::try_from(section.virtual_address.get(LE)).ok()?; + symbols.push((addr + va + image_base, sym)); + } + symbols.sort_unstable_by_key(|x| x.0); + Some(Object { + data, + sections, + strings, + symbols, + }) + } + + pub fn section(&self, _: &Stash, name: &str) -> Option<&'a [u8]> { + Some( + self.sections + .section_by_name(self.strings, name.as_bytes())? + .1 + .pe_data(self.data) + .ok()?, + ) + } + + pub fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> { + // Note that unlike other formats COFF doesn't embed the size of + // each symbol. As a last ditch effort search for the *closest* + // symbol to a particular address and return that one. This gets + // really wonky once symbols start getting removed because the + // symbols returned here can be totally incorrect, but we have + // no idea of knowing how to detect that. + let addr = usize::try_from(addr).ok()?; + let i = match self.symbols.binary_search_by_key(&addr, |p| p.0) { + Ok(i) => i, + // typically `addr` isn't in the array, but `i` is where + // we'd insert it, so the previous position must be the + // greatest less than `addr` + Err(i) => i.checked_sub(1)?, + }; + self.symbols[i].1.name(self.strings).ok() + } + + pub(super) fn search_object_map(&self, _addr: u64) -> Option<(&Context<'_>, u64)> { + None + } +} -- cgit v1.2.3