agb_debug/
lib.rs

1mod gwilym_encoding;
2mod load_dwarf;
3
4use addr2line::gimli;
5pub use gwilym_encoding::{GwilymDecodeError, gwilym_decode};
6pub use load_dwarf::{GimliDwarf, LoadDwarfError, load_dwarf};
7use thiserror::Error;
8
9pub use addr2line;
10
11pub struct AddressInfo {
12    pub location: Location,
13    pub is_interesting: bool,
14    pub is_inline: bool,
15    pub function: String,
16}
17
18#[derive(Debug, Error)]
19pub enum AddressInfoError {
20    #[error(transparent)]
21    Gimli(#[from] gimli::Error),
22}
23
24pub struct Location {
25    pub filename: String,
26    pub line: u32,
27    pub col: u32,
28}
29
30pub type Addr2LineContext = addr2line::Context<gimli::EndianRcSlice<gimli::RunTimeEndian>>;
31
32impl Default for Location {
33    fn default() -> Self {
34        Self {
35            filename: "??".to_string(),
36            line: 0,
37            col: 0,
38        }
39    }
40}
41
42pub fn address_info(
43    ctx: &Addr2LineContext,
44    address: u64,
45) -> Result<Vec<AddressInfo>, AddressInfoError> {
46    let mut frames = ctx.find_frames(address).skip_all_loads()?;
47
48    let mut is_first = true;
49
50    let mut infos = Vec::new();
51
52    while let Some(frame) = frames.next()? {
53        let function_name = if let Some(ref func) = frame.function {
54            func.demangle()?.into_owned()
55        } else {
56            "unknown function".to_string()
57        };
58
59        let location = frame
60            .location
61            .as_ref()
62            .map(|location| Location {
63                filename: location.file.unwrap_or("??").to_owned(),
64                line: location.line.unwrap_or(0),
65                col: location.column.unwrap_or(0),
66            })
67            .unwrap_or_default();
68
69        let is_interesting = is_interesting_function(&function_name, &location.filename);
70
71        infos.push(AddressInfo {
72            location,
73            is_interesting,
74            is_inline: !is_first,
75            function: function_name,
76        });
77        is_first = false;
78    }
79
80    Ok(infos)
81}
82
83fn is_interesting_function(function_name: &str, path: &str) -> bool {
84    if function_name == "rust_begin_unwind" {
85        return false; // this is the unwind exception call
86    }
87
88    if path.ends_with("panicking.rs") {
89        return false; // probably part of rust's internal panic mechanisms
90    }
91
92    true
93}