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 //! # Implementation
10 //!
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.
15 //!
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.
19 //!
20 //! # API Principles
21 //!
22 //! This library attempts to be as flexible as possible to accommodate different
23 //! backend implementations of acquiring a backtrace. Consequently the currently
24 //! exported functions are closure-based as opposed to the likely expected
25 //! iterator-based versions. This is done due to limitations of the underlying
26 //! APIs used from the system.
27 //!
28 //! # Usage
29 //!
30 //! First, add this to your Cargo.toml
31 //!
32 //! ```toml
33 //! [dependencies]
34 //! backtrace = "0.3"
35 //! ```
36 //!
37 //! Next:
38 //!
39 //! ```
40 //! extern crate backtrace;
41 //!
42 //! fn main() {
43 //! # // Unsafe here so test passes on no_std.
44 //! # #[cfg(feature = "std")] {
45 //!     backtrace::trace(|frame| {
46 //!         let ip = frame.ip();
47 //!         let symbol_address = frame.symbol_address();
48 //!
49 //!         // Resolve this instruction pointer to a symbol name
50 //!         backtrace::resolve_frame(frame, |symbol| {
51 //!             if let Some(name) = symbol.name() {
52 //!                 // ...
53 //!             }
54 //!             if let Some(filename) = symbol.filename() {
55 //!                 // ...
56 //!             }
57 //!         });
58 //!
59 //!         true // keep going to the next frame
60 //!     });
61 //! }
62 //! # }
63 //! ```
64 
65 #![doc(html_root_url = "https://docs.rs/backtrace")]
66 #![deny(missing_docs)]
67 #![no_std]
68 #![cfg_attr(all(feature = "std", target_env = "sgx"), feature(sgx_platform))]
69 #![allow(bare_trait_objects)] // TODO: remove when updating to 2018 edition
70 #![allow(rust_2018_idioms)]   // TODO: remove when updating to 2018 edition
71 
72 #[cfg(feature = "std")]
73 #[macro_use]
74 extern crate std;
75 
76 extern crate libc;
77 #[cfg(all(windows, feature = "verify-winapi"))]
78 extern crate winapi;
79 
80 #[cfg(feature = "serde_derive")]
81 #[cfg_attr(feature = "serde_derive", macro_use)]
82 extern crate serde_derive;
83 
84 #[cfg(feature = "rustc-serialize")]
85 extern crate rustc_serialize;
86 
87 #[macro_use]
88 extern crate cfg_if;
89 
90 extern crate rustc_demangle;
91 
92 #[cfg(feature = "cpp_demangle")]
93 extern crate cpp_demangle;
94 
95 cfg_if! {
96     if #[cfg(all(feature = "gimli-symbolize", unix, target_os = "linux"))] {
97         extern crate addr2line;
98         extern crate findshlibs;
99         extern crate memmap;
100     }
101 }
102 
103 pub use backtrace::{trace_unsynchronized, Frame};
104 mod backtrace;
105 
106 pub use symbolize::{resolve_unsynchronized, Symbol, SymbolName};
107 pub use symbolize::resolve_frame_unsynchronized;
108 mod symbolize;
109 
110 pub use types::BytesOrWideString;
111 mod types;
112 
113 cfg_if! {
114     if #[cfg(feature = "std")] {
115         pub use backtrace::trace;
116         pub use symbolize::{resolve, resolve_frame};
117         pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
118         mod capture;
119     }
120 }
121 
122 #[allow(dead_code)]
123 struct Bomb {
124     enabled: bool,
125 }
126 
127 #[allow(dead_code)]
128 impl Drop for Bomb {
drop(&mut self)129     fn drop(&mut self) {
130         if self.enabled {
131             panic!("cannot panic during the backtrace function");
132         }
133     }
134 }
135 
136 #[allow(dead_code)]
137 #[cfg(feature = "std")]
138 mod lock {
139     use std::boxed::Box;
140     use std::cell::Cell;
141     use std::sync::{Mutex, MutexGuard, Once, ONCE_INIT};
142 
143     pub struct LockGuard(Option<MutexGuard<'static, ()>>);
144 
145     static mut LOCK: *mut Mutex<()> = 0 as *mut _;
146     static INIT: Once = ONCE_INIT;
147     thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));
148 
149     impl Drop for LockGuard {
drop(&mut self)150         fn drop(&mut self) {
151             if self.0.is_some() {
152                 LOCK_HELD.with(|slot| {
153                     assert!(slot.get());
154                     slot.set(false);
155                 });
156             }
157         }
158     }
159 
lock() -> LockGuard160     pub fn lock() -> LockGuard {
161         if LOCK_HELD.with(|l| l.get()) {
162             return LockGuard(None);
163         }
164         LOCK_HELD.with(|s| s.set(true));
165         unsafe {
166             INIT.call_once(|| {
167                 LOCK = Box::into_raw(Box::new(Mutex::new(())));
168             });
169             LockGuard(Some((*LOCK).lock().unwrap()))
170         }
171     }
172 }
173 
174 #[cfg(all(windows, feature = "dbghelp"))]
175 mod dbghelp;
176 #[cfg(windows)]
177 mod windows;
178