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 //! 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]
106 extern 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)]
111 extern crate alloc;
112 
113 pub use self::backtrace::{trace_unsynchronized, Frame};
114 mod backtrace;
115 
116 pub use self::symbolize::resolve_frame_unsynchronized;
117 pub use self::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
118 mod symbolize;
119 
120 pub use self::types::BytesOrWideString;
121 mod types;
122 
123 #[cfg(feature = "std")]
124 pub use self::symbolize::clear_symbol_cache;
125 
126 mod print;
127 pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};
128 
129 cfg_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)]
139 struct Bomb {
140     enabled: bool,
141 }
142 
143 #[allow(dead_code)]
144 impl Drop for Bomb {
drop(&mut self)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")]
154 mod 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 {
drop(&mut self)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 
lock() -> LockGuard176     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")))]
191 mod dbghelp;
192 #[cfg(windows)]
193 mod windows;
194