backtrace/symbolize/
mod.rs

1use core::{fmt, str};
2
3cfg_if::cfg_if! {
4    if #[cfg(feature = "std")] {
5        use std::path::Path;
6        use std::prelude::v1::*;
7    }
8}
9
10use super::backtrace::Frame;
11use super::types::BytesOrWideString;
12use core::ffi::c_void;
13use rustc_demangle::{try_demangle, Demangle};
14
15/// Resolve an address to a symbol, passing the symbol to the specified
16/// closure.
17///
18/// This function will look up the given address in areas such as the local
19/// symbol table, dynamic symbol table, or DWARF debug info (depending on the
20/// activated implementation) to find symbols to yield.
21///
22/// The closure may not be called if resolution could not be performed, and it
23/// also may be called more than once in the case of inlined functions.
24///
25/// Symbols yielded represent the execution at the specified `addr`, returning
26/// file/line pairs for that address (if available).
27///
28/// Note that if you have a `Frame` then it's recommended to use the
29/// `resolve_frame` function instead of this one.
30///
31/// # Required features
32///
33/// This function requires the `std` feature of the `backtrace` crate to be
34/// enabled, and the `std` feature is enabled by default.
35///
36/// # Panics
37///
38/// This function strives to never panic, but if the `cb` provided panics then
39/// some platforms will force a double panic to abort the process. Some
40/// platforms use a C library which internally uses callbacks which cannot be
41/// unwound through, so panicking from `cb` may trigger a process abort.
42///
43/// # Example
44///
45/// ```
46/// extern crate backtrace;
47///
48/// fn main() {
49///     backtrace::trace(|frame| {
50///         let ip = frame.ip();
51///
52///         backtrace::resolve(ip, |symbol| {
53///             // ...
54///         });
55///
56///         false // only look at the top frame
57///     });
58/// }
59/// ```
60#[cfg(feature = "std")]
61pub fn resolve<F: FnMut(&Symbol)>(addr: *mut c_void, cb: F) {
62    let _guard = crate::lock::lock();
63    unsafe { resolve_unsynchronized(addr, cb) }
64}
65
66/// Resolve a previously capture frame to a symbol, passing the symbol to the
67/// specified closure.
68///
69/// This function performs the same function as `resolve` except that it takes a
70/// `Frame` as an argument instead of an address. This can allow some platform
71/// implementations of backtracing to provide more accurate symbol information
72/// or information about inline frames for example. It's recommended to use this
73/// if you can.
74///
75/// # Required features
76///
77/// This function requires the `std` feature of the `backtrace` crate to be
78/// enabled, and the `std` feature is enabled by default.
79///
80/// # Panics
81///
82/// This function strives to never panic, but if the `cb` provided panics then
83/// some platforms will force a double panic to abort the process. Some
84/// platforms use a C library which internally uses callbacks which cannot be
85/// unwound through, so panicking from `cb` may trigger a process abort.
86///
87/// # Example
88///
89/// ```
90/// extern crate backtrace;
91///
92/// fn main() {
93///     backtrace::trace(|frame| {
94///         backtrace::resolve_frame(frame, |symbol| {
95///             // ...
96///         });
97///
98///         false // only look at the top frame
99///     });
100/// }
101/// ```
102#[cfg(feature = "std")]
103pub fn resolve_frame<F: FnMut(&Symbol)>(frame: &Frame, cb: F) {
104    let _guard = crate::lock::lock();
105    unsafe { resolve_frame_unsynchronized(frame, cb) }
106}
107
108pub enum ResolveWhat<'a> {
109    Address(*mut c_void),
110    Frame(&'a Frame),
111}
112
113impl<'a> ResolveWhat<'a> {
114    #[allow(dead_code)]
115    fn address_or_ip(&self) -> *mut c_void {
116        match self {
117            ResolveWhat::Address(a) => adjust_ip(*a),
118            ResolveWhat::Frame(f) => adjust_ip(f.ip()),
119        }
120    }
121}
122
123// IP values from stack frames are typically (always?) the instruction
124// *after* the call that's the actual stack trace. Symbolizing this on
125// causes the filename/line number to be one ahead and perhaps into
126// the void if it's near the end of the function.
127//
128// This appears to basically always be the case on all platforms, so we always
129// subtract one from a resolved ip to resolve it to the previous call
130// instruction instead of the instruction being returned to.
131//
132// Ideally we would not do this. Ideally we would require callers of the
133// `resolve` APIs here to manually do the -1 and account that they want location
134// information for the *previous* instruction, not the current. Ideally we'd
135// also expose on `Frame` if we are indeed the address of the next instruction
136// or the current.
137//
138// For now though this is a pretty niche concern so we just internally always
139// subtract one. Consumers should keep working and getting pretty good results,
140// so we should be good enough.
141fn adjust_ip(a: *mut c_void) -> *mut c_void {
142    if a.is_null() {
143        a
144    } else {
145        (a as usize - 1) as *mut c_void
146    }
147}
148
149/// Same as `resolve`, only unsafe as it's unsynchronized.
150///
151/// This function does not have synchronization guarantees but is available when
152/// the `std` feature of this crate isn't compiled in. See the `resolve`
153/// function for more documentation and examples.
154///
155/// # Panics
156///
157/// See information on `resolve` for caveats on `cb` panicking.
158pub unsafe fn resolve_unsynchronized<F>(addr: *mut c_void, mut cb: F)
159where
160    F: FnMut(&Symbol),
161{
162    imp::resolve(ResolveWhat::Address(addr), &mut cb)
163}
164
165/// Same as `resolve_frame`, only unsafe as it's unsynchronized.
166///
167/// This function does not have synchronization guarantees but is available
168/// when the `std` feature of this crate isn't compiled in. See the
169/// `resolve_frame` function for more documentation and examples.
170///
171/// # Panics
172///
173/// See information on `resolve_frame` for caveats on `cb` panicking.
174pub unsafe fn resolve_frame_unsynchronized<F>(frame: &Frame, mut cb: F)
175where
176    F: FnMut(&Symbol),
177{
178    imp::resolve(ResolveWhat::Frame(frame), &mut cb)
179}
180
181/// A trait representing the resolution of a symbol in a file.
182///
183/// This trait is yielded as a trait object to the closure given to the
184/// `backtrace::resolve` function, and it is virtually dispatched as it's
185/// unknown which implementation is behind it.
186///
187/// A symbol can give contextual information about a function, for example the
188/// name, filename, line number, precise address, etc. Not all information is
189/// always available in a symbol, however, so all methods return an `Option`.
190pub struct Symbol {
191    // TODO: this lifetime bound needs to be persisted eventually to `Symbol`,
192    // but that's currently a breaking change. For now this is safe since
193    // `Symbol` is only ever handed out by reference and can't be cloned.
194    inner: imp::Symbol<'static>,
195}
196
197impl Symbol {
198    /// Returns the name of this function.
199    ///
200    /// The returned structure can be used to query various properties about the
201    /// symbol name:
202    ///
203    /// * The `Display` implementation will print out the demangled symbol.
204    /// * The raw `str` value of the symbol can be accessed (if it's valid
205    ///   utf-8).
206    /// * The raw bytes for the symbol name can be accessed.
207    pub fn name(&self) -> Option<SymbolName<'_>> {
208        self.inner.name()
209    }
210
211    /// Returns the starting address of this function.
212    pub fn addr(&self) -> Option<*mut c_void> {
213        self.inner.addr()
214    }
215
216    /// Returns the raw filename as a slice. This is mainly useful for `no_std`
217    /// environments.
218    pub fn filename_raw(&self) -> Option<BytesOrWideString<'_>> {
219        self.inner.filename_raw()
220    }
221
222    /// Returns the column number for where this symbol is currently executing.
223    ///
224    /// Only gimli currently provides a value here and even then only if `filename`
225    /// returns `Some`, and so it is then consequently subject to similar caveats.
226    pub fn colno(&self) -> Option<u32> {
227        self.inner.colno()
228    }
229
230    /// Returns the line number for where this symbol is currently executing.
231    ///
232    /// This return value is typically `Some` if `filename` returns `Some`, and
233    /// is consequently subject to similar caveats.
234    pub fn lineno(&self) -> Option<u32> {
235        self.inner.lineno()
236    }
237
238    /// Returns the file name where this function was defined.
239    ///
240    /// This is currently only available when libbacktrace or gimli is being
241    /// used (e.g. unix platforms other) and when a binary is compiled with
242    /// debuginfo. If neither of these conditions is met then this will likely
243    /// return `None`.
244    ///
245    /// # Required features
246    ///
247    /// This function requires the `std` feature of the `backtrace` crate to be
248    /// enabled, and the `std` feature is enabled by default.
249    #[cfg(feature = "std")]
250    #[allow(unreachable_code)]
251    pub fn filename(&self) -> Option<&Path> {
252        self.inner.filename()
253    }
254}
255
256impl fmt::Debug for Symbol {
257    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258        let mut d = f.debug_struct("Symbol");
259        if let Some(name) = self.name() {
260            d.field("name", &name);
261        }
262        if let Some(addr) = self.addr() {
263            d.field("addr", &addr);
264        }
265
266        #[cfg(feature = "std")]
267        {
268            if let Some(filename) = self.filename() {
269                d.field("filename", &filename);
270            }
271        }
272
273        if let Some(lineno) = self.lineno() {
274            d.field("lineno", &lineno);
275        }
276        d.finish()
277    }
278}
279
280cfg_if::cfg_if! {
281    if #[cfg(feature = "cpp_demangle")] {
282        // Maybe a parsed C++ symbol, if parsing the mangled symbol as Rust
283        // failed.
284        struct OptionCppSymbol<'a>(Option<::cpp_demangle::BorrowedSymbol<'a>>);
285
286        impl<'a> OptionCppSymbol<'a> {
287            fn parse(input: &'a [u8]) -> OptionCppSymbol<'a> {
288                OptionCppSymbol(::cpp_demangle::BorrowedSymbol::new(input).ok())
289            }
290
291            fn none() -> OptionCppSymbol<'a> {
292                OptionCppSymbol(None)
293            }
294        }
295    }
296}
297
298/// A wrapper around a symbol name to provide ergonomic accessors to the
299/// demangled name, the raw bytes, the raw string, etc.
300pub struct SymbolName<'a> {
301    bytes: &'a [u8],
302    demangled: Option<Demangle<'a>>,
303    #[cfg(feature = "cpp_demangle")]
304    cpp_demangled: OptionCppSymbol<'a>,
305}
306
307impl<'a> SymbolName<'a> {
308    /// Creates a new symbol name from the raw underlying bytes.
309    pub fn new(bytes: &'a [u8]) -> SymbolName<'a> {
310        let str_bytes = str::from_utf8(bytes).ok();
311        let demangled = str_bytes.and_then(|s| try_demangle(s).ok());
312
313        #[cfg(feature = "cpp_demangle")]
314        let cpp = if demangled.is_none() {
315            OptionCppSymbol::parse(bytes)
316        } else {
317            OptionCppSymbol::none()
318        };
319
320        SymbolName {
321            bytes,
322            demangled,
323            #[cfg(feature = "cpp_demangle")]
324            cpp_demangled: cpp,
325        }
326    }
327
328    /// Returns the raw (mangled) symbol name as a `str` if the symbol is valid utf-8.
329    ///
330    /// Use the `Display` implementation if you want the demangled version.
331    pub fn as_str(&self) -> Option<&'a str> {
332        self.demangled
333            .as_ref()
334            .map(|s| s.as_str())
335            .or_else(|| str::from_utf8(self.bytes).ok())
336    }
337
338    /// Returns the raw symbol name as a list of bytes
339    pub fn as_bytes(&self) -> &'a [u8] {
340        self.bytes
341    }
342}
343
344fn format_symbol_name(
345    fmt: fn(&str, &mut fmt::Formatter<'_>) -> fmt::Result,
346    mut bytes: &[u8],
347    f: &mut fmt::Formatter<'_>,
348) -> fmt::Result {
349    while bytes.len() > 0 {
350        match str::from_utf8(bytes) {
351            Ok(name) => {
352                fmt(name, f)?;
353                break;
354            }
355            Err(err) => {
356                fmt("\u{FFFD}", f)?;
357
358                match err.error_len() {
359                    Some(len) => bytes = &bytes[err.valid_up_to() + len..],
360                    None => break,
361                }
362            }
363        }
364    }
365    Ok(())
366}
367
368impl<'a> fmt::Display for SymbolName<'a> {
369    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370        if let Some(ref s) = self.demangled {
371            return s.fmt(f);
372        }
373
374        #[cfg(feature = "cpp_demangle")]
375        {
376            if let Some(ref cpp) = self.cpp_demangled.0 {
377                return cpp.fmt(f);
378            }
379        }
380
381        format_symbol_name(fmt::Display::fmt, self.bytes, f)
382    }
383}
384
385impl<'a> fmt::Debug for SymbolName<'a> {
386    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387        if let Some(ref s) = self.demangled {
388            return s.fmt(f);
389        }
390
391        #[cfg(all(feature = "std", feature = "cpp_demangle"))]
392        {
393            use std::fmt::Write;
394
395            // This may to print if the demangled symbol isn't actually
396            // valid, so handle the error here gracefully by not propagating
397            // it outwards.
398            if let Some(ref cpp) = self.cpp_demangled.0 {
399                let mut s = String::new();
400                if write!(s, "{cpp}").is_ok() {
401                    return s.fmt(f);
402                }
403            }
404        }
405
406        format_symbol_name(fmt::Debug::fmt, self.bytes, f)
407    }
408}
409
410/// Attempt to reclaim that cached memory used to symbolicate addresses.
411///
412/// This method will attempt to release any global data structures that have
413/// otherwise been cached globally or in the thread which typically represent
414/// parsed DWARF information or similar.
415///
416/// # Caveats
417///
418/// While this function is always available it doesn't actually do anything on
419/// most implementations. Libraries like dbghelp or libbacktrace do not provide
420/// facilities to deallocate state and manage the allocated memory. For now the
421/// `std` feature of this crate is the only feature where this
422/// function has any effect.
423#[cfg(feature = "std")]
424pub fn clear_symbol_cache() {
425    let _guard = crate::lock::lock();
426    unsafe {
427        imp::clear_symbol_cache();
428    }
429}
430
431cfg_if::cfg_if! {
432    if #[cfg(miri)] {
433        mod miri;
434        use miri as imp;
435    } else if #[cfg(all(windows, target_env = "msvc", not(target_vendor = "uwp")))] {
436        mod dbghelp;
437        use dbghelp as imp;
438    } else if #[cfg(all(
439        any(unix, all(windows, target_env = "gnu")),
440        not(target_vendor = "uwp"),
441        not(target_os = "emscripten"),
442        any(not(backtrace_in_libstd), feature = "backtrace"),
443    ))] {
444        mod gimli;
445        use gimli as imp;
446    } else {
447        mod noop;
448        use noop as imp;
449    }
450}