ckb_sentry_backtrace/
parse.rs

1use regex::Regex;
2
3use crate::utils::{demangle_symbol, filename, strip_symbol};
4use crate::{Frame, Stacktrace};
5
6lazy_static::lazy_static! {
7    static ref FRAME_RE: Regex = Regex::new(r#"(?xm)
8        ^
9            \s*(?:\d+:)?\s*                      # frame number (missing for inline)
10
11            (?:
12                (?P<addr_old>0x[a-f0-9]+)        # old style address prefix
13                \s-\s
14            )?
15
16            (?P<symbol>[^\r\n\(]+)               # symbol name
17
18            (?:
19                \s\((?P<addr_new>0x[a-f0-9]+)\)  # new style address in parens
20            )?
21
22            (?:
23                \r?\n
24                \s+at\s                          # padded "at" in new line
25                (?P<path>[^\r\n]+?)              # path to source file
26                (?::(?P<lineno>\d+))?            # optional source line
27            )?
28        $
29    "#).unwrap();
30}
31
32/// Parses a backtrace string into a Sentry `Stacktrace`.
33pub fn parse_stacktrace(bt: &str) -> Option<Stacktrace> {
34    let mut last_address = None;
35
36    let frames = FRAME_RE
37        .captures_iter(&bt)
38        .map(|captures| {
39            let abs_path = captures.name("path").map(|m| m.as_str().to_string());
40            let filename = abs_path.as_ref().map(|p| filename(p).to_string());
41            let real_symbol = captures["symbol"].to_string();
42            let symbol = strip_symbol(&real_symbol);
43            let function = demangle_symbol(symbol);
44
45            // Obtain the instruction address. A missing address usually indicates an inlined stack
46            // frame, in which case the previous address needs to be used.
47            last_address = captures
48                .name("addr_new")
49                .or_else(|| captures.name("addr_old"))
50                .and_then(|m| m.as_str().parse().ok())
51                .or(last_address);
52
53            Frame {
54                symbol: if symbol != function {
55                    Some(symbol.into())
56                } else {
57                    None
58                },
59                function: Some(function),
60                instruction_addr: last_address,
61                abs_path,
62                filename,
63                lineno: captures
64                    .name("lineno")
65                    .map(|x| x.as_str().parse::<u64>().unwrap()),
66                ..Default::default()
67            }
68        })
69        .collect();
70
71    Stacktrace::from_frames_reversed(frames)
72}