diff options
Diffstat (limited to 'vendor/addr2line/src/builtin_split_dwarf_loader.rs')
-rw-r--r-- | vendor/addr2line/src/builtin_split_dwarf_loader.rs | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/vendor/addr2line/src/builtin_split_dwarf_loader.rs b/vendor/addr2line/src/builtin_split_dwarf_loader.rs new file mode 100644 index 0000000..4711931 --- /dev/null +++ b/vendor/addr2line/src/builtin_split_dwarf_loader.rs @@ -0,0 +1,164 @@ +use alloc::borrow::Cow; +use alloc::sync::Arc; +use std::fs::File; +use std::path::PathBuf; + +use object::Object; + +use crate::{LookupContinuation, LookupResult}; + +#[cfg(unix)] +fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>( + r: &R, +) -> Result<PathBuf, gimli::Error> { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + let bytes = r.to_slice()?; + let s = OsStr::from_bytes(&bytes); + Ok(PathBuf::from(s)) +} + +#[cfg(not(unix))] +fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>( + r: &R, +) -> Result<PathBuf, gimli::Error> { + let bytes = r.to_slice()?; + let s = std::str::from_utf8(&bytes).map_err(|_| gimli::Error::BadUtf8)?; + Ok(PathBuf::from(s)) +} + +fn load_section<'data: 'file, 'file, O, R, F>( + id: gimli::SectionId, + file: &'file O, + endian: R::Endian, + loader: &mut F, +) -> Result<R, gimli::Error> +where + O: object::Object<'data, 'file>, + R: gimli::Reader<Endian = gimli::RunTimeEndian>, + F: FnMut(Cow<'data, [u8]>, R::Endian) -> R, +{ + use object::ObjectSection; + + let data = id + .dwo_name() + .and_then(|dwo_name| { + file.section_by_name(dwo_name) + .and_then(|section| section.uncompressed_data().ok()) + }) + .unwrap_or(Cow::Borrowed(&[])); + Ok(loader(data, endian)) +} + +/// A simple builtin split DWARF loader. +pub struct SplitDwarfLoader<R, F> +where + R: gimli::Reader<Endian = gimli::RunTimeEndian>, + F: FnMut(Cow<'_, [u8]>, R::Endian) -> R, +{ + loader: F, + dwarf_package: Option<gimli::DwarfPackage<R>>, +} + +impl<R, F> SplitDwarfLoader<R, F> +where + R: gimli::Reader<Endian = gimli::RunTimeEndian>, + F: FnMut(Cow<'_, [u8]>, R::Endian) -> R, +{ + fn load_dwarf_package(loader: &mut F, path: Option<PathBuf>) -> Option<gimli::DwarfPackage<R>> { + let mut path = path.map(Ok).unwrap_or_else(std::env::current_exe).ok()?; + 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.set_extension(dwp_extension); + let file = File::open(&path).ok()?; + let map = unsafe { memmap2::Mmap::map(&file).ok()? }; + let dwp = object::File::parse(&*map).ok()?; + + let endian = if dwp.is_little_endian() { + gimli::RunTimeEndian::Little + } else { + gimli::RunTimeEndian::Big + }; + + let empty = loader(Cow::Borrowed(&[]), endian); + gimli::DwarfPackage::load( + |section_id| load_section(section_id, &dwp, endian, loader), + empty, + ) + .ok() + } + + /// Create a new split DWARF loader. + pub fn new(mut loader: F, path: Option<PathBuf>) -> SplitDwarfLoader<R, F> { + let dwarf_package = SplitDwarfLoader::load_dwarf_package(&mut loader, path); + SplitDwarfLoader { + loader, + dwarf_package, + } + } + + /// Run the provided `LookupResult` to completion, loading any necessary + /// split DWARF along the way. + pub fn run<L>(&mut self, mut l: LookupResult<L>) -> L::Output + where + L: LookupContinuation<Buf = R>, + { + loop { + let (load, continuation) = match l { + LookupResult::Output(output) => break output, + LookupResult::Load { load, continuation } => (load, continuation), + }; + + let mut r: Option<Arc<gimli::Dwarf<_>>> = None; + if let Some(dwp) = self.dwarf_package.as_ref() { + if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) { + r = Some(Arc::new(cu)); + } + } + + if r.is_none() { + let mut path = PathBuf::new(); + if let Some(p) = load.comp_dir.as_ref() { + if let Ok(p) = convert_path(p) { + path.push(p); + } + } + + if let Some(p) = load.path.as_ref() { + if let Ok(p) = convert_path(p) { + path.push(p); + } + } + + if let Ok(file) = File::open(&path) { + if let Ok(map) = unsafe { memmap2::Mmap::map(&file) } { + if let Ok(file) = object::File::parse(&*map) { + let endian = if file.is_little_endian() { + gimli::RunTimeEndian::Little + } else { + gimli::RunTimeEndian::Big + }; + + r = gimli::Dwarf::load(|id| { + load_section(id, &file, endian, &mut self.loader) + }) + .ok() + .map(|mut dwo_dwarf| { + dwo_dwarf.make_dwo(&load.parent); + Arc::new(dwo_dwarf) + }); + } + } + } + } + + l = continuation.resume(r); + } + } +} |