summaryrefslogtreecommitdiffstats
path: root/library/backtrace/src/symbolize/gimli/elf.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/backtrace/src/symbolize/gimli/elf.rs')
-rw-r--r--library/backtrace/src/symbolize/gimli/elf.rs92
1 files changed, 82 insertions, 10 deletions
diff --git a/library/backtrace/src/symbolize/gimli/elf.rs b/library/backtrace/src/symbolize/gimli/elf.rs
index bc71ee2c9..b0eec0762 100644
--- a/library/backtrace/src/symbolize/gimli/elf.rs
+++ b/library/backtrace/src/symbolize/gimli/elf.rs
@@ -3,7 +3,8 @@ use super::mystd::fs;
use super::mystd::os::unix::ffi::{OsStrExt, OsStringExt};
use super::mystd::path::{Path, PathBuf};
use super::Either;
-use super::{Context, Mapping, Stash, Vec};
+use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash, Vec};
+use alloc::sync::Arc;
use core::convert::{TryFrom, TryInto};
use core::str;
use object::elf::{ELFCOMPRESS_ZLIB, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED};
@@ -24,24 +25,26 @@ impl Mapping {
// Try to locate an external debug file using the build ID.
if let Some(path_debug) = object.build_id().and_then(locate_build_id) {
- if let Some(mapping) = Mapping::new_debug(path_debug, None) {
+ if let Some(mapping) = Mapping::new_debug(path, path_debug, None) {
return Some(Either::A(mapping));
}
}
// Try to locate an external debug file using the GNU debug link section.
if let Some((path_debug, crc)) = object.gnu_debuglink_path(path) {
- if let Some(mapping) = Mapping::new_debug(path_debug, Some(crc)) {
+ if let Some(mapping) = Mapping::new_debug(path, path_debug, Some(crc)) {
return Some(Either::A(mapping));
}
}
- Context::new(stash, object, None).map(Either::B)
+ let dwp = Mapping::load_dwarf_package(path, stash);
+
+ Context::new(stash, object, None, dwp).map(Either::B)
})
}
/// Load debuginfo from an external debug file.
- fn new_debug(path: PathBuf, crc: Option<u32>) -> Option<Mapping> {
+ fn new_debug(original_path: &Path, path: PathBuf, crc: Option<u32>) -> Option<Mapping> {
let map = super::mmap(&path)?;
Mapping::mk(map, |map, stash| {
let object = Object::parse(&map)?;
@@ -51,20 +54,45 @@ impl Mapping {
}
// Try to locate a supplementary object file.
+ let mut sup = None;
if let Some((path_sup, build_id_sup)) = object.gnu_debugaltlink_path(&path) {
if let Some(map_sup) = super::mmap(&path_sup) {
- let map_sup = stash.set_mmap_aux(map_sup);
- if let Some(sup) = Object::parse(map_sup) {
- if sup.build_id() == Some(build_id_sup) {
- return Context::new(stash, object, Some(sup));
+ let map_sup = stash.cache_mmap(map_sup);
+ if let Some(sup_) = Object::parse(map_sup) {
+ if sup_.build_id() == Some(build_id_sup) {
+ sup = Some(sup_);
}
}
}
}
- Context::new(stash, object, None)
+ let dwp = Mapping::load_dwarf_package(original_path, stash);
+
+ Context::new(stash, object, sup, dwp)
})
}
+
+ /// Try to locate a DWARF package file.
+ fn load_dwarf_package<'data>(path: &Path, stash: &'data Stash) -> Option<Object<'data>> {
+ let mut path_dwp = path.to_path_buf();
+ let dwp_extension = path
+ .extension()
+ .map(|previous_extension| {
+ let mut previous_extension = previous_extension.to_os_string();
+ previous_extension.push(".dwp");
+ previous_extension
+ })
+ .unwrap_or_else(|| "dwp".into());
+ path_dwp.set_extension(dwp_extension);
+ if let Some(map_dwp) = super::mmap(&path_dwp) {
+ let map_dwp = stash.cache_mmap(map_dwp);
+ if let Some(dwp_) = Object::parse(map_dwp) {
+ return Some(dwp_);
+ }
+ }
+
+ None
+ }
}
struct ParsedSym {
@@ -421,3 +449,47 @@ fn locate_debugaltlink(path: &Path, filename: &[u8], build_id: &[u8]) -> Option<
locate_build_id(build_id)
}
+
+fn convert_path<R: gimli::Reader>(r: &R) -> Result<PathBuf, gimli::Error> {
+ let bytes = r.to_slice()?;
+ Ok(PathBuf::from(OsStr::from_bytes(&bytes)))
+}
+
+pub(super) fn handle_split_dwarf<'data>(
+ package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
+ stash: &'data Stash,
+ load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
+) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
+ if let Some(dwp) = package.as_ref() {
+ if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) {
+ return Some(Arc::new(cu));
+ }
+ }
+
+ let mut path = PathBuf::new();
+ if let Some(p) = load.comp_dir.as_ref() {
+ path.push(convert_path(p).ok()?);
+ }
+
+ path.push(convert_path(load.path.as_ref()?).ok()?);
+
+ if let Some(map_dwo) = super::mmap(&path) {
+ let map_dwo = stash.cache_mmap(map_dwo);
+ if let Some(dwo) = Object::parse(map_dwo) {
+ return gimli::Dwarf::load(|id| -> Result<_, ()> {
+ let data = id
+ .dwo_name()
+ .and_then(|name| dwo.section(stash, name))
+ .unwrap_or(&[]);
+ Ok(EndianSlice::new(data, Endian))
+ })
+ .ok()
+ .map(|mut dwo_dwarf| {
+ dwo_dwarf.make_dwo(&load.parent);
+ Arc::new(dwo_dwarf)
+ });
+ }
+ }
+
+ None
+}