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; }
87
88 if path.ends_with("panicking.rs") {
89 return false; }
91
92 true
93}