diff --git a/agb-addr2line/Cargo.toml b/agb-addr2line/Cargo.toml new file mode 100644 index 00000000..82cfffa7 --- /dev/null +++ b/agb-addr2line/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "agb-addr2line" +version = "0.19.1" +edition = "2021" +authors = ["Gwilym Inzani "] +license = "MPL-2.0" +description = "CLI utility to convert agb stack trace dumps into human readable stack traces" +repository = "https://github.com/agbrs/agb" + +[dependencies] +anyhow = "1" +clap = { version = "4", features = ["derive"] } +addr2line = "0.21" + +[profile.dev] +opt-level = 3 +debug = true + +[profile.release] +opt-level = 3 +lto = "fat" +debug = true diff --git a/agb-addr2line/src/main.rs b/agb-addr2line/src/main.rs new file mode 100644 index 00000000..4c5641a8 --- /dev/null +++ b/agb-addr2line/src/main.rs @@ -0,0 +1,43 @@ +use std::{fs, path::PathBuf, str::FromStr}; + +use addr2line::object; +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + /// The filename of the elf file + elf_path: PathBuf, + + /// The output of agb's dump + dump: String, +} + +fn main() -> anyhow::Result<()> { + let cli = Args::parse(); + + let file = fs::read(cli.elf_path)?; + let object = object::File::parse(file.as_slice())?; + + let ctx = addr2line::Context::new(&object)?; + + if let Some(location) = ctx.find_location(parse_address(&cli.dump)?)? { + let file = location.file.unwrap_or("unknown file"); + let line = location + .line + .map(|line| line.to_string()) + .unwrap_or_else(|| "??".to_owned()); + + println!("{file}:{line}"); + } + + Ok(()) +} + +fn parse_address(input: &str) -> Result::Err> { + if let Some(input) = input.strip_prefix("0x") { + u64::from_str_radix(input, 16) + } else { + input.parse() + } +}