#
std/backtrace/src/backtrace/
mod.rs

    1use core::ffi::c_void;
    2use core::fmt;
    3
    4/// Inspects the current call-stack, passing all active frames into the closure
    5/// provided to calculate a stack trace.
    6///
    7/// This function is the workhorse of this library in calculating the stack
    8/// traces for a program. The given closure `cb` is yielded instances of a
    9/// `Frame` which represent information about that call frame on the stack. The
    10/// closure is yielded frames in a top-down fashion (most recently called
    11/// functions first).
    12///
    13/// The closure's return value is an indication of whether the backtrace should
    14/// continue. A return value of `false` will terminate the backtrace and return
    15/// immediately.
    16///
    17/// Once a `Frame` is acquired you will likely want to call `backtrace::resolve`
    18/// to convert the `ip` (instruction pointer) or symbol address to a `Symbol`
    19/// through which the name and/or filename/line number can be learned.
    20///
    21/// Note that this is a relatively low-level function and if you'd like to, for
    22/// example, capture a backtrace to be inspected later, then the `Backtrace`
    23/// type may be more appropriate.
    24///
    25/// # Required features
    26///
    27/// This function requires the `std` feature of the `backtrace` crate to be
    28/// enabled, and the `std` feature is enabled by default.
    29///
    30/// # Panics
    31///
    32/// This function strives to never panic, but if the `cb` provided panics then
    33/// some platforms will force a double panic to abort the process. Some
    34/// platforms use a C library which internally uses callbacks which cannot be
    35/// unwound through, so panicking from `cb` may trigger a process abort.
    36///
    37/// # Example
    38///
    39/// ```
    40/// extern crate backtrace;
    41///
    42/// fn main() {
    43///     backtrace::trace(|frame| {
    44///         // ...
    45///
    46///         true // continue the backtrace
    47///     });
    48/// }
    49/// ```
    50#[cfg(feature = "std")]
    51pub fn trace<F: FnMut(&Frame) -> bool>(cb: F) {
    52    let _guard = crate::lock::lock();
    53    unsafe { trace_unsynchronized(cb) }
    54}
    55
    56/// Same as `trace`, only unsafe as it's unsynchronized.
    57///
    58/// This function does not have synchronization guarantees but is available
    59/// when the `std` feature of this crate isn't compiled in. See the `trace`
    60/// function for more documentation and examples.
    61///
    62/// # Panics
    63///
    64/// See information on `trace` for caveats on `cb` panicking.
    65pub unsafe fn trace_unsynchronized<F: FnMut(&Frame) -> bool>(mut cb: F) {
    66    unsafe { trace_imp(&mut cb) }
    67}
    68
    69/// A trait representing one frame of a backtrace, yielded to the `trace`
    70/// function of this crate.
    71///
    72/// The tracing function's closure will be yielded frames, and the frame is
    73/// virtually dispatched as the underlying implementation is not always known
    74/// until runtime.
    75#[derive(Clone)]
    76pub struct Frame {
    77    pub(crate) inner: FrameImp,
    78}
    79
    80impl Frame {
    81    /// Returns the current instruction pointer of this frame.
    82    ///
    83    /// This is normally the next instruction to execute in the frame, but not
    84    /// all implementations list this with 100% accuracy (but it's generally
    85    /// pretty close).
    86    ///
    87    /// It is recommended to pass this value to `backtrace::resolve` to turn it
    88    /// into a symbol name.
    89    pub fn ip(&self) -> *mut c_void {
    90        self.inner.ip()
    91    }
    92
    93    /// Returns the current stack pointer of this frame.
    94    ///
    95    /// In the case that a backend cannot recover the stack pointer for this
    96    /// frame, a null pointer is returned.
    97    pub fn sp(&self) -> *mut c_void {
    98        self.inner.sp()
    99    }
    100
    101    /// Returns the starting symbol address of the frame of this function.
    102    ///
    103    /// This will attempt to rewind the instruction pointer returned by `ip` to
    104    /// the start of the function, returning that value. In some cases, however,
    105    /// backends will just return `ip` from this function.
    106    ///
    107    /// The returned value can sometimes be used if `backtrace::resolve` failed
    108    /// on the `ip` given above.
    109    pub fn symbol_address(&self) -> *mut c_void {
    110        self.inner.symbol_address()
    111    }
    112
    113    /// Returns the base address of the module to which the frame belongs.
    114    pub fn module_base_address(&self) -> Option<*mut c_void> {
    115        self.inner.module_base_address()
    116    }
    117}
    118
    119impl fmt::Debug for Frame {
    120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    121        f.debug_struct("Frame")
    122            .field("ip", &self.ip())
    123            .field("symbol_address", &self.symbol_address())
    124            .finish()
    125    }
    126}
    127
    128#[cfg(all(target_env = "sgx", target_vendor = "fortanix"))]
    129mod sgx_image_base {
    130
    131    #[cfg(not(feature = "std"))]
    132    pub(crate) mod imp {
    133        use core::ffi::c_void;
    134        use core::sync::atomic::{AtomicUsize, Ordering::SeqCst};
    135
    136        static IMAGE_BASE: AtomicUsize = AtomicUsize::new(0);
    137
    138        /// Set the image base address. This is only available for Fortanix SGX
    139        /// target when the `std` feature is not enabled. This can be used in the
    140        /// standard library to set the correct base address.
    141        #[doc(hidden)]
    142        pub fn set_image_base(base_addr: *mut c_void) {
    143            IMAGE_BASE.store(base_addr as _, SeqCst);
    144        }
    145
    146        pub(crate) fn get_image_base() -> *mut c_void {
    147            IMAGE_BASE.load(SeqCst) as _
    148        }
    149    }
    150
    151    #[cfg(feature = "std")]
    152    mod imp {
    153        use core::ffi::c_void;
    154
    155        pub(crate) fn get_image_base() -> *mut c_void {
    156            std::os::fortanix_sgx::mem::image_base() as _
    157        }
    158    }
    159
    160    pub(crate) use imp::get_image_base;
    161}
    162
    163#[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))]
    164pub use sgx_image_base::imp::set_image_base;
    165
    166cfg_if::cfg_if! {
    167    // This needs to come first, to ensure that
    168    // Miri takes priority over the host platform
    169    if #[cfg(miri)] {
    170        pub(crate) mod miri;
    171        use self::miri::trace as trace_imp;
    172        pub(crate) use self::miri::Frame as FrameImp;
    173    } else if #[cfg(
    174        any(
    175            all(
    176                unix,
    177                not(target_os = "emscripten"),
    178                not(all(target_os = "ios", target_arch = "arm")),
    179            ),
    180            all(
    181                target_env = "sgx",
    182                target_vendor = "fortanix",
    183            ),
    184        )
    185    )] {
    186        mod libunwind;
    187        use self::libunwind::trace as trace_imp;
    188        pub(crate) use self::libunwind::Frame as FrameImp;
    189    } else if #[cfg(all(windows, not(target_vendor = "uwp")))] {
    190        cfg_if::cfg_if! {
    191            if #[cfg(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "arm64ec"))] {
    192                mod win64;
    193                use self::win64::trace as trace_imp;
    194                pub(crate) use self::win64::Frame as FrameImp;
    195            } else if #[cfg(any(target_arch = "x86", target_arch = "arm"))] {
    196                mod win32;
    197                use self::win32::trace as trace_imp;
    198                pub(crate) use self::win32::Frame as FrameImp;
    199            }
    200        }
    201    } else {
    202        mod noop;
    203        use self::noop::trace as trace_imp;
    204        pub(crate) use self::noop::Frame as FrameImp;
    205    }
    206}