Skip to content

Commit

Permalink
Merge b165e26 into 3a2dbaf
Browse files Browse the repository at this point in the history
  • Loading branch information
khuey committed Jan 23, 2023
2 parents 3a2dbaf + b165e26 commit 53db48c
Show file tree
Hide file tree
Showing 9 changed files with 895 additions and 160 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Install rust
run: rustup update 1.42.0 && rustup default 1.42.0
run: rustup update 1.55.0 && rustup default 1.55.0
- name: Build
run: cargo build

Expand Down
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ readme = "./README.md"
repository = "https://github.com/gimli-rs/addr2line"

[dependencies]
gimli = { version = "0.27.0", default-features = false, features = ["read"] }
gimli = { version = "0.27.1", default-features = false, features = ["read"] }
fallible-iterator = { version = "0.2", default-features = false, optional = true }
memmap2 = { version = "0.5.5", optional = true }
object = { version = "0.30.0", default-features = false, features = ["read"], optional = true }
smallvec = { version = "1", default-features = false, optional = true }
rustc-demangle = { version = "0.1", optional = true }
Expand All @@ -25,7 +26,6 @@ alloc = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-all
compiler_builtins = { version = '0.1.2', optional = true }

[dev-dependencies]
memmap2 = "0.5.5"
clap = "3.1.6"
backtrace = "0.3.13"
findshlibs = "0.10"
Expand All @@ -41,7 +41,7 @@ debug = true
codegen-units = 1

[features]
default = ["rustc-demangle", "cpp_demangle", "std-object", "fallible-iterator", "smallvec"]
default = ["rustc-demangle", "cpp_demangle", "std-object", "fallible-iterator", "smallvec", "memmap2"]
std = ["gimli/std"]
std-object = ["std", "object", "object/std", "object/compression", "gimli/endian-reader"]

Expand All @@ -52,7 +52,7 @@ rustc-dep-of-std = ['core', 'alloc', 'compiler_builtins', 'gimli/rustc-dep-of-st
[[test]]
name = "output_equivalence"
harness = false
required-features = ["std-object"]
required-features = ["default"]

[[test]]
name = "correctness"
Expand All @@ -64,4 +64,4 @@ required-features = ["std-object"]

[[example]]
name = "addr2line"
required-features = ["std-object"]
required-features = ["default"]
13 changes: 7 additions & 6 deletions benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::env;
use std::fs::File;
use std::path::{self, PathBuf};

use addr2line::LookupResultExt;
use object::{Object, ObjectSection, ObjectSymbol};

fn release_fixture_path() -> PathBuf {
Expand Down Expand Up @@ -224,15 +225,15 @@ fn context_query_with_functions_rc(b: &mut test::Bencher) {
let ctx = addr2line::Context::new(file).unwrap();
// Ensure nothing is lazily loaded.
for addr in &addresses {
let mut frames = ctx.find_frames(*addr).unwrap();
let mut frames = ctx.find_frames(*addr).skip_all_loads().unwrap();
while let Ok(Some(ref frame)) = frames.next() {
test::black_box(frame);
}
}

b.iter(|| {
for addr in &addresses {
let mut frames = ctx.find_frames(*addr).unwrap();
let mut frames = ctx.find_frames(*addr).skip_all_loads().unwrap();
while let Ok(Some(ref frame)) = frames.next() {
test::black_box(frame);
}
Expand All @@ -253,15 +254,15 @@ fn context_query_with_functions_slice(b: &mut test::Bencher) {
let ctx = addr2line::Context::from_dwarf(dwarf).unwrap();
// Ensure nothing is lazily loaded.
for addr in &addresses {
let mut frames = ctx.find_frames(*addr).unwrap();
let mut frames = ctx.find_frames(*addr).skip_all_loads().unwrap();
while let Ok(Some(ref frame)) = frames.next() {
test::black_box(frame);
}
}

b.iter(|| {
for addr in &addresses {
let mut frames = ctx.find_frames(*addr).unwrap();
let mut frames = ctx.find_frames(*addr).skip_all_loads().unwrap();
while let Ok(Some(ref frame)) = frames.next() {
test::black_box(frame);
}
Expand Down Expand Up @@ -314,7 +315,7 @@ fn context_new_and_query_with_functions_rc(b: &mut test::Bencher) {
b.iter(|| {
let ctx = addr2line::Context::new(file).unwrap();
for addr in addresses.iter().take(100) {
let mut frames = ctx.find_frames(*addr).unwrap();
let mut frames = ctx.find_frames(*addr).skip_all_loads().unwrap();
while let Ok(Some(ref frame)) = frames.next() {
test::black_box(frame);
}
Expand All @@ -334,7 +335,7 @@ fn context_new_and_query_with_functions_slice(b: &mut test::Bencher) {
let dwarf = dwarf_borrow(&dwarf);
let ctx = addr2line::Context::from_dwarf(dwarf).unwrap();
for addr in addresses.iter().take(100) {
let mut frames = ctx.find_frames(*addr).unwrap();
let mut frames = ctx.find_frames(*addr).skip_all_loads().unwrap();
while let Ok(Some(ref frame)) = frames.next() {
test::black_box(frame);
}
Expand Down
15 changes: 12 additions & 3 deletions examples/addr2line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ extern crate typed_arena;
use std::borrow::Cow;
use std::fs::File;
use std::io::{BufRead, Lines, StdinLock, Write};
use std::path::Path;
use std::path::{Path, PathBuf};

use clap::{Arg, Command, Values};
use fallible_iterator::FallibleIterator;
use object::{Object, ObjectSection, SymbolMap, SymbolMapName};
use typed_arena::Arena;

use addr2line::{Context, Location};
use addr2line::{builtin_split_dwarf_loader, Context, Location};

fn parse_uint_from_hex_string(string: &str) -> Option<u64> {
if string.len() > 2 && string.starts_with("0x") {
Expand Down Expand Up @@ -201,6 +201,12 @@ fn main() {
dwarf.load_sup(&mut load_sup_section).unwrap();
}

let mut split_dwarf_loader = builtin_split_dwarf_loader::SplitDwarfLoader::new(
|data, endian| {
gimli::EndianSlice::new(arena_data.alloc(Cow::Owned(data.into_owned())), endian)
},
Some(PathBuf::from(path)),
);
let ctx = Context::from_dwarf(dwarf).unwrap();

let stdin = std::io::stdin();
Expand All @@ -227,7 +233,10 @@ fn main() {
if do_functions || do_inlines {
let mut printed_anything = false;
if let Some(probe) = probe {
let mut frames = ctx.find_frames(probe).unwrap().enumerate();
let mut frames = split_dwarf_loader
.run(ctx.find_frames(probe))
.unwrap()
.enumerate();
while let Some((i, frame)) = frames.next().unwrap() {
if pretty && i != 0 {
print!(" (inlined by) ");
Expand Down
132 changes: 132 additions & 0 deletions src/builtin_split_dwarf_loader.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use alloc::borrow::Cow;
use alloc::sync::Arc;
use std::fs::File;
use std::path::PathBuf;

use object::Object;

use crate::{LookupContinuation, LookupResult};

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::Break(output) => break output,
LookupResult::Continue(load) => load,
};

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 path = PathBuf::from(&load.dwo_name);
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);
}
}
}

0 comments on commit 53db48c

Please sign in to comment.