ckb_sentry_backtrace/
parse.rs1use 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
32pub 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 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}