Skip to content

Commit 290f5b2

Browse files
committed
Use backtrace formatting from the backtrace crate
1 parent 6c18a3d commit 290f5b2

File tree

4 files changed

+96
-153
lines changed

4 files changed

+96
-153
lines changed

Diff for: Cargo.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ dependencies = [
109109

110110
[[package]]
111111
name = "backtrace"
112-
version = "0.3.35"
112+
version = "0.3.37"
113113
source = "registry+https://github.com/rust-lang/crates.io-index"
114-
checksum = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55"
114+
checksum = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2"
115115
dependencies = [
116116
"backtrace-sys",
117117
"cfg-if",

Diff for: src/libstd/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ unwind = { path = "../libunwind" }
2626
hashbrown = { version = "0.5.0", features = ['rustc-dep-of-std'] }
2727

2828
[dependencies.backtrace]
29-
version = "0.3.35"
29+
version = "0.3.37"
3030
default-features = false # don't use coresymbolication on OSX
3131
features = [
3232
"rustc-dep-of-std", # enable build support for integrating into libstd

Diff for: src/libstd/panicking.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
158158

159159
fn default_hook(info: &PanicInfo<'_>) {
160160
#[cfg(feature = "backtrace")]
161-
use crate::sys_common::backtrace;
161+
use crate::sys_common::{backtrace as backtrace_mod};
162162

163163
// If this is a double panic, make sure that we print a backtrace
164164
// for this panic. Otherwise only print it if logging is enabled.
@@ -167,9 +167,9 @@ fn default_hook(info: &PanicInfo<'_>) {
167167
let panics = update_panic_count(0);
168168

169169
if panics >= 2 {
170-
Some(backtrace::PrintFormat::Full)
170+
Some(backtrace::PrintFmt::Full)
171171
} else {
172-
backtrace::log_enabled()
172+
backtrace_mod::log_enabled()
173173
}
174174
};
175175

@@ -197,7 +197,7 @@ fn default_hook(info: &PanicInfo<'_>) {
197197
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
198198

199199
if let Some(format) = log_backtrace {
200-
let _ = backtrace::print(err, format);
200+
let _ = backtrace_mod::print(err, format);
201201
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
202202
let _ = writeln!(err, "note: run with `RUST_BACKTRACE=1` \
203203
environment variable to display a backtrace.");

Diff for: src/libstd/sys_common/backtrace.rs

+89-146
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,20 @@
22
/// supported platforms.
33
44
use crate::env;
5+
use crate::fmt;
56
use crate::io;
67
use crate::io::prelude::*;
7-
use crate::mem;
88
use crate::path::{self, Path};
9-
use crate::ptr;
109
use crate::sync::atomic::{self, Ordering};
1110
use crate::sys::mutex::Mutex;
1211

13-
use backtrace::{BytesOrWideString, Frame, Symbol};
14-
15-
pub const HEX_WIDTH: usize = 2 + 2 * mem::size_of::<usize>();
12+
use backtrace::{BacktraceFmt, BytesOrWideString, PrintFmt};
1613

1714
/// Max number of frames to print.
1815
const MAX_NB_FRAMES: usize = 100;
1916

2017
/// Prints the current backtrace.
21-
pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
18+
pub fn print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
2219
static LOCK: Mutex = Mutex::new();
2320

2421
// There are issues currently linking libbacktrace into tests, and in
@@ -39,26 +36,66 @@ pub fn print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
3936
}
4037
}
4138

42-
fn _print(w: &mut dyn Write, format: PrintFormat) -> io::Result<()> {
43-
writeln!(w, "stack backtrace:")?;
39+
fn _print(w: &mut dyn Write, format: PrintFmt) -> io::Result<()> {
40+
struct DisplayBacktrace {
41+
format: PrintFmt,
42+
}
43+
impl fmt::Display for DisplayBacktrace {
44+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
45+
_print_fmt(fmt, self.format)
46+
}
47+
}
48+
write!(w, "{}", DisplayBacktrace { format })
49+
}
4450

45-
let mut printer = Printer::new(format, w);
51+
fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt::Result {
52+
let mut print_path = move |fmt: &mut fmt::Formatter<'_>, bows: BytesOrWideString<'_>| {
53+
output_filename(fmt, bows, print_fmt)
54+
};
55+
let mut bt_fmt = BacktraceFmt::new(fmt, print_fmt, &mut print_path);
56+
bt_fmt.add_context()?;
57+
let mut skipped = false;
4658
unsafe {
59+
let mut idx = 0;
60+
let mut res = Ok(());
4761
backtrace::trace_unsynchronized(|frame| {
62+
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
63+
skipped = true;
64+
return false;
65+
}
66+
4867
let mut hit = false;
68+
let mut stop = false;
4969
backtrace::resolve_frame_unsynchronized(frame, |symbol| {
5070
hit = true;
51-
printer.output(frame, Some(symbol));
71+
if print_fmt == PrintFmt::Short {
72+
if let Some(sym) = symbol.name().and_then(|s| s.as_str()) {
73+
if sym.contains("__rust_begin_short_backtrace") {
74+
skipped = true;
75+
stop = true;
76+
return;
77+
}
78+
}
79+
}
80+
81+
res = bt_fmt.frame().symbol(frame, symbol);
5282
});
83+
if stop {
84+
return false;
85+
}
5386
if !hit {
54-
printer.output(frame, None);
87+
res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
5588
}
56-
!printer.done
89+
90+
idx += 1;
91+
res.is_ok()
5792
});
93+
res?;
5894
}
59-
if printer.skipped {
95+
bt_fmt.finish()?;
96+
if skipped {
6097
writeln!(
61-
w,
98+
fmt,
6299
"note: Some details are omitted, \
63100
run with `RUST_BACKTRACE=full` for a verbose backtrace."
64101
)?;
@@ -77,33 +114,24 @@ where
77114
f()
78115
}
79116

80-
/// Controls how the backtrace should be formatted.
81-
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
82-
pub enum PrintFormat {
83-
/// Show only relevant data from the backtrace.
84-
Short = 2,
85-
/// Show all the frames with absolute path for files.
86-
Full = 3,
87-
}
88-
89117
// For now logging is turned off by default, and this function checks to see
90118
// whether the magical environment variable is present to see if it's turned on.
91-
pub fn log_enabled() -> Option<PrintFormat> {
119+
pub fn log_enabled() -> Option<PrintFmt> {
92120
static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
93121
match ENABLED.load(Ordering::SeqCst) {
94122
0 => {}
95123
1 => return None,
96-
2 => return Some(PrintFormat::Short),
97-
_ => return Some(PrintFormat::Full),
124+
2 => return Some(PrintFmt::Short),
125+
_ => return Some(PrintFmt::Full),
98126
}
99127

100128
let val = env::var_os("RUST_BACKTRACE").and_then(|x| {
101129
if &x == "0" {
102130
None
103131
} else if &x == "full" {
104-
Some(PrintFormat::Full)
132+
Some(PrintFmt::Full)
105133
} else {
106-
Some(PrintFormat::Short)
134+
Some(PrintFmt::Short)
107135
}
108136
});
109137
ENABLED.store(
@@ -116,130 +144,45 @@ pub fn log_enabled() -> Option<PrintFormat> {
116144
val
117145
}
118146

119-
struct Printer<'a, 'b> {
120-
format: PrintFormat,
121-
done: bool,
122-
skipped: bool,
123-
idx: usize,
124-
out: &'a mut (dyn Write + 'b),
125-
}
126-
127-
impl<'a, 'b> Printer<'a, 'b> {
128-
fn new(format: PrintFormat, out: &'a mut (dyn Write + 'b)) -> Printer<'a, 'b> {
129-
Printer { format, done: false, skipped: false, idx: 0, out }
130-
}
131-
132-
/// Prints the symbol of the backtrace frame.
133-
///
134-
/// These output functions should now be used everywhere to ensure consistency.
135-
/// You may want to also use `output_fileline`.
136-
fn output(&mut self, frame: &Frame, symbol: Option<&Symbol>) {
137-
if self.idx > MAX_NB_FRAMES {
138-
self.done = true;
139-
self.skipped = true;
140-
return;
141-
}
142-
if self._output(frame, symbol).is_err() {
143-
self.done = true;
144-
}
145-
self.idx += 1;
146-
}
147-
148-
fn _output(&mut self, frame: &Frame, symbol: Option<&Symbol>) -> io::Result<()> {
149-
if self.format == PrintFormat::Short {
150-
if let Some(sym) = symbol.and_then(|s| s.name()).and_then(|s| s.as_str()) {
151-
if sym.contains("__rust_begin_short_backtrace") {
152-
self.skipped = true;
153-
self.done = true;
154-
return Ok(());
155-
}
156-
}
157-
158-
// Remove the `17: 0x0 - <unknown>` line.
159-
if self.format == PrintFormat::Short && frame.ip() == ptr::null_mut() {
160-
self.skipped = true;
161-
return Ok(());
162-
}
163-
}
164-
165-
match self.format {
166-
PrintFormat::Full => {
167-
write!(self.out, " {:2}: {:2$?} - ", self.idx, frame.ip(), HEX_WIDTH)?
168-
}
169-
PrintFormat::Short => write!(self.out, " {:2}: ", self.idx)?,
170-
}
171-
172-
match symbol.and_then(|s| s.name()) {
173-
Some(symbol) => {
174-
match self.format {
175-
PrintFormat::Full => write!(self.out, "{}", symbol)?,
176-
// Strip the trailing hash if short mode.
177-
PrintFormat::Short => write!(self.out, "{:#}", symbol)?,
178-
}
179-
}
180-
None => self.out.write_all(b"<unknown>")?,
147+
/// Prints the filename of the backtrace frame.
148+
///
149+
/// See also `output`.
150+
fn output_filename(
151+
fmt: &mut fmt::Formatter<'_>,
152+
bows: BytesOrWideString<'_>,
153+
print_fmt: PrintFmt,
154+
) -> fmt::Result {
155+
#[cfg(windows)]
156+
let path_buf;
157+
let file = match bows {
158+
#[cfg(unix)]
159+
BytesOrWideString::Bytes(bytes) => {
160+
use crate::os::unix::prelude::*;
161+
Path::new(crate::ffi::OsStr::from_bytes(bytes))
181162
}
182-
self.out.write_all(b"\n")?;
183-
if let Some(sym) = symbol {
184-
self.output_fileline(sym)?;
163+
#[cfg(not(unix))]
164+
BytesOrWideString::Bytes(bytes) => {
165+
Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
185166
}
186-
Ok(())
187-
}
188-
189-
/// Prints the filename and line number of the backtrace frame.
190-
///
191-
/// See also `output`.
192-
fn output_fileline(&mut self, symbol: &Symbol) -> io::Result<()> {
193167
#[cfg(windows)]
194-
let path_buf;
195-
let file = match symbol.filename_raw() {
196-
#[cfg(unix)]
197-
Some(BytesOrWideString::Bytes(bytes)) => {
198-
use crate::os::unix::prelude::*;
199-
Path::new(crate::ffi::OsStr::from_bytes(bytes))
200-
}
201-
#[cfg(not(unix))]
202-
Some(BytesOrWideString::Bytes(bytes)) => {
203-
Path::new(crate::str::from_utf8(bytes).unwrap_or("<unknown>"))
204-
}
205-
#[cfg(windows)]
206-
Some(BytesOrWideString::Wide(wide)) => {
207-
use crate::os::windows::prelude::*;
208-
path_buf = crate::ffi::OsString::from_wide(wide);
209-
Path::new(&path_buf)
210-
}
211-
#[cfg(not(windows))]
212-
Some(BytesOrWideString::Wide(_wide)) => {
213-
Path::new("<unknown>")
214-
}
215-
None => return Ok(()),
216-
};
217-
let line = match symbol.lineno() {
218-
Some(line) => line,
219-
None => return Ok(()),
220-
};
221-
// prior line: " ##: {:2$} - func"
222-
self.out.write_all(b"")?;
223-
match self.format {
224-
PrintFormat::Full => write!(self.out, " {:1$}", "", HEX_WIDTH)?,
225-
PrintFormat::Short => write!(self.out, " ")?,
168+
BytesOrWideString::Wide(wide) => {
169+
use crate::os::windows::prelude::*;
170+
path_buf = crate::ffi::OsString::from_wide(wide);
171+
Path::new(&path_buf)
226172
}
227-
228-
let mut already_printed = false;
229-
if self.format == PrintFormat::Short && file.is_absolute() {
230-
if let Ok(cwd) = env::current_dir() {
231-
if let Ok(stripped) = file.strip_prefix(&cwd) {
232-
if let Some(s) = stripped.to_str() {
233-
write!(self.out, " at .{}{}:{}", path::MAIN_SEPARATOR, s, line)?;
234-
already_printed = true;
235-
}
173+
#[cfg(not(windows))]
174+
BytesOrWideString::Wide(_wide) => {
175+
Path::new("<unknown>")
176+
}
177+
};
178+
if print_fmt == PrintFmt::Short && file.is_absolute() {
179+
if let Ok(cwd) = env::current_dir() {
180+
if let Ok(stripped) = file.strip_prefix(&cwd) {
181+
if let Some(s) = stripped.to_str() {
182+
return write!(fmt, ".{}{}", path::MAIN_SEPARATOR, s);
236183
}
237184
}
238185
}
239-
if !already_printed {
240-
write!(self.out, " at {}:{}", file.display(), line)?;
241-
}
242-
243-
self.out.write_all(b"\n")
244186
}
187+
fmt::Display::fmt(&file.display(), fmt)
245188
}

0 commit comments

Comments
 (0)