summaryrefslogtreecommitdiffstats
path: root/vendor/backtrace/src/symbolize/gimli/coff.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/backtrace/src/symbolize/gimli/coff.rs')
-rw-r--r--vendor/backtrace/src/symbolize/gimli/coff.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/vendor/backtrace/src/symbolize/gimli/coff.rs b/vendor/backtrace/src/symbolize/gimli/coff.rs
new file mode 100644
index 000000000..84d334207
--- /dev/null
+++ b/vendor/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<Mapping> {
+ 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<usize> {
+ 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<Object<'a>> {
+ 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
+ }
+}