diff options
Diffstat (limited to 'library/backtrace/src/symbolize/gimli.rs')
-rw-r--r-- | library/backtrace/src/symbolize/gimli.rs | 73 |
1 files changed, 60 insertions, 13 deletions
diff --git a/library/backtrace/src/symbolize/gimli.rs b/library/backtrace/src/symbolize/gimli.rs index cd4cec58c..7f1c6a528 100644 --- a/library/backtrace/src/symbolize/gimli.rs +++ b/library/backtrace/src/symbolize/gimli.rs @@ -58,7 +58,7 @@ struct Mapping { // 'static lifetime is a lie to hack around lack of support for self-referential structs. cx: Context<'static>, _map: Mmap, - _stash: Stash, + stash: Stash, } enum Either<A, B> { @@ -97,7 +97,7 @@ impl Mapping { // only borrow `map` and `stash` and we're preserving them below. cx: unsafe { core::mem::transmute::<Context<'_>, Context<'static>>(cx) }, _map: data, - _stash: stash, + stash: stash, }) } } @@ -105,6 +105,7 @@ impl Mapping { struct Context<'a> { dwarf: addr2line::Context<EndianSlice<'a, Endian>>, object: Object<'a>, + package: Option<gimli::DwarfPackage<EndianSlice<'a, Endian>>>, } impl<'data> Context<'data> { @@ -112,6 +113,7 @@ impl<'data> Context<'data> { stash: &'data Stash, object: Object<'data>, sup: Option<Object<'data>>, + dwp: Option<Object<'data>>, ) -> Option<Context<'data>> { let mut sections = gimli::Dwarf::load(|id| -> Result<_, ()> { let data = object.section(stash, id.name()).unwrap_or(&[]); @@ -129,7 +131,46 @@ impl<'data> Context<'data> { } let dwarf = addr2line::Context::from_dwarf(sections).ok()?; - Some(Context { dwarf, object }) + let mut package = None; + if let Some(dwp) = dwp { + package = Some( + gimli::DwarfPackage::load( + |id| -> Result<_, gimli::Error> { + let data = id + .dwo_name() + .and_then(|name| dwp.section(stash, name)) + .unwrap_or(&[]); + Ok(EndianSlice::new(data, Endian)) + }, + EndianSlice::new(&[], Endian), + ) + .ok()?, + ); + } + + Some(Context { + dwarf, + object, + package, + }) + } + + fn find_frames( + &'_ self, + stash: &'data Stash, + probe: u64, + ) -> gimli::Result<addr2line::FrameIter<'_, EndianSlice<'data, Endian>>> { + use addr2line::{LookupContinuation, LookupResult}; + + let mut l = self.dwarf.find_frames(probe); + loop { + let (load, continuation) = match l { + LookupResult::Output(output) => break output, + LookupResult::Load { load, continuation } => (load, continuation), + }; + + l = continuation.resume(handle_split_dwarf(self.package.as_ref(), stash, load)); + } } } @@ -142,7 +183,7 @@ fn mmap(path: &Path) -> Option<Mmap> { cfg_if::cfg_if! { if #[cfg(windows)] { mod coff; - use self::coff::Object; + use self::coff::{handle_split_dwarf, Object}; } else if #[cfg(any( target_os = "macos", target_os = "ios", @@ -150,10 +191,10 @@ cfg_if::cfg_if! { target_os = "watchos", ))] { mod macho; - use self::macho::Object; + use self::macho::{handle_split_dwarf, Object}; } else { mod elf; - use self::elf::Object; + use self::elf::{handle_split_dwarf, Object}; } } @@ -178,6 +219,7 @@ cfg_if::cfg_if! { target_os = "fuchsia", target_os = "freebsd", target_os = "openbsd", + target_os = "netbsd", all(target_os = "android", feature = "dl_iterate_phdr"), ), not(target_env = "uclibc"), @@ -302,7 +344,7 @@ impl Cache { .next() } - fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<&'a mut Context<'a>> { + fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<(&'a mut Context<'a>, &'a Stash)> { let idx = self.mappings.iter().position(|(idx, _)| *idx == lib); // Invariant: after this conditional completes without early returning @@ -328,10 +370,15 @@ impl Cache { self.mappings.insert(0, (lib, mapping)); } - let cx: &'a mut Context<'static> = &mut self.mappings[0].1.cx; + let mapping = &mut self.mappings[0].1; + let cx: &'a mut Context<'static> = &mut mapping.cx; + let stash: &'a Stash = &mapping.stash; // don't leak the `'static` lifetime, make sure it's scoped to just // ourselves - Some(unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) }) + Some(( + unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) }, + stash, + )) } } @@ -353,12 +400,12 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) // Finally, get a cached mapping or create a new mapping for this file, and // evaluate the DWARF info to find the file/line/name for this address. - let cx = match cache.mapping_for_lib(lib) { - Some(cx) => cx, + let (cx, stash) = match cache.mapping_for_lib(lib) { + Some((cx, stash)) => (cx, stash), None => return, }; let mut any_frames = false; - if let Ok(mut frames) = cx.dwarf.find_frames(addr as u64) { + if let Ok(mut frames) = cx.find_frames(stash, addr as u64) { while let Ok(Some(frame)) = frames.next() { any_frames = true; let name = match frame.function { @@ -374,7 +421,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol)) } if !any_frames { if let Some((object_cx, object_addr)) = cx.object.search_object_map(addr as u64) { - if let Ok(mut frames) = object_cx.dwarf.find_frames(object_addr) { + if let Ok(mut frames) = object_cx.find_frames(stash, object_addr) { while let Ok(Some(frame)) = frames.next() { any_frames = true; call(Symbol::Frame { |