agb/agb-addr2line/src/main.rs

105 lines
2.4 KiB
Rust
Raw Normal View History

2024-04-01 14:22:41 +01:00
use std::{borrow::Cow, fs, path::PathBuf};
2024-04-01 13:26:48 +01:00
2024-04-01 14:05:22 +01:00
use addr2line::{gimli, object};
2024-04-01 13:26:48 +01:00
use clap::Parser;
2024-04-01 14:10:23 +01:00
use colored::Colorize;
2024-04-01 13:26:48 +01:00
#[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,
}
2024-04-01 13:43:08 +01:00
struct Location {
filename: String,
line: u32,
}
impl Default for Location {
fn default() -> Self {
Self {
filename: "??".to_string(),
line: 0,
}
}
}
2024-04-01 13:26:48 +01:00
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)?;
2024-04-01 14:16:13 +01:00
for (i, address) in cli.dump.split('-').enumerate() {
2024-04-01 14:05:22 +01:00
let mut address = u64::from_str_radix(address, 16)?;
if address <= 0xFFFF {
address += 0x0800_0000;
}
2024-04-01 14:16:13 +01:00
print_address(&ctx, i, address)?;
2024-04-01 14:05:22 +01:00
}
Ok(())
}
2024-04-01 14:16:13 +01:00
fn print_address(
ctx: &addr2line::Context<impl gimli::Reader>,
index: usize,
address: u64,
) -> anyhow::Result<()> {
2024-04-01 14:05:22 +01:00
let mut frames = ctx.find_frames(address).skip_all_loads()?;
2024-04-01 13:43:08 +01:00
2024-04-01 14:16:13 +01:00
let mut is_first = true;
2024-04-01 13:43:08 +01:00
while let Some(frame) = frames.next()? {
let function_name = if let Some(func) = frame.function {
func.demangle()?.into_owned()
} else {
"unknown function".to_string()
};
let location = frame
.location
.map(|location| Location {
filename: location.file.unwrap_or("??").to_owned(),
line: location.line.unwrap_or(0),
})
.unwrap_or_default();
2024-04-01 13:26:48 +01:00
2024-04-01 14:16:13 +01:00
if is_first {
2024-04-01 14:22:41 +01:00
print!("{index}:\t{}", function_name.bold());
2024-04-01 14:16:13 +01:00
} else {
2024-04-01 14:22:41 +01:00
print!("\t(inlined by) {function_name}");
2024-04-01 14:16:13 +01:00
}
2024-04-01 14:10:23 +01:00
println!(
2024-04-01 14:22:41 +01:00
" {}:{}",
prettify_path(&location.filename).green(),
2024-04-01 14:10:23 +01:00
location.line.to_string().green()
);
2024-04-01 14:16:13 +01:00
is_first = false;
2024-04-01 13:26:48 +01:00
}
Ok(())
}
2024-04-01 14:22:41 +01:00
fn prettify_path(path: &str) -> Cow<'_, str> {
if let Some(src_index) = path.rfind("/src/") {
let crate_name_start = path[0..src_index].rfind('/');
let crate_name = crate_name_start
.map(|crate_name_start| &path[crate_name_start + 1..src_index])
.unwrap_or("<crate>");
Cow::Owned(format!("<{crate_name}>/{}", &path[src_index + 5..]))
} else {
Cow::Borrowed(path)
}
}