backtrace/
lib.rs

1//! A library for acquiring a backtrace at runtime
2//!
3//! This library is meant to supplement the `RUST_BACKTRACE=1` support of the
4//! standard library by allowing an acquisition of a backtrace at runtime
5//! programmatically. The backtraces generated by this library do not need to be
6//! parsed, for example, and expose the functionality of multiple backend
7//! implementations.
8//!
9//! # Usage
10//!
11//! First, add this to your Cargo.toml
12//!
13//! ```toml
14//! [dependencies]
15//! pprof-backtrace = "0.3"
16//! ```
17//!
18//! Next:
19//!
20//! ```
21//! fn main() {
22//! # // Unsafe here so test passes on no_std.
23//! # #[cfg(feature = "std")] {
24//!     backtrace::trace(|frame| {
25//!         let ip = frame.ip();
26//!         let symbol_address = frame.symbol_address();
27//!
28//!         // Resolve this instruction pointer to a symbol name
29//!         backtrace::resolve_frame(frame, |symbol| {
30//!             if let Some(name) = symbol.name() {
31//!                 // ...
32//!             }
33//!             if let Some(filename) = symbol.filename() {
34//!                 // ...
35//!             }
36//!         });
37//!
38//!         true // keep going to the next frame
39//!     });
40//! }
41//! # }
42//! ```
43//!
44//! # Backtrace accuracy
45//!
46//! This crate implements best-effort attempts to get the native backtrace. This
47//! is not always guaranteed to work, and some platforms don't return any
48//! backtrace at all. If your application requires accurate backtraces then it's
49//! recommended to closely evaluate this crate to see whether it's suitable
50//! for your use case on your target platforms.
51//!
52//! Even on supported platforms, there's a number of reasons that backtraces may
53//! be less-than-accurate, including but not limited to:
54//!
55//! * Unwind information may not be available. This crate primarily implements
56//!   backtraces by unwinding the stack, but not all functions may have
57//!   unwinding information (e.g. DWARF unwinding information).
58//!
59//! * Rust code may be compiled without unwinding information for some
60//!   functions. This can also happen for Rust code compiled with
61//!   `-Cpanic=abort`. You can remedy this, however, with
62//!   `-Cforce-unwind-tables` as a compiler option.
63//!
64//! * Unwind information may be inaccurate or corrupt. In the worst case
65//!   inaccurate unwind information can lead this library to segfault. In the
66//!   best case inaccurate information will result in a truncated stack trace.
67//!
68//! * Backtraces may not report filenames/line numbers correctly due to missing
69//!   or corrupt debug information. This won't lead to segfaults unlike corrupt
70//!   unwinding information, but missing or malformed debug information will
71//!   mean that filenames and line numbers will not be available. This may be
72//!   because debug information wasn't generated by the compiler, or it's just
73//!   missing on the filesystem.
74//!
75//! * Not all platforms are supported. For example there's no way to get a
76//!   backtrace on WebAssembly at the moment.
77//!
78//! * Crate features may be disabled. Currently this crate supports using Gimli
79//!   libbacktrace on non-Windows platforms for reading debuginfo for
80//!   backtraces. If both crate features are disabled, however, then these
81//!   platforms will generate a backtrace but be unable to generate symbols for
82//!   it.
83//!
84//! In most standard workflows for most standard platforms you generally don't
85//! need to worry about these caveats. We'll try to fix ones where we can over
86//! time, but otherwise it's important to be aware of the limitations of
87//! unwinding-based backtraces!
88
89#![doc(html_root_url = "https://docs.rs/backtrace")]
90#![deny(missing_docs)]
91#![no_std]
92#![cfg_attr(
93    all(feature = "std", target_env = "sgx", target_vendor = "fortanix"),
94    feature(sgx_platform)
95)]
96#![warn(rust_2018_idioms)]
97// When we're building as part of libstd, silence all warnings since they're
98// irrelevant as this crate is developed out-of-tree.
99#![cfg_attr(backtrace_in_libstd, allow(warnings))]
100#![cfg_attr(not(feature = "std"), allow(dead_code))]
101// We know this is deprecated, it's only here for back-compat reasons.
102#![cfg_attr(feature = "rustc-serialize", allow(deprecated))]
103
104#[cfg(feature = "std")]
105#[macro_use]
106extern crate std;
107
108// This is only used for gimli right now, which is only used on some platforms,
109// so don't worry if it's unused in other configurations.
110#[allow(unused_extern_crates)]
111extern crate alloc;
112
113pub use self::backtrace::{trace_unsynchronized, Frame};
114mod backtrace;
115
116pub use self::symbolize::resolve_frame_unsynchronized;
117pub use self::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
118mod symbolize;
119
120pub use self::types::BytesOrWideString;
121mod types;
122
123#[cfg(feature = "std")]
124pub use self::symbolize::clear_symbol_cache;
125
126mod print;
127pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};
128
129cfg_if::cfg_if! {
130    if #[cfg(feature = "std")] {
131        pub use self::backtrace::trace;
132        pub use self::symbolize::{resolve, resolve_frame};
133        pub use self::capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
134        mod capture;
135    }
136}
137
138#[allow(dead_code)]
139struct Bomb {
140    enabled: bool,
141}
142
143#[allow(dead_code)]
144impl Drop for Bomb {
145    fn drop(&mut self) {
146        if self.enabled {
147            panic!("cannot panic during the backtrace function");
148        }
149    }
150}
151
152#[allow(dead_code)]
153#[cfg(feature = "std")]
154mod lock {
155    use std::boxed::Box;
156    use std::cell::Cell;
157    use std::sync::{Mutex, MutexGuard, Once};
158
159    pub struct LockGuard(Option<MutexGuard<'static, ()>>);
160
161    static mut LOCK: *mut Mutex<()> = 0 as *mut _;
162    static INIT: Once = Once::new();
163    thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));
164
165    impl Drop for LockGuard {
166        fn drop(&mut self) {
167            if self.0.is_some() {
168                LOCK_HELD.with(|slot| {
169                    assert!(slot.get());
170                    slot.set(false);
171                });
172            }
173        }
174    }
175
176    pub fn lock() -> LockGuard {
177        if LOCK_HELD.with(|l| l.get()) {
178            return LockGuard(None);
179        }
180        LOCK_HELD.with(|s| s.set(true));
181        unsafe {
182            INIT.call_once(|| {
183                LOCK = Box::into_raw(Box::new(Mutex::new(())));
184            });
185            LockGuard(Some((*LOCK).lock().unwrap()))
186        }
187    }
188}
189
190#[cfg(all(windows, not(target_vendor = "uwp")))]
191mod dbghelp;
192#[cfg(windows)]
193mod windows;