1 //! A library for acquiring a backtrace at runtime
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
11 //! This library makes use of a number of strategies for actually acquiring a
12 //! backtrace. For example unix uses libgcc's libunwind bindings by default to
13 //! acquire a backtrace, but coresymbolication or dladdr is used on OSX to
14 //! acquire symbol names while linux uses gcc's libbacktrace.
16 //! When using the default feature set of this library the "most reasonable" set
17 //! of defaults is chosen for the current platform, but the features activated
18 //! can also be controlled at a finer granularity.
20 //! # Platform Support
22 //! Currently this library is verified to work on Linux, OSX, and Windows, but
23 //! it may work on other platforms as well. Note that the quality of the
24 //! backtrace may vary across platforms.
28 //! This library attempts to be as flexible as possible to accommodate different
29 //! backend implementations of acquiring a backtrace. Consequently the currently
30 //! exported functions are closure-based as opposed to the likely expected
31 //! iterator-based versions. This is done due to limitations of the underlying
32 //! APIs used from the system.
36 //! First, add this to your Cargo.toml
46 //! extern crate backtrace;
49 //! # // Unsafe here so test passes on no_std.
50 //! # #[cfg(feature = "std")] {
51 //! backtrace::trace(|frame| {
52 //! let ip = frame.ip();
53 //! let symbol_address = frame.symbol_address();
55 //! // Resolve this instruction pointer to a symbol name
56 //! backtrace::resolve(ip, |symbol| {
57 //! if let Some(name) = symbol.name() {
60 //! if let Some(filename) = symbol.filename() {
65 //! true // keep going to the next frame
71 #![doc(html_root_url = "https://docs.rs/backtrace")]
72 #![deny(missing_docs)]
75 #[cfg(feature = "std")]
76 #[macro_use] extern crate std;
83 #[cfg(feature = "serde_derive")]
84 #[cfg_attr(feature = "serde_derive", macro_use)]
85 extern crate serde_derive
;
87 #[cfg(feature = "rustc-serialize")]
88 extern crate rustc_serialize
;
93 extern crate rustc_demangle
;
95 #[cfg(feature = "cpp_demangle")]
96 extern crate cpp_demangle
;
99 if #[cfg(all(feature = "gimli-symbolize", unix, target_os = "linux"))] {
100 extern crate addr2line
;
101 extern crate findshlibs
;
108 #[allow(dead_code)] // not used everywhere
113 pub use backtrace
::{trace_unsynchronized, Frame}
;
116 pub use symbolize
::{resolve_unsynchronized, Symbol, SymbolName}
;
119 pub use types
::BytesOrWideString
;
123 if #[cfg(feature = "std")] {
124 pub use backtrace
::trace
;
125 pub use symbolize
::resolve
;
126 pub use capture
::{Backtrace, BacktraceFrame, BacktraceSymbol}
;
140 panic
!("cannot panic during the backtrace function");
146 #[cfg(feature = "std")]
150 use std
::sync
::{Once, Mutex, MutexGuard, ONCE_INIT}
;
152 pub struct LockGuard(MutexGuard
<'
static, ()>);
154 static mut LOCK
: *mut Mutex
<()> = 0 as *mut _
;
155 static INIT
: Once
= ONCE_INIT
;
156 thread_local
!(static LOCK_HELD
: Cell
<bool
> = Cell
::new(false));
158 impl Drop
for LockGuard
{
160 LOCK_HELD
.with(|slot
| {
167 pub fn lock() -> Option
<LockGuard
> {
168 if LOCK_HELD
.with(|l
| l
.get()) {
171 LOCK_HELD
.with(|s
| s
.set(true));
174 LOCK
= Box
::into_raw(Box
::new(Mutex
::new(())));
176 Some(LockGuard((*LOCK
).lock().unwrap()))
181 // requires external synchronization
182 #[cfg(all(windows, feature = "dbghelp"))]
183 unsafe fn dbghelp_init() {
184 use winapi
::shared
::minwindef
;
185 use winapi
::um
::{dbghelp, processthreadsapi}
;
187 static mut INITIALIZED
: bool
= false;
190 dbghelp
::SymInitializeW(processthreadsapi
::GetCurrentProcess(),