Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update backtrace Debug formatting #261

Closed
wants to merge 17 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion examples/backtrace.rs
Original file line number Diff line number Diff line change
@@ -3,5 +3,9 @@ extern crate backtrace;
use backtrace::Backtrace;

fn main() {
println!("{:?}", Backtrace::new());
let backtrace = Backtrace::new();
println!("No Precision:\n{:?}\n", backtrace);
println!("No Precision Pretty:\n{:#?}\n", backtrace);
println!("Precision of 4:\n{:.4?}\n", backtrace);
println!("Precision of 4 Pretty:\n{:#.4?}", backtrace);
}
14 changes: 10 additions & 4 deletions src/capture.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::PrintFmt;
use crate::{resolve, resolve_frame, trace, BacktraceFmt, Symbol, SymbolName};
use crate::{resolve, resolve_frame, trace, BacktraceFmt, PrintFmt, Symbol, SymbolName};
use std::ffi::c_void;
use std::fmt;
use std::path::{Path, PathBuf};
@@ -327,12 +326,19 @@ impl BacktraceSymbol {
impl fmt::Debug for Backtrace {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let full = fmt.alternate();
let precision = fmt.precision();

let (frames, style) = if full {
(&self.frames[..], PrintFmt::Full)
} else {
(&self.frames[self.actual_start_index..], PrintFmt::Short)
};

let frames = match precision {
Some(precision) => &frames[..precision],
None => frames,
};

// 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
@@ -343,11 +349,11 @@ impl fmt::Debug for Backtrace {
if !full {
if let Ok(cwd) = &cwd {
if let Ok(suffix) = path.strip_prefix(cwd) {
return fmt::Display::fmt(&suffix.display(), fmt);
return write!(fmt, "{}", &suffix.display());
}
}
}
fmt::Display::fmt(&path.display(), fmt)
write!(fmt, "{}", &path.display())
};

let mut f = BacktraceFmt::new(fmt, style, &mut print_path);
61 changes: 28 additions & 33 deletions src/print.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::BytesOrWideString;
use cfg_if::cfg_if;
use core::ffi::c_void;
use core::fmt;

const HEX_WIDTH: usize = 2 + 2 * core::mem::size_of::<usize>();

#[cfg(target_os = "fuchsia")]
mod fuchsia;

@@ -57,9 +56,13 @@ impl<'a, 'b> BacktraceFmt<'a, 'b> {
/// sumbolicated later, and otherwise this should just be the first method
/// you call after creating a `BacktraceFmt`.
pub fn add_context(&mut self) -> fmt::Result {
self.fmt.write_str("stack backtrace:\n")?;
#[cfg(target_os = "fuchsia")]
fuchsia::print_dso_context(self.fmt)?;
cfg_if! {
if #[cfg(target_os = "fuchsia")] {
fuchsia::print_dso_context(self.fmt)?;
} else {
self.fmt.write_str("[")?;
}
}
Ok(())
}

@@ -69,18 +72,20 @@ impl<'a, 'b> BacktraceFmt<'a, 'b> {
/// to actually print a frame, and on destruction it will increment the
/// frame counter.
pub fn frame(&mut self) -> BacktraceFrameFmt<'_, 'a, 'b> {
let is_first_frame = self.frame_index == 0;
BacktraceFrameFmt {
fmt: self,
is_first_frame,
symbol_index: 0,
}
}

/// Completes the backtrace output.
///
/// This is currently a no-op but is added for future compatibility with
/// backtrace formats.
/// If not running on fuchsia, then close the list, otherwise this is a no-op.
pub fn finish(&mut self) -> fmt::Result {
// Currently a no-op-- including this hook to allow for future additions.
#[cfg(not(target_os = "fuchsia"))]
self.fmt.write_str("]")?;
Ok(())
}
}
@@ -90,6 +95,7 @@ impl<'a, 'b> BacktraceFmt<'a, 'b> {
/// This type is created by the `BacktraceFmt::frame` function.
pub struct BacktraceFrameFmt<'fmt, 'a, 'b> {
fmt: &'fmt mut BacktraceFmt<'a, 'b>,
is_first_frame: bool,
symbol_index: usize,
}

@@ -202,51 +208,40 @@ impl BacktraceFrameFmt<'_, '_, '_> {
frame_ip = usize::wrapping_sub(frame_ip as usize, image_base as _) as _;
}

// Print the index of the frame as well as the optional instruction
// pointer of the frame. If we're beyond the first symbol of this frame
// though we just print appropriate whitespace.
if self.symbol_index == 0 {
write!(self.fmt.fmt, "{:4}: ", self.fmt.frame_index)?;
if let PrintFmt::Full = self.fmt.format {
write!(self.fmt.fmt, "{:1$?} - ", frame_ip, HEX_WIDTH)?;
}
} else {
write!(self.fmt.fmt, " ")?;
if let PrintFmt::Full = self.fmt.format {
write!(self.fmt.fmt, "{:1$}", "", HEX_WIDTH + 3)?;
}
// If we are not printing the first frame, print a comma and space before opening the "map"
if !self.is_first_frame {
self.fmt.fmt.write_str(", ")?;
}
self.fmt.fmt.write_str("{ ")?;

// Next up write out the symbol name, using the alternate formatting for
// more information if we're a full backtrace. Here we also handle
// symbols which don't have a name,
match (symbol_name, &self.fmt.format) {
(Some(name), PrintFmt::Short) => write!(self.fmt.fmt, "{:#}", name)?,
(Some(name), PrintFmt::Full) => write!(self.fmt.fmt, "{}", name)?,
(None, _) | (_, PrintFmt::__Nonexhaustive) => write!(self.fmt.fmt, "<unknown>")?,
(Some(name), PrintFmt::Short) => write!(self.fmt.fmt, "function: \"{:#}\"", name)?,
(Some(name), PrintFmt::Full) => write!(self.fmt.fmt, "function: \"{}\"", name)?,
(None, _) | (_, PrintFmt::__Nonexhaustive) => {
write!(self.fmt.fmt, "function: \"<unknown>\"")?
}
}
self.fmt.fmt.write_str("\n")?;

// And last up, print out the filename/line number if they're available.
if let (Some(file), Some(line)) = (filename, lineno) {
self.print_fileline(file, line)?;
}

// Close the "map"
self.fmt.fmt.write_str(" }")?;

Ok(())
}

fn print_fileline(&mut self, file: BytesOrWideString, line: u32) -> fmt::Result {
// Filename/line are printed on lines under the symbol name, so print
// some appropriate whitespace to sort of right-align ourselves.
if let PrintFmt::Full = self.fmt.format {
write!(self.fmt.fmt, "{:1$}", "", HEX_WIDTH)?;
}
write!(self.fmt.fmt, " at ")?;

// Delegate to our internal callback to print the filename and then
// print out the line number.
self.fmt.fmt.write_str(", file: \"")?;
(self.fmt.print_path)(self.fmt.fmt, file)?;
write!(self.fmt.fmt, ":{}\n", line)?;
write!(self.fmt.fmt, "\", line: {}", line)?;
Ok(())
}