use std::env;
use anyhow::bail;
use anyhow::Context as _;
use anyhow::Result;
use blazesym::symbolize::source::Elf;
use blazesym::symbolize::source::Source;
use blazesym::symbolize::CodeInfo;
use blazesym::symbolize::Input;
use blazesym::symbolize::Sym;
use blazesym::symbolize::Symbolized;
use blazesym::symbolize::Symbolizer;
use blazesym::Addr;
const ADDR_WIDTH: usize = 16;
fn print_frame(name: &str, addr_info: Option<(Addr, Addr, usize)>, code_info: Option<&CodeInfo>) {
let code_info = code_info.map(|code_info| {
let path = code_info.to_path();
let path = path.display();
match (code_info.line, code_info.column) {
(Some(line), Some(col)) => format!(" {path}:{line}:{col}"),
(Some(line), None) => format!(" {path}:{line}"),
(None, _) => format!(" {path}"),
}
});
if let Some((input_addr, addr, offset)) = addr_info {
println!(
"{input_addr:#0ADDR_WIDTH$x}: {name} @ {addr:#x}+{offset:#x}{code_info}",
code_info = code_info.as_deref().unwrap_or("")
)
} else {
println!(
"{:ADDR_WIDTH$} {name}{code_info} [inlined]",
" ",
code_info = code_info
.map(|info| format!(" @{info}"))
.as_deref()
.unwrap_or("")
)
}
}
fn main() -> Result<()> {
let args = env::args().collect::<Vec<_>>();
if args.len() != 3 {
bail!(
"Usage: {} <elf-path> <address>",
args.first().map(String::as_str).unwrap_or("addr2ln_pid")
);
}
let bin_name = &args[1];
let addr_str = &args[2][..];
let addr = Addr::from_str_radix(addr_str.trim_start_matches("0x"), 16)
.with_context(|| format!("failed to parse address: {addr_str}"))?;
let src = Source::Elf(Elf::new(bin_name));
let addrs = [addr];
let symbolizer = Symbolizer::new();
let syms = symbolizer
.symbolize(&src, Input::VirtOffset(&addrs))
.with_context(|| format!("failed to symbolize address {addr:#x}"))?;
for (input_addr, sym) in addrs.iter().copied().zip(syms) {
match sym {
Symbolized::Sym(Sym {
name,
addr,
offset,
code_info,
inlined,
..
}) => {
print_frame(
&name,
Some((input_addr, addr, offset)),
code_info.as_deref(),
);
for frame in inlined.iter() {
print_frame(&frame.name, None, frame.code_info.as_ref());
}
}
Symbolized::Unknown(..) => {
println!("{input_addr:#0ADDR_WIDTH$x}: <no-symbol>")
}
}
}
Ok(())
}