Skip to content

Commit

Permalink
Add --all option to addr2line binary (#307)
Browse files Browse the repository at this point in the history
This displays line number information for all known addresses.
  • Loading branch information
philipc committed Jun 27, 2024
1 parent 8219b00 commit 6323487
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 22 deletions.
41 changes: 33 additions & 8 deletions src/bin/addr2line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf};

use clap::{Arg, ArgAction, Command};

use addr2line::{Loader, Location};
use addr2line::{Loader, LoaderReader, Location};

fn parse_uint_from_hex_string(string: &str) -> Option<u64> {
if string.len() > 2 && string.starts_with("0x") {
Expand All @@ -17,15 +17,28 @@ fn parse_uint_from_hex_string(string: &str) -> Option<u64> {
enum Addrs<'a> {
Args(clap::parser::ValuesRef<'a, String>),
Stdin(Lines<StdinLock<'a>>),
All {
iter: addr2line::LocationRangeIter<'a, LoaderReader<'a>>,
max: u64,
},
}

impl<'a> Iterator for Addrs<'a> {
type Item = Option<u64>;

fn next(&mut self) -> Option<Option<u64>> {
let text = match *self {
Addrs::Args(ref mut vals) => vals.next().map(Cow::from),
Addrs::Stdin(ref mut lines) => lines.next().map(Result::unwrap).map(Cow::from),
let text = match self {
Addrs::Args(vals) => vals.next().map(Cow::from),
Addrs::Stdin(lines) => lines.next().map(Result::unwrap).map(Cow::from),
Addrs::All { iter, max } => {
for (addr, _len, _loc) in iter {
if addr >= *max {
*max = addr + 1;
return Some(Some(addr));
}
}
return None;
}
};
text.as_ref()
.map(Cow::as_ref)
Expand Down Expand Up @@ -104,6 +117,11 @@ fn main() {
.value_name("filename")
.value_parser(clap::value_parser!(PathBuf))
.help("Path to supplementary object file."),
Arg::new("all")
.long("all")
.action(ArgAction::SetTrue)
.conflicts_with("addrs")
.help("Display all addresses that have line number information."),
Arg::new("functions")
.short('f')
.long("functions")
Expand Down Expand Up @@ -162,10 +180,17 @@ fn main() {
let ctx = Loader::new_with_sup(opts.exe, opts.sup).unwrap();

let stdin = std::io::stdin();
let addrs = matches
.get_many::<String>("addrs")
.map(Addrs::Args)
.unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()));
let addrs = if matches.get_flag("all") {
Addrs::All {
iter: ctx.find_location_range(0, !0).unwrap(),
max: 0,
}
} else {
matches
.get_many::<String>("addrs")
.map(Addrs::Args)
.unwrap_or_else(|| Addrs::Stdin(stdin.lock().lines()))
};

for probe in addrs {
if opts.print_addrs {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ mod line;
#[cfg(feature = "loader")]
mod loader;
#[cfg(feature = "loader")]
pub use loader::Loader;
pub use loader::{Loader, LoaderReader};

mod lookup;
pub use lookup::{LookupContinuation, LookupResult, SplitDwarfLoad};
Expand Down
31 changes: 18 additions & 13 deletions src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ use crate::{
SplitDwarfLoad,
};

type Reader<'a> = gimli::EndianSlice<'a, gimli::RunTimeEndian>;
/// The type used by [`Loader`] for reading DWARF data.
///
/// This is used in the return types of the methods of [`Loader`].
// TODO: use impl Trait when stable
pub type LoaderReader<'a> = gimli::EndianSlice<'a, gimli::RunTimeEndian>;

type Error = Box<dyn std::error::Error>;
type Result<T> = std::result::Result<T, Error>;

Expand Down Expand Up @@ -106,7 +111,7 @@ impl Loader {
&self,
probe_low: u64,
probe_high: u64,
) -> Result<LocationRangeIter<'_, Reader>> {
) -> Result<LocationRangeIter<'_, LoaderReader>> {
self.borrow_internal(|i, data, mmap| {
i.find_location_range(probe_low, probe_high, data, mmap)
})
Expand All @@ -116,7 +121,7 @@ impl Loader {
/// memory address.
///
/// This calls [`Context::find_frames`] with the given address.
pub fn find_frames(&self, probe: u64) -> Result<FrameIter<'_, Reader<'_>>> {
pub fn find_frames(&self, probe: u64) -> Result<FrameIter<'_, LoaderReader<'_>>> {
self.borrow_internal(|i, data, mmap| i.find_frames(probe, data, mmap))
}

Expand All @@ -127,10 +132,10 @@ impl Loader {
}

struct LoaderInternal<'a> {
ctx: Context<Reader<'a>>,
ctx: Context<LoaderReader<'a>>,
relative_address_base: u64,
symbols: SymbolMap<SymbolMapName<'a>>,
dwarf_package: Option<gimli::DwarfPackage<Reader<'a>>>,
dwarf_package: Option<gimli::DwarfPackage<LoaderReader<'a>>>,
// Map from address to Mach-O object file path.
object_map: object::ObjectMap<'a>,
// A context for each Mach-O object file.
Expand Down Expand Up @@ -251,7 +256,7 @@ impl<'a> LoaderInternal<'a> {
probe: u64,
arena_data: &'a Arena<Vec<u8>>,
arena_mmap: &'a Arena<Mmap>,
) -> (&Context<Reader<'a>>, u64) {
) -> (&Context<LoaderReader<'a>>, u64) {
self.object_ctx(probe, arena_data, arena_mmap)
.unwrap_or((&self.ctx, probe))
}
Expand All @@ -261,7 +266,7 @@ impl<'a> LoaderInternal<'a> {
probe: u64,
arena_data: &'a Arena<Vec<u8>>,
arena_mmap: &'a Arena<Mmap>,
) -> Option<(&Context<Reader<'a>>, u64)> {
) -> Option<(&Context<LoaderReader<'a>>, u64)> {
let symbol = self.object_map.get(probe)?;
let object_context = self.objects[symbol.object_index()]
.borrow_with(|| {
Expand Down Expand Up @@ -291,7 +296,7 @@ impl<'a> LoaderInternal<'a> {
probe_high: u64,
arena_data: &'a Arena<Vec<u8>>,
arena_mmap: &'a Arena<Mmap>,
) -> Result<LocationRangeIter<'a, Reader>> {
) -> Result<LocationRangeIter<'a, LoaderReader>> {
let (ctx, probe) = self.ctx(probe_low, arena_data, arena_mmap);
// TODO: handle ranges that cover multiple objects
let probe_high = probe + (probe_high - probe_low);
Expand All @@ -303,7 +308,7 @@ impl<'a> LoaderInternal<'a> {
probe: u64,
arena_data: &'a Arena<Vec<u8>>,
arena_mmap: &'a Arena<Mmap>,
) -> Result<FrameIter<'a, Reader>> {
) -> Result<FrameIter<'a, LoaderReader>> {
let (ctx, probe) = self.ctx(probe, arena_data, arena_mmap);
let mut frames = ctx.find_frames(probe);
loop {
Expand All @@ -319,10 +324,10 @@ impl<'a> LoaderInternal<'a> {

fn load_dwo(
&self,
load: SplitDwarfLoad<Reader<'a>>,
load: SplitDwarfLoad<LoaderReader<'a>>,
arena_data: &'a Arena<Vec<u8>>,
arena_mmap: &'a Arena<Mmap>,
) -> Result<Option<Arc<gimli::Dwarf<Reader<'a>>>>> {
) -> Result<Option<Arc<gimli::Dwarf<LoaderReader<'a>>>>> {
// Load the DWO file from the DWARF package, if available.
if let Some(dwp) = self.dwarf_package.as_ref() {
if let Some(cu) = dwp.find_cu(load.dwo_id, &load.parent)? {
Expand Down Expand Up @@ -366,7 +371,7 @@ impl<'a> LoaderInternal<'a> {
}

struct ObjectContext<'a> {
ctx: Context<Reader<'a>>,
ctx: Context<LoaderReader<'a>>,
symbols: SymbolMap<SymbolMapName<'a>>,
}

Expand Down Expand Up @@ -406,7 +411,7 @@ impl<'a> ObjectContext<'a> {
Some(ObjectContext { ctx, symbols })
}

fn ctx(&self, symbol_name: &[u8], probe: u64) -> Option<(&Context<Reader<'a>>, u64)> {
fn ctx(&self, symbol_name: &[u8], probe: u64) -> Option<(&Context<LoaderReader<'a>>, u64)> {
self.symbols
.symbols()
.iter()
Expand Down

0 comments on commit 6323487

Please sign in to comment.