|  | #![allow(clippy::from_over_into)] | 
|  |  | 
|  | use crate::PrintFmt; | 
|  | #[cfg(feature = "serde")] | 
|  | use crate::resolve; | 
|  | use crate::{BacktraceFmt, Symbol, SymbolName, resolve_frame, trace}; | 
|  | 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: Box<[BacktraceFrame]>, | 
|  | } | 
|  |  | 
|  | #[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<D>(deserializer: D) -> Result<Self, D::Error> | 
|  | 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<E>(self, v: u8) -> Result<Self::Value, E> | 
|  | where | 
|  | E: serde::de::Error, | 
|  | { | 
|  | Ok(TracePtr(v as usize as *mut c_void)) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E> | 
|  | where | 
|  | E: serde::de::Error, | 
|  | { | 
|  | Ok(TracePtr(v as usize as *mut c_void)) | 
|  | } | 
|  |  | 
|  | #[inline] | 
|  | fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E> | 
|  | 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<E>(self, v: u64) -> Result<Self::Value, E> | 
|  | 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | 
|  | where | 
|  | S: serde::ser::Serializer, | 
|  | { | 
|  | serializer.serialize_u64(self.0 as usize as u64) | 
|  | } | 
|  | } | 
|  |  | 
|  | fn _assert_send_sync() { | 
|  | fn _assert<T: Send + Sync>() {} | 
|  | _assert::<Backtrace>(); | 
|  | } | 
|  |  | 
|  | /// 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<Box<[BacktraceSymbol]>>, | 
|  | } | 
|  |  | 
|  | #[derive(Clone)] | 
|  | enum Frame { | 
|  | Raw(crate::Frame), | 
|  | #[cfg(feature = "serde")] | 
|  | Deserialized { | 
|  | ip: TracePtr, | 
|  | symbol_address: TracePtr, | 
|  | module_base_address: Option<TracePtr>, | 
|  | }, | 
|  | } | 
|  |  | 
|  | 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) -> Box<[BacktraceSymbol]> { | 
|  | let mut symbols = Vec::new(); | 
|  | let sym = |symbol: &Symbol| { | 
|  | symbols.push(BacktraceSymbol { | 
|  | name: symbol.name().map(|m| m.as_bytes().into()), | 
|  | 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.into_boxed_slice() | 
|  | } | 
|  | } | 
|  |  | 
|  | /// 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<Box<[u8]>>, | 
|  | addr: Option<TracePtr>, | 
|  | filename: Option<PathBuf>, | 
|  | lineno: Option<u32>, | 
|  | colno: Option<u32>, | 
|  | } | 
|  |  | 
|  | 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: frames.into_boxed_slice(), | 
|  | } | 
|  | } | 
|  |  | 
|  | /// 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_ref() | 
|  | } | 
|  |  | 
|  | /// 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<Vec<BacktraceFrame>> for Backtrace { | 
|  | fn from(frames: Vec<BacktraceFrame>) -> Self { | 
|  | Backtrace { | 
|  | frames: frames.into_boxed_slice(), | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | impl From<crate::Frame> for BacktraceFrame { | 
|  | fn from(frame: crate::Frame) -> Self { | 
|  | BacktraceFrame { | 
|  | frame: Frame::Raw(frame), | 
|  | symbols: None, | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // we don't want to implement `impl From<Backtrace> for Vec<BacktraceFrame>` on purpose, | 
|  | // because "... additional directions for Vec<T> can weaken type inference ..." | 
|  | // more information on https://github.com/rust-lang/backtrace-rs/pull/526 | 
|  | impl Into<Vec<BacktraceFrame>> for Backtrace { | 
|  | fn into(self) -> Vec<BacktraceFrame> { | 
|  | self.frames.into_vec() | 
|  | } | 
|  | } | 
|  |  | 
|  | 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<SymbolName<'_>> { | 
|  | 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_deref() | 
|  | } | 
|  |  | 
|  | /// 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<u32> { | 
|  | 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<u32> { | 
|  | 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<usize>, | 
|  | symbols: Option<Box<[BacktraceSymbol]>>, | 
|  | } | 
|  |  | 
|  | impl Serialize for BacktraceFrame { | 
|  | fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> | 
|  | 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: D) -> Result<Self, D::Error> | 
|  | 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()); | 
|  | } | 
|  | } | 
|  | } |