sentry_backtrace/
process.rs

1use std::borrow::Cow;
2
3use backtrace::Backtrace;
4use sentry_core::ClientOptions;
5
6use crate::trim::is_well_known_not_in_app;
7use crate::utils::{
8    demangle_symbol, filename, function_starts_with, parse_crate_name, strip_symbol,
9};
10use crate::{Frame, Stacktrace};
11
12/// Processes a `Stacktrace`.
13///
14/// Marks frames as in-app based on the provided `ClientOptions`.
15pub fn process_event_stacktrace(stacktrace: &mut Stacktrace, options: &ClientOptions) {
16    // automatically prime in_app and set package
17    let mut any_in_app = false;
18    for frame in &mut stacktrace.frames {
19        let func_name = match frame.function {
20            Some(ref func) => func,
21            None => continue,
22        };
23
24        // set package if missing to crate prefix
25        if frame.package.is_none() {
26            frame.package = parse_crate_name(func_name);
27        }
28
29        match frame.in_app {
30            Some(true) => {
31                any_in_app = true;
32                continue;
33            }
34            Some(false) => {
35                continue;
36            }
37            None => {}
38        }
39
40        for m in &options.in_app_include {
41            if function_starts_with(func_name, m) {
42                frame.in_app = Some(true);
43                any_in_app = true;
44                break;
45            }
46        }
47
48        if frame.in_app.is_some() {
49            continue;
50        }
51
52        for m in &options.in_app_exclude {
53            if function_starts_with(func_name, m) {
54                frame.in_app = Some(false);
55                break;
56            }
57        }
58
59        if frame.in_app.is_some() {
60            continue;
61        }
62
63        if is_well_known_not_in_app(func_name) {
64            frame.in_app = Some(false);
65        }
66    }
67
68    if !any_in_app {
69        for frame in &mut stacktrace.frames {
70            if frame.in_app.is_none() {
71                frame.in_app = Some(true);
72            }
73        }
74    }
75}
76
77/// Convert a `backtrace::Backtrace` into a Rust `Stacktrace`
78pub fn backtrace_to_stacktrace(bt: &Backtrace) -> Option<Stacktrace> {
79    let frames = bt
80        .frames()
81        .iter()
82        .flat_map(|frame| {
83            // For each frame, there may be multiple symbols if a function was inlined, so
84            // add an entry for each symbol.
85            let symbols = frame.symbols();
86            symbols
87                .iter()
88                .map(move |sym| {
89                    let abs_path = sym.filename().map(|m| m.to_string_lossy().to_string());
90                    let filename = abs_path.as_ref().map(|p| filename(p).to_string());
91                    let real_symbol = sym
92                        .name()
93                        .map_or(Cow::Borrowed("<unknown>"), |n| Cow::Owned(n.to_string()));
94                    let symbol = strip_symbol(&real_symbol);
95                    let function = demangle_symbol(&symbol);
96                    Frame {
97                        symbol: if symbol != function {
98                            Some(symbol.into())
99                        } else {
100                            None
101                        },
102                        function: Some(function),
103                        instruction_addr: Some(frame.ip().into()),
104                        abs_path,
105                        filename,
106                        lineno: sym.lineno().map(u64::from),
107                        colno: None,
108                        ..Default::default()
109                    }
110
111                    // If there were no symbols at all, make sure to add at least one frame, as we
112                    // may be able to symbolicate it on the server.
113                })
114                .chain(if symbols.is_empty() {
115                    Some(Frame {
116                        instruction_addr: Some(frame.ip().into()),
117                        function: Some("<unknown>".into()),
118                        ..Default::default()
119                    })
120                } else {
121                    None
122                })
123        })
124        .collect();
125    Stacktrace::from_frames_reversed(frames)
126}