aboutsummaryrefslogtreecommitdiff
path: root/vendor/addr2line/src/builtin_split_dwarf_loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/addr2line/src/builtin_split_dwarf_loader.rs')
-rw-r--r--vendor/addr2line/src/builtin_split_dwarf_loader.rs164
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);
+ }
+ }
+}