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 //! # Platform Support
21 //!
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.
25 //!
26 //! # API Principles
27 //!
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.
33 //!
34 //! # Usage
35 //!
36 //! First, add this to your Cargo.toml
37 //!
38 //! ```toml
39 //! [dependencies]
40 //! backtrace = "0.2"
41 //! ```
42 //!
43 //! Next:
44 //!
45 //! ```
46 //! extern crate backtrace;
47 //!
48 //! fn main() {
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();
54 //!
55 //!         // Resolve this instruction pointer to a symbol name
56 //!         backtrace::resolve(ip, |symbol| {
57 //!             if let Some(name) = symbol.name() {
58 //!                 // ...
59 //!             }
60 //!             if let Some(filename) = symbol.filename() {
61 //!                 // ...
62 //!             }
63 //!         });
64 //!
65 //!         true // keep going to the next frame
66 //!     });
67 //! }
68 //! # }
69 //! ```
70 
71 #![doc(html_root_url = "https://docs.rs/backtrace")]
72 #![deny(missing_docs)]
73 #![no_std]
74 #![cfg_attr(target_env = "sgx", feature(sgx_platform))]
75 
76 #[cfg(feature = "std")]
77 #[macro_use] extern crate std;
78 
79 #[cfg(any(unix, target_env = "sgx"))]
80 extern crate libc;
81 #[cfg(windows)]
82 extern crate winapi;
83 
84 #[cfg(feature = "serde_derive")]
85 #[cfg_attr(feature = "serde_derive", macro_use)]
86 extern crate serde_derive;
87 
88 #[cfg(feature = "rustc-serialize")]
89 extern crate rustc_serialize;
90 
91 #[macro_use]
92 extern crate cfg_if;
93 
94 extern crate rustc_demangle;
95 
96 #[cfg(feature = "cpp_demangle")]
97 extern crate cpp_demangle;
98 
99 cfg_if! {
100     if #[cfg(all(feature = "gimli-symbolize", unix, target_os = "linux"))] {
101         extern crate addr2line;
102         extern crate findshlibs;
103         extern crate gimli;
104         extern crate memmap;
105         extern crate object;
106     }
107 }
108 
109 #[allow(dead_code)] // not used everywhere
110 #[cfg(unix)]
111 #[macro_use]
112 mod dylib;
113 
114 pub use backtrace::{trace_unsynchronized, Frame};
115 mod backtrace;
116 
117 pub use symbolize::{resolve_unsynchronized, Symbol, SymbolName};
118 mod symbolize;
119 
120 pub use types::BytesOrWideString;
121 mod types;
122 
123 cfg_if! {
124     if #[cfg(feature = "std")] {
125         pub use backtrace::trace;
126         pub use symbolize::resolve;
127         pub use capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
128         mod capture;
129     }
130 }
131 
132 #[allow(dead_code)]
133 struct Bomb {
134     enabled: bool,
135 }
136 
137 #[allow(dead_code)]
138 impl Drop for Bomb {
drop(&mut self)139     fn drop(&mut self) {
140         if self.enabled {
141             panic!("cannot panic during the backtrace function");
142         }
143     }
144 }
145 
146 #[allow(dead_code)]
147 #[cfg(feature = "std")]
148 mod lock {
149     use std::cell::Cell;
150     use std::boxed::Box;
151     use std::sync::{Once, Mutex, MutexGuard, ONCE_INIT};
152 
153     pub struct LockGuard(MutexGuard<'static, ()>);
154 
155     static mut LOCK: *mut Mutex<()> = 0 as *mut _;
156     static INIT: Once = ONCE_INIT;
157     thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));
158 
159     impl Drop for LockGuard {
drop(&mut self)160         fn drop(&mut self) {
161             LOCK_HELD.with(|slot| {
162                 assert!(slot.get());
163                 slot.set(false);
164             });
165         }
166     }
167 
lock() -> Option<LockGuard>168     pub fn lock() -> Option<LockGuard> {
169         if LOCK_HELD.with(|l| l.get()) {
170             return None
171         }
172         LOCK_HELD.with(|s| s.set(true));
173         unsafe {
174             INIT.call_once(|| {
175                 LOCK = Box::into_raw(Box::new(Mutex::new(())));
176             });
177             Some(LockGuard((*LOCK).lock().unwrap()))
178         }
179     }
180 }
181 
182 // requires external synchronization
183 #[cfg(all(windows, feature = "dbghelp"))]
dbghelp_init()184 unsafe fn dbghelp_init() {
185     use winapi::shared::minwindef;
186     use winapi::um::{dbghelp, processthreadsapi};
187 
188     static mut INITIALIZED: bool = false;
189 
190     if !INITIALIZED {
191         dbghelp::SymInitializeW(processthreadsapi::GetCurrentProcess(),
192                                 0 as *mut _,
193                                 minwindef::TRUE);
194         INITIALIZED = true;
195     }
196 }
197