#[cfg(feature = "serde")] use crate::resolve; use crate::PrintFmt; use crate::{resolve_frame, trace, BacktraceFmt, Symbol, SymbolName}; use core::ffi::c_void; use std::fmt; use std::path::{Path, PathBuf}; use std::prelude::v1::*; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// Representation of an owned and self-contained backtrace. /// /// This structure can be used to capture a backtrace at various points in a /// program and later used to inspect what the backtrace was at that time. /// /// `Backtrace` supports pretty-printing of backtraces through its `Debug` /// implementation. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[derive(Clone)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct Backtrace { // Frames here are listed from top-to-bottom of the stack frames: Vec, } #[derive(Clone, Copy)] struct TracePtr(*mut c_void); /// SAFETY: These pointers are always valid within a process and are not used for mutation. unsafe impl Send for TracePtr {} /// SAFETY: These pointers are always valid within a process and are not used for mutation. unsafe impl Sync for TracePtr {} impl TracePtr { fn into_void(self) -> *mut c_void { self.0 } #[cfg(feature = "serde")] fn from_addr(addr: usize) -> Self { TracePtr(addr as *mut c_void) } } #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for TracePtr { #[inline] fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct PrimitiveVisitor; impl<'de> serde::de::Visitor<'de> for PrimitiveVisitor { type Value = TracePtr; fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("usize") } #[inline] fn visit_u8(self, v: u8) -> Result where E: serde::de::Error, { Ok(TracePtr(v as usize as *mut c_void)) } #[inline] fn visit_u16(self, v: u16) -> Result where E: serde::de::Error, { Ok(TracePtr(v as usize as *mut c_void)) } #[inline] fn visit_u32(self, v: u32) -> Result where E: serde::de::Error, { if usize::BITS >= 32 { Ok(TracePtr(v as usize as *mut c_void)) } else { Err(E::invalid_type( serde::de::Unexpected::Unsigned(v as _), &self, )) } } #[inline] fn visit_u64(self, v: u64) -> Result where E: serde::de::Error, { if usize::BITS >= 64 { Ok(TracePtr(v as usize as *mut c_void)) } else { Err(E::invalid_type( serde::de::Unexpected::Unsigned(v as _), &self, )) } } } deserializer.deserialize_u64(PrimitiveVisitor) } } #[cfg(feature = "serde")] impl Serialize for TracePtr { #[inline] fn serialize(&self, serializer: S) -> Result where S: serde::ser::Serializer, { serializer.serialize_u64(self.0 as usize as u64) } } fn _assert_send_sync() { fn _assert() {} _assert::(); } /// Captured version of a frame in a backtrace. /// /// This type is returned as a list from `Backtrace::frames` and represents one /// stack frame in a captured backtrace. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[derive(Clone)] pub struct BacktraceFrame { frame: Frame, symbols: Option>, } #[derive(Clone)] enum Frame { Raw(crate::Frame), #[cfg(feature = "serde")] Deserialized { ip: TracePtr, symbol_address: TracePtr, module_base_address: Option, }, } impl Frame { fn ip(&self) -> *mut c_void { match *self { Frame::Raw(ref f) => f.ip(), #[cfg(feature = "serde")] Frame::Deserialized { ip, .. } => ip.into_void(), } } fn symbol_address(&self) -> *mut c_void { match *self { Frame::Raw(ref f) => f.symbol_address(), #[cfg(feature = "serde")] Frame::Deserialized { symbol_address, .. } => symbol_address.into_void(), } } fn module_base_address(&self) -> Option<*mut c_void> { match *self { Frame::Raw(ref f) => f.module_base_address(), #[cfg(feature = "serde")] Frame::Deserialized { module_base_address, .. } => module_base_address.map(|addr| addr.into_void()), } } /// Resolve all addresses in the frame to their symbolic names. fn resolve_symbols(&self) -> Vec { let mut symbols = Vec::new(); let sym = |symbol: &Symbol| { symbols.push(BacktraceSymbol { name: symbol.name().map(|m| m.as_bytes().to_vec()), addr: symbol.addr().map(TracePtr), filename: symbol.filename().map(|m| m.to_owned()), lineno: symbol.lineno(), colno: symbol.colno(), }); }; match *self { Frame::Raw(ref f) => resolve_frame(f, sym), #[cfg(feature = "serde")] Frame::Deserialized { ip, .. } => { resolve(ip.into_void(), sym); } } symbols } } /// Captured version of a symbol in a backtrace. /// /// This type is returned as a list from `BacktraceFrame::symbols` and /// represents the metadata for a symbol in a backtrace. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[derive(Clone)] #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct BacktraceSymbol { name: Option>, addr: Option, filename: Option, lineno: Option, colno: Option, } impl Backtrace { /// Captures a backtrace at the callsite of this function, returning an /// owned representation. /// /// This function is useful for representing a backtrace as an object in /// Rust. This returned value can be sent across threads and printed /// elsewhere, and the purpose of this value is to be entirely self /// contained. /// /// Note that on some platforms acquiring a full backtrace and resolving it /// can be extremely expensive. If the cost is too much for your application /// it's recommended to instead use `Backtrace::new_unresolved()` which /// avoids the symbol resolution step (which typically takes the longest) /// and allows deferring that to a later date. /// /// # Examples /// /// ``` /// use backtrace::Backtrace; /// /// let current_backtrace = Backtrace::new(); /// ``` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[inline(never)] // want to make sure there's a frame here to remove pub fn new() -> Backtrace { let mut bt = Self::create(Self::new as usize); bt.resolve(); bt } /// Similar to `new` except that this does not resolve any symbols, this /// simply captures the backtrace as a list of addresses. /// /// At a later time the `resolve` function can be called to resolve this /// backtrace's symbols into readable names. This function exists because /// the resolution process can sometimes take a significant amount of time /// whereas any one backtrace may only be rarely printed. /// /// # Examples /// /// ``` /// use backtrace::Backtrace; /// /// let mut current_backtrace = Backtrace::new_unresolved(); /// println!("{current_backtrace:?}"); // no symbol names /// current_backtrace.resolve(); /// println!("{current_backtrace:?}"); // symbol names now present /// ``` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. #[inline(never)] // want to make sure there's a frame here to remove pub fn new_unresolved() -> Backtrace { Self::create(Self::new_unresolved as usize) } fn create(ip: usize) -> Backtrace { let mut frames = Vec::new(); trace(|frame| { frames.push(BacktraceFrame { frame: Frame::Raw(frame.clone()), symbols: None, }); // clear inner frames, and start with call site. if frame.symbol_address() as usize == ip { frames.clear(); } true }); frames.shrink_to_fit(); Backtrace { frames } } /// Returns the frames from when this backtrace was captured. /// /// The first entry of this slice is likely the function `Backtrace::new`, /// and the last frame is likely something about how this thread or the main /// function started. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn frames(&self) -> &[BacktraceFrame] { self.frames.as_slice() } /// If this backtrace was created from `new_unresolved` then this function /// will resolve all addresses in the backtrace to their symbolic names. /// /// If this backtrace has been previously resolved or was created through /// `new`, this function does nothing. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn resolve(&mut self) { self.frames.iter_mut().for_each(BacktraceFrame::resolve); } } impl From> for Backtrace { fn from(frames: Vec) -> Self { Backtrace { frames } } } impl From for BacktraceFrame { fn from(frame: crate::Frame) -> Self { BacktraceFrame { frame: Frame::Raw(frame), symbols: None, } } } // we don't want implementing `impl From for Vec` on purpose, // because "... additional directions for Vec can weaken type inference ..." // more information on https://github.com/rust-lang/backtrace-rs/pull/526 impl Into> for Backtrace { fn into(self) -> Vec { self.frames } } impl BacktraceFrame { /// Same as `Frame::ip` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn ip(&self) -> *mut c_void { self.frame.ip() } /// Same as `Frame::symbol_address` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn symbol_address(&self) -> *mut c_void { self.frame.symbol_address() } /// Same as `Frame::module_base_address` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn module_base_address(&self) -> Option<*mut c_void> { self.frame.module_base_address() } /// Returns the list of symbols that this frame corresponds to. /// /// Normally there is only one symbol per frame, but sometimes if a number /// of functions are inlined into one frame then multiple symbols will be /// returned. The first symbol listed is the "innermost function", whereas /// the last symbol is the outermost (last caller). /// /// Note that if this frame came from an unresolved backtrace then this will /// return an empty list. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn symbols(&self) -> &[BacktraceSymbol] { self.symbols.as_ref().map(|s| &s[..]).unwrap_or(&[]) } /// Resolve all addresses in this frame to their symbolic names. /// /// If this frame has been previously resolved, this function does nothing. /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn resolve(&mut self) { if self.symbols.is_none() { self.symbols = Some(self.frame.resolve_symbols()); } } } impl BacktraceSymbol { /// Same as `Symbol::name` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn name(&self) -> Option> { self.name.as_ref().map(|s| SymbolName::new(s)) } /// Same as `Symbol::addr` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn addr(&self) -> Option<*mut c_void> { self.addr.map(|s| s.into_void()) } /// Same as `Symbol::filename` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn filename(&self) -> Option<&Path> { self.filename.as_ref().map(|p| &**p) } /// Same as `Symbol::lineno` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn lineno(&self) -> Option { self.lineno } /// Same as `Symbol::colno` /// /// # Required features /// /// This function requires the `std` feature of the `backtrace` crate to be /// enabled, and the `std` feature is enabled by default. pub fn colno(&self) -> Option { self.colno } } impl fmt::Debug for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let style = if fmt.alternate() { PrintFmt::Full } else { PrintFmt::Short }; // When printing paths we try to strip the cwd if it exists, otherwise // we just print the path as-is. Note that we also only do this for the // short format, because if it's full we presumably want to print // everything. let cwd = std::env::current_dir(); let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: crate::BytesOrWideString<'_>| { let path = path.into_path_buf(); if style == PrintFmt::Full { if let Ok(cwd) = &cwd { if let Ok(suffix) = path.strip_prefix(cwd) { return fmt::Display::fmt(&suffix.display(), fmt); } } } fmt::Display::fmt(&path.display(), fmt) }; let mut f = BacktraceFmt::new(fmt, style, &mut print_path); f.add_context()?; for frame in &self.frames { f.frame().backtrace_frame(frame)?; } f.finish()?; Ok(()) } } impl Default for Backtrace { fn default() -> Backtrace { Backtrace::new() } } impl fmt::Debug for BacktraceFrame { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BacktraceFrame") .field("ip", &self.ip()) .field("symbol_address", &self.symbol_address()) .finish() } } impl fmt::Debug for BacktraceSymbol { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("BacktraceSymbol") .field("name", &self.name()) .field("addr", &self.addr()) .field("filename", &self.filename()) .field("lineno", &self.lineno()) .field("colno", &self.colno()) .finish() } } #[cfg(feature = "serde")] mod serde_impls { use super::*; use serde::de::Deserializer; use serde::ser::Serializer; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] struct SerializedFrame { ip: usize, symbol_address: usize, module_base_address: Option, symbols: Option>, } impl Serialize for BacktraceFrame { fn serialize(&self, s: S) -> Result where S: Serializer, { let BacktraceFrame { frame, symbols } = self; SerializedFrame { ip: frame.ip() as usize, symbol_address: frame.symbol_address() as usize, module_base_address: frame.module_base_address().map(|sym_a| sym_a as usize), symbols: symbols.clone(), } .serialize(s) } } impl<'a> Deserialize<'a> for BacktraceFrame { fn deserialize(d: D) -> Result where D: Deserializer<'a>, { let frame: SerializedFrame = SerializedFrame::deserialize(d)?; Ok(BacktraceFrame { frame: Frame::Deserialized { ip: TracePtr::from_addr(frame.ip), symbol_address: TracePtr::from_addr(frame.symbol_address), module_base_address: frame.module_base_address.map(TracePtr::from_addr), }, symbols: frame.symbols, }) } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_frame_conversion() { let mut frames = vec![]; crate::trace(|frame| { let converted = BacktraceFrame::from(frame.clone()); frames.push(converted); true }); let mut manual = Backtrace::from(frames); manual.resolve(); let frames = manual.frames(); for frame in frames { println!("{:?}", frame.ip()); println!("{:?}", frame.symbol_address()); println!("{:?}", frame.module_base_address()); println!("{:?}", frame.symbols()); } } }