From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- library/backtrace/src/capture.rs | 555 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 555 insertions(+) create mode 100644 library/backtrace/src/capture.rs (limited to 'library/backtrace/src/capture.rs') diff --git a/library/backtrace/src/capture.rs b/library/backtrace/src/capture.rs new file mode 100644 index 000000000..e0dd9c474 --- /dev/null +++ b/library/backtrace/src/capture.rs @@ -0,0 +1,555 @@ +use crate::PrintFmt; +use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName}; +use std::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 = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +pub struct Backtrace { + // Frames here are listed from top-to-bottom of the stack + frames: Vec, + // The index we believe is the actual start of the backtrace, omitting + // frames like `Backtrace::new` and `backtrace::trace`. + actual_start_index: usize, +} + +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), + #[allow(dead_code)] + Deserialized { + ip: usize, + symbol_address: usize, + module_base_address: Option, + }, +} + +impl Frame { + fn ip(&self) -> *mut c_void { + match *self { + Frame::Raw(ref f) => f.ip(), + Frame::Deserialized { ip, .. } => ip as *mut c_void, + } + } + + fn symbol_address(&self) -> *mut c_void { + match *self { + Frame::Raw(ref f) => f.symbol_address(), + Frame::Deserialized { symbol_address, .. } => symbol_address as *mut c_void, + } + } + + fn module_base_address(&self) -> Option<*mut c_void> { + match *self { + Frame::Raw(ref f) => f.module_base_address(), + Frame::Deserialized { + module_base_address, + .. + } => module_base_address.map(|addr| addr as *mut c_void), + } + } +} + +/// 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 = "serialize-rustc", derive(RustcDecodable, RustcEncodable))] +#[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(); + let mut actual_start_index = None; + trace(|frame| { + frames.push(BacktraceFrame { + frame: Frame::Raw(frame.clone()), + symbols: None, + }); + + if frame.symbol_address() as usize == ip && actual_start_index.is_none() { + actual_start_index = Some(frames.len()); + } + true + }); + + Backtrace { + frames, + actual_start_index: actual_start_index.unwrap_or(0), + } + } + + /// 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[self.actual_start_index..] + } + + /// 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) { + for frame in self.frames.iter_mut().filter(|f| f.symbols.is_none()) { + 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(|a| a as usize), + filename: symbol.filename().map(|m| m.to_owned()), + lineno: symbol.lineno(), + colno: symbol.colno(), + }); + }; + match frame.frame { + Frame::Raw(ref f) => resolve_frame(f, sym), + Frame::Deserialized { ip, .. } => { + resolve(ip as *mut c_void, sym); + } + } + } + frame.symbols = Some(symbols); + } + } +} + +impl From> for Backtrace { + fn from(frames: Vec) -> Self { + Backtrace { + frames, + actual_start_index: 0, + } + } +} + +impl From for BacktraceFrame { + fn from(frame: crate::Frame) -> BacktraceFrame { + BacktraceFrame { + frame: Frame::Raw(frame), + symbols: None, + } + } +} + +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() as *mut c_void + } + + /// 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() as *mut c_void + } + + /// 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() + .map(|addr| addr as *mut c_void) + } + + /// 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(&[]) + } +} + +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 as *mut c_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 full = fmt.alternate(); + let (frames, style) = if full { + (&self.frames[..], PrintFmt::Full) + } else { + (&self.frames[self.actual_start_index..], 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 !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 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 = "serialize-rustc")] +mod rustc_serialize_impls { + use super::*; + use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + + #[derive(RustcEncodable, RustcDecodable)] + struct SerializedFrame { + ip: usize, + symbol_address: usize, + module_base_address: Option, + symbols: Option>, + } + + impl Decodable for BacktraceFrame { + fn decode(d: &mut D) -> Result + where + D: Decoder, + { + let frame: SerializedFrame = SerializedFrame::decode(d)?; + Ok(BacktraceFrame { + frame: Frame::Deserialized { + ip: frame.ip, + symbol_address: frame.symbol_address, + module_base_address: frame.module_base_address, + }, + symbols: frame.symbols, + }) + } + } + + impl Encodable for BacktraceFrame { + fn encode(&self, e: &mut E) -> Result<(), E::Error> + where + E: Encoder, + { + 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(|addr| addr as usize), + symbols: symbols.clone(), + } + .encode(e) + } + } +} + +#[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(|addr| addr 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: frame.ip, + symbol_address: frame.symbol_address, + module_base_address: frame.module_base_address, + }, + 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()); + } + } +} -- cgit v1.2.3