Skip to content

Commit 957c33c

Browse files
committed
Auto merge of #38165 - Yamakaky:better-backtrace, r=alexcrichton
Improve backtrace formating while panicking. Fixes #37783. Done: - Fix alignment of file paths for better readability - `RUST_BACKTRACE=full` prints all the informations (current behaviour) - `RUST_BACKTRACE=(short|yes)` is the default and does: - Skip irrelevant frames at the beginning and the end - Remove function address - Remove the current directory from the absolute paths - Remove `::hfabe6541873` at the end of the symbols - `RUST_BACKTRACE=(0|no)` disables the backtrace. - `RUST_BACKTRACE=<everything else>` is equivalent to `short` for backward compatibility. - doc - More uniform printing across platforms. Removed, TODO in a new PR: - Remove path prefix for libraries and libstd Example of short backtrace: ```rust fn fail() { panic!(); } fn main() { let closure = || fail(); closure(); } ``` Short: ``` thread 'main' panicked at 'explicit panic', t.rs:2 Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. stack backtrace: 0: t::fail at ./t.rs:2 1: t::main::{{closure}} at ./t.rs:6 2: t::main at ./t.rs:7 ``` Full: ``` thread 'main' panicked at 'This function never returns!', t.rs:2 stack backtrace: 0: 0x558ddf666478 - std::sys::imp::backtrace::tracing::imp::unwind_backtrace::hec84c9dd8389cc5d at /home/yamakaky/dev/rust/rust/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:49 1: 0x558ddf65d90e - std::sys_common::backtrace::_print::hfa25f8b31f4b4353 at /home/yamakaky/dev/rust/rust/src/libstd/sys_common/backtrace.rs:71 2: 0x558ddf65cb5e - std::sys_common::backtrace::print::h9b711e11ac3ba805 at /home/yamakaky/dev/rust/rust/src/libstd/sys_common/backtrace.rs:60 3: 0x558ddf66796e - std::panicking::default_hook::{{closure}}::h736d216e74748044 at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:355 4: 0x558ddf66743c - std::panicking::default_hook::h16baff397e46ea10 at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:371 5: 0x558ddf6682bc - std::panicking::rust_panic_with_hook::h6d5a9bb4eca42c80 at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:559 6: 0x558ddf64ea93 - std::panicking::begin_panic::h17dc549df2f10b99 at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:521 7: 0x558ddf64ec42 - t::diverges::he6bc43fc925905f5 at /tmp/p/t.rs:2 8: 0x558ddf64ec5a - t::main::h0ffc20356b8a69c0 at /tmp/p/t.rs:6 9: 0x558ddf6687f5 - core::ops::FnOnce::call_once::hce41f19c0db56f93 10: 0x558ddf667cde - std::panicking::try::do_call::hd4c8c97efb4291df at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:464 11: 0x558ddf698d77 - __rust_try 12: 0x558ddf698c57 - __rust_maybe_catch_panic at /home/yamakaky/dev/rust/rust/src/libpanic_unwind/lib.rs:98 13: 0x558ddf667adb - std::panicking::try::h2c56ed2a59ec1d12 at /home/yamakaky/dev/rust/rust/src/libstd/panicking.rs:440 14: 0x558ddf66cc9a - std::panic::catch_unwind::h390834e0251cc9af at /home/yamakaky/dev/rust/rust/src/libstd/panic.rs:361 15: 0x558ddf6809ee - std::rt::lang_start::hb73087428e233982 at /home/yamakaky/dev/rust/rust/src/libstd/rt.rs:57 16: 0x558ddf64ec92 - main 17: 0x7fecb869e290 - __libc_start_main 18: 0x558ddf64e8b9 - _start 19: 0x0 - <unknown> ```
2 parents 1572bf1 + 53a5d56 commit 957c33c

File tree

19 files changed

+816
-519
lines changed

19 files changed

+816
-519
lines changed

src/doc/book/src/functions.md

+14-1
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ If you want more information, you can get a backtrace by setting the
230230
```text
231231
$ RUST_BACKTRACE=1 ./diverges
232232
thread 'main' panicked at 'This function never returns!', hello.rs:2
233+
Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
234+
stack backtrace:
235+
hello::diverges
236+
at ./hello.rs:2
237+
hello::main
238+
at ./hello.rs:6
239+
```
240+
241+
If you want the complete backtrace and filenames:
242+
243+
```text
244+
$ RUST_BACKTRACE=full ./diverges
245+
thread 'main' panicked at 'This function never returns!', hello.rs:2
233246
stack backtrace:
234247
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
235248
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
@@ -262,7 +275,7 @@ note: Run with `RUST_BACKTRACE=1` for a backtrace.
262275
`RUST_BACKTRACE` also works with Cargo’s `run` command:
263276

264277
```text
265-
$ RUST_BACKTRACE=1 cargo run
278+
$ RUST_BACKTRACE=full cargo run
266279
Running `target/debug/diverges`
267280
thread 'main' panicked at 'This function never returns!', hello.rs:2
268281
stack backtrace:

src/libstd/panicking.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,11 @@ fn default_hook(info: &PanicInfo) {
320320
let log_backtrace = {
321321
let panics = update_panic_count(0);
322322

323-
panics >= 2 || backtrace::log_enabled()
323+
if panics >= 2 {
324+
Some(backtrace::PrintFormat::Full)
325+
} else {
326+
backtrace::log_enabled()
327+
}
324328
};
325329

326330
let file = info.location.file;
@@ -347,8 +351,8 @@ fn default_hook(info: &PanicInfo) {
347351

348352
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
349353

350-
if log_backtrace {
351-
let _ = backtrace::write(err);
354+
if let Some(format) = log_backtrace {
355+
let _ = backtrace::print(err, format);
352356
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
353357
let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
354358
}

src/libstd/sys/redox/backtrace.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@
1010

1111
use libc;
1212
use io;
13-
use sys_common::backtrace::output;
13+
use sys_common::backtrace::Frame;
14+
15+
pub use sys_common::gnu::libbacktrace::*;
16+
pub struct BacktraceContext;
1417

1518
#[inline(never)]
16-
pub fn write(w: &mut io::Write) -> io::Result<()> {
17-
output(w, 0, 0 as *mut libc::c_void, None)
19+
pub fn unwind_backtrace(frames: &mut [Frame])
20+
-> io::Result<(usize, BacktraceContext)>
21+
{
22+
Ok((0, BacktraceContext))
1823
}

src/libstd/sys/unix/backtrace/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@
8383
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
8484
/// all unix platforms we support right now, so it at least gets the job done.
8585
86-
pub use self::tracing::write;
86+
pub use self::tracing::unwind_backtrace;
87+
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
8788

8889
// tracing impls:
8990
mod tracing;
@@ -100,3 +101,5 @@ pub mod gnu {
100101
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
101102
}
102103
}
104+
105+
pub struct BacktraceContext;

src/libstd/sys/unix/backtrace/printing/dladdr.rs

+37-25
Original file line numberDiff line numberDiff line change
@@ -9,33 +9,45 @@
99
// except according to those terms.
1010

1111
use io;
12-
use io::prelude::*;
12+
use intrinsics;
13+
use ffi::CStr;
1314
use libc;
15+
use sys::backtrace::BacktraceContext;
16+
use sys_common::backtrace::Frame;
1417

15-
pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
16-
_symaddr: *mut libc::c_void) -> io::Result<()> {
17-
use sys_common::backtrace::{output};
18-
use intrinsics;
19-
use ffi::CStr;
20-
21-
#[repr(C)]
22-
struct Dl_info {
23-
dli_fname: *const libc::c_char,
24-
dli_fbase: *mut libc::c_void,
25-
dli_sname: *const libc::c_char,
26-
dli_saddr: *mut libc::c_void,
27-
}
28-
extern {
29-
fn dladdr(addr: *const libc::c_void,
30-
info: *mut Dl_info) -> libc::c_int;
18+
pub fn resolve_symname<F>(frame: Frame,
19+
callback: F,
20+
_: &BacktraceContext) -> io::Result<()>
21+
where F: FnOnce(Option<&str>) -> io::Result<()>
22+
{
23+
unsafe {
24+
let mut info: Dl_info = intrinsics::init();
25+
let symname = if dladdr(frame.exact_position, &mut info) == 0 {
26+
None
27+
} else {
28+
CStr::from_ptr(info.dli_sname).to_str().ok()
29+
};
30+
callback(symname)
3131
}
32+
}
3233

33-
let mut info: Dl_info = unsafe { intrinsics::init() };
34-
if unsafe { dladdr(addr, &mut info) == 0 } {
35-
output(w, idx,addr, None)
36-
} else {
37-
output(w, idx, addr, Some(unsafe {
38-
CStr::from_ptr(info.dli_sname).to_bytes()
39-
}))
40-
}
34+
pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame,
35+
_f: F,
36+
_: &BacktraceContext) -> io::Result<bool>
37+
where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
38+
{
39+
Ok(false)
40+
}
41+
42+
#[repr(C)]
43+
struct Dl_info {
44+
dli_fname: *const libc::c_char,
45+
dli_fbase: *mut libc::c_void,
46+
dli_sname: *const libc::c_char,
47+
dli_saddr: *mut libc::c_void,
48+
}
49+
50+
extern {
51+
fn dladdr(addr: *const libc::c_void,
52+
info: *mut Dl_info) -> libc::c_int;
4153
}

src/libstd/sys/unix/backtrace/printing/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
pub use self::imp::print;
11+
pub use self::imp::{foreach_symbol_fileline, resolve_symname};
1212

1313
#[cfg(any(target_os = "macos", target_os = "ios",
1414
target_os = "emscripten"))]
@@ -17,5 +17,6 @@ mod imp;
1717

1818
#[cfg(not(any(target_os = "macos", target_os = "ios",
1919
target_os = "emscripten")))]
20-
#[path = "gnu.rs"]
21-
mod imp;
20+
mod imp {
21+
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
22+
}

src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs

+22-29
Original file line numberDiff line numberDiff line change
@@ -18,39 +18,32 @@
1818
/// simple to use it should be used only on iOS devices as the only viable
1919
/// option.
2020
21-
use io::prelude::*;
2221
use io;
2322
use libc;
2423
use mem;
25-
use sys::mutex::Mutex;
24+
use sys::backtrace::BacktraceContext;
25+
use sys_common::backtrace::Frame;
2626

27-
use super::super::printing::print;
28-
29-
#[inline(never)]
30-
pub fn write(w: &mut Write) -> io::Result<()> {
31-
extern {
32-
fn backtrace(buf: *mut *mut libc::c_void,
33-
sz: libc::c_int) -> libc::c_int;
27+
#[inline(never)] // if we know this is a function call, we can skip it when
28+
// tracing
29+
pub fn unwind_backtrace(frames: &mut [Frame])
30+
-> io::Result<(usize, BacktraceContext)>
31+
{
32+
const FRAME_LEN: usize = 100;
33+
assert!(FRAME_LEN >= frames.len());
34+
let mut raw_frames = [::std::ptr::null_mut(); FRAME_LEN];
35+
let nb_frames = unsafe {
36+
backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
37+
} as usize;
38+
for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
39+
*to = Frame {
40+
exact_position: *from,
41+
symbol_addr: *from,
42+
};
3443
}
44+
Ok((nb_frames as usize, BacktraceContext))
45+
}
3546

36-
// while it doesn't requires lock for work as everything is
37-
// local, it still displays much nicer backtraces when a
38-
// couple of threads panic simultaneously
39-
static LOCK: Mutex = Mutex::new();
40-
unsafe {
41-
LOCK.lock();
42-
43-
writeln!(w, "stack backtrace:")?;
44-
// 100 lines should be enough
45-
const SIZE: usize = 100;
46-
let mut buf: [*mut libc::c_void; SIZE] = mem::zeroed();
47-
let cnt = backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize;
48-
49-
// skipping the first one as it is write itself
50-
for i in 1..cnt {
51-
print(w, i as isize, buf[i], buf[i])?
52-
}
53-
LOCK.unlock();
54-
}
55-
Ok(())
47+
extern {
48+
fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
5649
}

0 commit comments

Comments
 (0)