use core::ffi::c_void; use core::fmt; /// Inspects the current call-stack, passing all active frames into the closure /// provided to calculate a stack trace. /// /// This function is the workhorse of this library in calculating the stack /// traces for a program. The given closure `cb` is yielded instances of a /// `Frame` which represent information about that call frame on the stack. The /// closure is yielded frames in a top-down fashion (most recently called /// functions first). /// /// The closure's return value is an indication of whether the backtrace should /// continue. A return value of `false` will terminate the backtrace and return /// immediately. /// /// Once a `Frame` is acquired you will likely want to call `backtrace::resolve` /// to convert the `ip` (instruction pointer) or symbol address to a `Symbol` /// through which the name and/or filename/line number can be learned. /// /// Note that this is a relatively low-level function and if you'd like to, for /// example, capture a backtrace to be inspected later, then the `Backtrace` /// type may be more appropriate. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. /// /// # Panics /// /// This function strives to never panic, but if the `cb` provided panics then /// some platforms will force a double panic to abort the process. Some /// platforms use a C library which internally uses callbacks which cannot be /// unwound through, so panicking from `cb` may trigger a process abort. /// /// # Example /// /// ``` /// extern crate backtrace; /// /// fn main() { /// backtrace::trace(|frame| { /// // ... /// /// true // continue the backtrace /// }); /// } /// ``` #[cfg(feature = "std")] pub fn trace bool>(cb: F) { let _guard = crate::lock::lock(); unsafe { trace_unsynchronized(cb) } } /// Same as `trace`, only unsafe as it's unsynchronized. /// /// This function does not have synchronization guarantees but is available /// when the `std` feature of this crate isn't compiled in. See the `trace` /// function for more documentation and examples. /// /// # Panics /// /// See information on `trace` for caveats on `cb` panicking. pub unsafe fn trace_unsynchronized bool>(mut cb: F) { trace_imp(&mut cb) } /// A trait representing one frame of a backtrace, yielded to the `trace` /// function of this crate. /// /// The tracing function's closure will be yielded frames, and the frame is /// virtually dispatched as the underlying implementation is not always known /// until runtime. #[derive(Clone)] pub struct Frame { pub(crate) inner: FrameImp, } impl Frame { /// Returns the current instruction pointer of this frame. /// /// This is normally the next instruction to execute in the frame, but not /// all implementations list this with 100% accuracy (but it's generally /// pretty close). /// /// It is recommended to pass this value to `backtrace::resolve` to turn it /// into a symbol name. pub fn ip(&self) -> *mut c_void { self.inner.ip() } /// Returns the current stack pointer of this frame. /// /// In the case that a backend cannot recover the stack pointer for this /// frame, a null pointer is returned. pub fn sp(&self) -> *mut c_void { self.inner.sp() } /// Returns the starting symbol address of the frame of this function. /// /// This will attempt to rewind the instruction pointer returned by `ip` to /// the start of the function, returning that value. In some cases, however, /// backends will just return `ip` from this function. /// /// The returned value can sometimes be used if `backtrace::resolve` failed /// on the `ip` given above. pub fn symbol_address(&self) -> *mut c_void { self.inner.symbol_address() } /// Returns the base address of the module to which the frame belongs. pub fn module_base_address(&self) -> Option<*mut c_void> { self.inner.module_base_address() } } impl fmt::Debug for Frame { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Frame") .field("ip", &self.ip()) .field("symbol_address", &self.symbol_address()) .finish() } } #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] mod sgx_image_base { #[cfg(not(feature = "std"))] pub(crate) mod imp { use core::ffi::c_void; use core::sync::atomic::{AtomicUsize, Ordering::SeqCst}; static IMAGE_BASE: AtomicUsize = AtomicUsize::new(0); /// Set the image base address. This is only available for Fortanix SGX /// target when the `std` feature is not enabled. This can be used in the /// standard library to set the correct base address. #[doc(hidden)] pub fn set_image_base(base_addr: *mut c_void) { IMAGE_BASE.store(base_addr as _, SeqCst); } pub(crate) fn get_image_base() -> *mut c_void { IMAGE_BASE.load(SeqCst) as _ } } #[cfg(feature = "std")] mod imp { use core::ffi::c_void; pub(crate) fn get_image_base() -> *mut c_void { std::os::fortanix_sgx::mem::image_base() as _ } } pub(crate) use imp::get_image_base; } #[cfg(all(target_env = "sgx", target_vendor = "fortanix", not(feature = "std")))] pub use sgx_image_base::imp::set_image_base; cfg_if::cfg_if! { // This needs to come first, to ensure that // Miri takes priority over the host platform if #[cfg(miri)] { pub(crate) mod miri; use self::miri::trace as trace_imp; pub(crate) use self::miri::Frame as FrameImp; } else if #[cfg( any( all( unix, not(target_os = "emscripten"), not(all(target_os = "ios", target_arch = "arm")), ), all( target_env = "sgx", target_vendor = "fortanix", ), ) )] { mod libunwind; use self::libunwind::trace as trace_imp; pub(crate) use self::libunwind::Frame as FrameImp; } else if #[cfg(all(windows, not(target_vendor = "uwp")))] { cfg_if::cfg_if! { if #[cfg(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "arm64ec"))] { mod dbghelp64; use dbghelp64 as dbghelp; } else if #[cfg(any(target_arch = "x86", target_arch = "arm"))] { mod dbghelp32; use dbghelp32 as dbghelp; } } use self::dbghelp::trace as trace_imp; pub(crate) use self::dbghelp::Frame as FrameImp; } else { mod noop; use self::noop::trace as trace_imp; pub(crate) use self::noop::Frame as FrameImp; } }