From c31174f2519d1aa39e8f8e73dc7303e3422b33d0 Mon Sep 17 00:00:00 2001 From: Mindaugas Vinkelis Date: Wed, 17 May 2023 16:34:26 +0300 Subject: [PATCH] make it easy to resolve symbols by frame --- src/capture.rs | 96 ++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 43 deletions(-) diff --git a/src/capture.rs b/src/capture.rs index e0dd9c474..3494c2009 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -26,9 +26,6 @@ use serde::{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() { @@ -86,6 +83,27 @@ impl Frame { } => module_base_address.map(|addr| addr as *mut c_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(|a| a as usize), + filename: symbol.filename().map(|m| m.to_owned()), + lineno: symbol.lineno(), + colno: symbol.colno(), + }); + }; + match *self { + Frame::Raw(ref f) => resolve_frame(f, sym), + Frame::Deserialized { ip, .. } => { + resolve(ip as *mut c_void, sym); + } + } + symbols + } } /// Captured version of a symbol in a backtrace. @@ -172,23 +190,22 @@ impl Backtrace { 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()); + // clear inner frames, and start with call site. + if frame.symbol_address() as usize == ip { + frames.clear(); } + true }); + frames.shrink_to_fit(); - Backtrace { - frames, - actual_start_index: actual_start_index.unwrap_or(0), - } + Backtrace { frames } } /// Returns the frames from when this backtrace was captured. @@ -202,7 +219,7 @@ impl Backtrace { /// 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..] + self.frames.as_slice() } /// If this backtrace was created from `new_unresolved` then this function @@ -216,41 +233,18 @@ impl Backtrace { /// 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); - } + self.frames.iter_mut().for_each(BacktraceFrame::resolve); } } impl From> for Backtrace { fn from(frames: Vec) -> Self { - Backtrace { - frames, - actual_start_index: 0, - } + Backtrace { frames } } } impl From for BacktraceFrame { - fn from(frame: crate::Frame) -> BacktraceFrame { + fn from(frame: crate::Frame) -> Self { BacktraceFrame { frame: Frame::Raw(frame), symbols: None, @@ -258,6 +252,9 @@ impl From for BacktraceFrame { } } +// 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 @@ -314,6 +311,20 @@ impl BacktraceFrame { 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 { @@ -370,11 +381,10 @@ impl BacktraceSymbol { 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) + let style = if fmt.alternate() { + PrintFmt::Full } else { - (&self.frames[self.actual_start_index..], PrintFmt::Short) + PrintFmt::Short }; // When printing paths we try to strip the cwd if it exists, otherwise @@ -385,7 +395,7 @@ impl fmt::Debug for Backtrace { let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: crate::BytesOrWideString<'_>| { let path = path.into_path_buf(); - if !full { + if style == PrintFmt::Full { if let Ok(cwd) = &cwd { if let Ok(suffix) = path.strip_prefix(cwd) { return fmt::Display::fmt(&suffix.display(), fmt); @@ -397,7 +407,7 @@ impl fmt::Debug for Backtrace { let mut f = BacktraceFmt::new(fmt, style, &mut print_path); f.add_context()?; - for frame in frames { + for frame in &self.frames { f.frame().backtrace_frame(frame)?; } f.finish()?;