#
std/backtrace/src/
lib.rs

    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//! # // Unsafe here so test passes on no_std.
    22//! # #[cfg(feature = "std")] {
    23//! backtrace::trace(|frame| {
    24//!     let ip = frame.ip();
    25//!     let symbol_address = frame.symbol_address();
    26//!
    27//!     // Resolve this instruction pointer to a symbol name
    28//!     backtrace::resolve_frame(frame, |symbol| {
    29//!         if let Some(name) = symbol.name() {
    30//!             // ...
    31//!         }
    32//!         if let Some(filename) = symbol.filename() {
    33//!             // ...
    34//!         }
    35//!     });
    36//!
    37//!     true // keep going to the next frame
    38//! });
    39//! # }
    40//! ```
    41//!
    42//! # Backtrace accuracy
    43//!
    44//! This crate implements best-effort attempts to get the native backtrace. This
    45//! is not always guaranteed to work, and some platforms don't return any
    46//! backtrace at all. If your application requires accurate backtraces then it's
    47//! recommended to closely evaluate this crate to see whether it's suitable
    48//! for your use case on your target platforms.
    49//!
    50//! Even on supported platforms, there's a number of reasons that backtraces may
    51//! be less-than-accurate, including but not limited to:
    52//!
    53//! * Unwind information may not be available. This crate primarily implements
    54//!   backtraces by unwinding the stack, but not all functions may have
    55//!   unwinding information (e.g. DWARF unwinding information).
    56//!
    57//! * Rust code may be compiled without unwinding information for some
    58//!   functions. This can also happen for Rust code compiled with
    59//!   `-Cpanic=abort`. You can remedy this, however, with
    60//!   `-Cforce-unwind-tables` as a compiler option.
    61//!
    62//! * Unwind information may be inaccurate or corrupt. In the worst case
    63//!   inaccurate unwind information can lead this library to segfault. In the
    64//!   best case inaccurate information will result in a truncated stack trace.
    65//!
    66//! * Backtraces may not report filenames/line numbers correctly due to missing
    67//!   or corrupt debug information. This won't lead to segfaults unlike corrupt
    68//!   unwinding information, but missing or malformed debug information will
    69//!   mean that filenames and line numbers will not be available. This may be
    70//!   because debug information wasn't generated by the compiler, or it's just
    71//!   missing on the filesystem.
    72//!
    73//! * Not all platforms are supported. For example there's no way to get a
    74//!   backtrace on WebAssembly at the moment.
    75//!
    76//! * Crate features may be disabled. Currently this crate supports using Gimli
    77//!   libbacktrace on non-Windows platforms for reading debuginfo for
    78//!   backtraces. If both crate features are disabled, however, then these
    79//!   platforms will generate a backtrace but be unable to generate symbols for
    80//!   it.
    81//!
    82//! In most standard workflows for most standard platforms you generally don't
    83//! need to worry about these caveats. We'll try to fix ones where we can over
    84//! time, but otherwise it's important to be aware of the limitations of
    85//! unwinding-based backtraces!
    86
    87#![deny(missing_docs)]
    88#![no_std]
    89#![cfg_attr(
    90    all(feature = "std", target_env = "sgx", target_vendor = "fortanix"),
    91    feature(sgx_platform)
    92)]
    93#![warn(rust_2018_idioms)]
    94// When we're building as part of libstd, silence all warnings since they're
    95// irrelevant as this crate is developed out-of-tree.
    96#![cfg_attr(backtrace_in_libstd, allow(warnings))]
    97#![cfg_attr(not(feature = "std"), allow(dead_code))]
    98
    99#[cfg(feature = "std")]
    100#[macro_use]
    101extern crate std;
    102
    103// This is only used for gimli right now, which is only used on some platforms, and miri
    104// so don't worry if it's unused in other configurations.
    105#[allow(unused_extern_crates)]
    106extern crate alloc;
    107
    108pub use self::backtrace::{trace_unsynchronized, Frame};
    109mod backtrace;
    110
    111pub use self::symbolize::resolve_frame_unsynchronized;
    112pub use self::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
    113mod symbolize;
    114
    115pub use self::types::BytesOrWideString;
    116mod types;
    117
    118#[cfg(feature = "std")]
    119pub use self::symbolize::clear_symbol_cache;
    120
    121mod print;
    122pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};
    123
    124cfg_if::cfg_if! {
    125    if #[cfg(feature = "std")] {
    126        pub use self::backtrace::trace;
    127        pub use self::symbolize::{resolve, resolve_frame};
    128        pub use self::capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
    129        mod capture;
    130    }
    131}
    132
    133cfg_if::cfg_if! {
    134    if #[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] {
    135        pub use self::backtrace::set_image_base;
    136    }
    137}
    138
    139#[cfg(feature = "std")]
    140mod lock {
    141    use std::boxed::Box;
    142    use std::cell::Cell;
    143    use std::ptr;
    144    use std::sync::{Mutex, MutexGuard, Once};
    145
    146    /// A "Maybe" LockGuard
    147    pub struct LockGuard(Option<MutexGuard<'static, ()>>);
    148
    149    /// The global lock, lazily allocated on first use
    150    static mut LOCK: *mut Mutex<()> = ptr::null_mut();
    151    static INIT: Once = Once::new();
    152    // Whether this thread is the one that holds the lock
    153    thread_local!(static LOCK_HELD: Cell<bool> = const { Cell::new(false) });
    154
    155    impl Drop for LockGuard {
    156        fn drop(&mut self) {
    157            // Don't do anything if we're a LockGuard(None)
    158            if self.0.is_some() {
    159                LOCK_HELD.with(|slot| {
    160                    // Immediately crash if we somehow aren't the thread holding this lock
    161                    assert!(slot.get());
    162                    // We are no longer the thread holding this lock
    163                    slot.set(false);
    164                });
    165            }
    166            // lock implicitly released here, if we're a LockGuard(Some(..))
    167        }
    168    }
    169
    170    /// Acquire a partially unsound(!!!) global re-entrant lock over
    171    /// backtrace's internals.
    172    ///
    173    /// That is, this lock can be acquired as many times as you want
    174    /// on a single thread without deadlocking, allowing one thread
    175    /// to acquire exclusive access to the ability to make backtraces.
    176    /// Calls to this locking function are freely sprinkled in every place
    177    /// where that needs to be enforced.
    178    ///
    179    ///
    180    /// # Why
    181    ///
    182    /// This was first introduced to guard uses of Windows' dbghelp API,
    183    /// which isn't threadsafe. It's unclear if other things now rely on
    184    /// this locking.
    185    ///
    186    ///
    187    /// # How
    188    ///
    189    /// The basic idea is to have a single global mutex, and a thread_local
    190    /// boolean saying "yep this is the thread that acquired the mutex".
    191    ///
    192    /// The first time a thread acquires the lock, it is handed a
    193    /// `LockGuard(Some(..))` that will actually release the lock on Drop.
    194    /// All subsequence attempts to lock on the same thread will see
    195    /// that their thread acquired the lock, and get `LockGuard(None)`
    196    /// which will do nothing when dropped.
    197    ///
    198    ///
    199    /// # Safety
    200    ///
    201    /// As long as you only ever assign the returned LockGuard to a freshly
    202    /// declared local variable, it will do its job correctly, as the "first"
    203    /// LockGuard will strictly outlive all subsequent LockGuards and
    204    /// properly release the lock when the thread is done with backtracing.
    205    ///
    206    /// However if you ever attempt to store a LockGuard beyond the scope
    207    /// it was acquired in, it might actually be a `LockGuard(None)` that
    208    /// doesn't actually hold the lock! In this case another thread might
    209    /// acquire the lock and you'll get races this system was intended to
    210    /// avoid!
    211    ///
    212    /// This is why this is "partially unsound". As a public API this would
    213    /// be unacceptable, but this is crate-private, and if you use this in
    214    /// the most obvious and simplistic way it Just Works™.
    215    ///
    216    /// Note however that std specifically bypasses this lock, and uses
    217    /// the `*_unsynchronized` backtrace APIs. This is "fine" because
    218    /// it wraps its own calls to backtrace in a non-reentrant Mutex
    219    /// that prevents two backtraces from getting interleaved during printing.
    220    pub fn lock() -> LockGuard {
    221        // If we're the thread holding this lock, pretend to acquire the lock
    222        // again by returning a LockGuard(None)
    223        if LOCK_HELD.with(|l| l.get()) {
    224            return LockGuard(None);
    225        }
    226        // Insist that we totally are the thread holding the lock
    227        // (our thread will block until we are)
    228        LOCK_HELD.with(|s| s.set(true));
    229        unsafe {
    230            // lazily allocate the lock if necessary
    231            INIT.call_once(|| {
    232                LOCK = Box::into_raw(Box::new(Mutex::new(())));
    233            });
    234            // ok *actually* try to acquire the lock, blocking as necessary
    235            LockGuard(Some((*LOCK).lock().unwrap()))
    236        }
    237    }
    238}
    239
    240#[cfg(all(
    241    windows,
    242    any(
    243        target_env = "msvc",
    244        all(target_env = "gnu", any(target_arch = "x86", target_arch = "arm"))
    245    ),
    246    not(target_vendor = "uwp")
    247))]
    248mod dbghelp;
    249// Auto-generated by windows-bindgen/riddle
    250#[cfg(any(windows, target_os = "cygwin"))]
    251mod windows_sys;