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