      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144

    //! A library for acquiring a backtrace at runtime
    //!
    //! This library is meant to supplement the `RUST_BACKTRACE=1` support of the
    //! standard library by allowing an acquisition of a backtrace at runtime
    //! programmatically. The backtraces generated by this library do not need to be
    //! parsed, for example, and expose the functionality of multiple backend
    //! implementations.
    //!
    //! # Usage
    //!
    //! First, add this to your Cargo.toml
    //!
    //! ```toml
    //! [dependencies]
    //! backtrace = "0.3"
    //! ```
    //!
    //! Next:
    //!
    //! ```
    //! fn main() {
    //! # // Unsafe here so test passes on no_std.
    //! # #[cfg(feature = "std")] {
    //!     backtrace::trace(|frame| {
    //!         let ip = frame.ip();
    //!         let symbol_address = frame.symbol_address();
    //!
    //!         // Resolve this instruction pointer to a symbol name
    //!         backtrace::resolve_frame(frame, |symbol| {
    //!             if let Some(name) = symbol.name() {
    //!                 // ...
    //!             }
    //!             if let Some(filename) = symbol.filename() {
    //!                 // ...
    //!             }
    //!         });
    //!
    //!         true // keep going to the next frame
    //!     });
    //! }
    //! # }
    //! ```

    #![doc(html_root_url = "https://docs.rs/backtrace")]
    #![deny(missing_docs)]
    #![no_std]
    #![cfg_attr(
        all(feature = "std", target_env = "sgx", target_vendor = "fortanix"),
        feature(sgx_platform)
    )]
    #![warn(rust_2018_idioms)]
    // When we're building as part of libstd, silence all warnings since they're
    // irrelevant as this crate is developed out-of-tree.
    #![cfg_attr(backtrace_in_libstd, allow(warnings))]

    #[cfg(feature = "std")]
    #[macro_use]
    extern crate std;

    // This is only used for gimli right now, so silence warnings elsewhere.
    #[cfg_attr(not(target_os = "linux"), allow(unused_extern_crates))]
    extern crate alloc;

    pub use self::backtrace::{trace_unsynchronized, Frame};
    mod backtrace;

    pub use self::symbolize::resolve_frame_unsynchronized;
    pub use self::symbolize::{resolve_unsynchronized, Symbol, SymbolName};
    mod symbolize;

    pub use self::types::BytesOrWideString;
    mod types;

    #[cfg(feature = "std")]
    pub use self::symbolize::clear_symbol_cache;

    mod print;
    pub use print::{BacktraceFmt, BacktraceFrameFmt, PrintFmt};

    cfg_if::cfg_if! {
        if #[cfg(feature = "std")] {
            pub use self::backtrace::trace;
            pub use self::symbolize::{resolve, resolve_frame};
            pub use self::capture::{Backtrace, BacktraceFrame, BacktraceSymbol};
            mod capture;
        }
    }

    #[allow(dead_code)]
    struct Bomb {
        enabled: bool,
    }

    #[allow(dead_code)]
    impl Drop for Bomb {
        fn drop(&mut self) {
            if self.enabled {
                panic!("cannot panic during the backtrace function");
            }
        }
    }

    #[allow(dead_code)]
    #[cfg(feature = "std")]
    mod lock {
        use std::boxed::Box;
        use std::cell::Cell;
        use std::sync::{Mutex, MutexGuard, Once};

        pub struct LockGuard(Option<MutexGuard<'static, ()>>);

        static mut LOCK: *mut Mutex<()> = 0 as *mut _;
        static INIT: Once = Once::new();
        thread_local!(static LOCK_HELD: Cell<bool> = Cell::new(false));

        impl Drop for LockGuard {
            fn drop(&mut self) {
                if self.0.is_some() {
                    LOCK_HELD.with(|slot| {
                        assert!(slot.get());
                        slot.set(false);
                    });
                }
            }
        }

        pub fn lock() -> LockGuard {
            if LOCK_HELD.with(|l| l.get()) {
                return LockGuard(None);
            }
            LOCK_HELD.with(|s| s.set(true));
            unsafe {
                INIT.call_once(|| {
                    LOCK = Box::into_raw(Box::new(Mutex::new(())));
                });
                LockGuard(Some((*LOCK).lock().unwrap()))
            }
        }
    }

    #[cfg(all(windows, not(target_vendor = "uwp")))]
    mod dbghelp;
    #[cfg(windows)]
    mod windows;