diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 9dbaf784f89e0..c0a06920e429a 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -26,6 +26,15 @@ // Re-export some of our utilities which are expected by other crates. pub use panicking::{begin_panic, begin_panic_fmt, update_panic_count}; +#[cfg(feature = "backtrace")] +pub use sys_common::backtrace::begin_short_backtrace; + +#[cfg(not(feature = "backtrace"))] +#[unstable(feature = "rt", reason = "this is only exported for use in libtest", issue = "0")] +pub fn begin_short_backtrace R, R>(f: F) -> R { + f() +} + // To reduce the generated code of the new `lang_start`, this function is doing // the real work. #[cfg(not(test))] @@ -56,7 +65,7 @@ fn lang_start_internal(main: &(Fn() -> i32 + Sync + ::panic::RefUnwindSafe), // Let's run some code! #[cfg(feature = "backtrace")] let exit_code = panic::catch_unwind(|| { - ::sys_common::backtrace::__rust_begin_short_backtrace(move || main()) + ::sys_common::backtrace::begin_short_backtrace(move || main()) }); #[cfg(not(feature = "backtrace"))] let exit_code = panic::catch_unwind(move || main()); diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs index 1b970187558c8..32ab77522943f 100644 --- a/src/libstd/sys/cloudabi/backtrace.rs +++ b/src/libstd/sys/cloudabi/backtrace.rs @@ -95,17 +95,17 @@ where pub fn resolve_symname(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()> where - F: FnOnce(Option<&str>) -> io::Result<()>, + F: FnOnce(Option<(&str, usize)>) -> io::Result<()>, { unsafe { let mut info: Dl_info = intrinsics::init(); - let symname = + let syminfo = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() { None } else { - CStr::from_ptr(info.dli_sname).to_str().ok() + CStr::from_ptr(info.dli_sname).to_str().ok().map(|s| (s, info.dli_saddr as usize)) }; - callback(symname) + callback(syminfo) } } diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs index bc56fd6594ea6..ad0452839922d 100644 --- a/src/libstd/sys/unix/backtrace/printing/dladdr.rs +++ b/src/libstd/sys/unix/backtrace/printing/dladdr.rs @@ -18,17 +18,17 @@ use sys_common::backtrace::Frame; pub fn resolve_symname(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> + where F: FnOnce(Option<(&str, usize)>) -> io::Result<()> { unsafe { let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || + let syminfo = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() { None } else { - CStr::from_ptr(info.dli_sname).to_str().ok() + CStr::from_ptr(info.dli_sname).to_str().ok().map(|s| (s, info.dli_saddr as usize)) }; - callback(symname) + callback(syminfo) } } diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs index caa60712b1d58..c4f52a27b0cd9 100644 --- a/src/libstd/sys/unix/backtrace/printing/mod.rs +++ b/src/libstd/sys/unix/backtrace/printing/mod.rs @@ -31,11 +31,11 @@ pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline; #[cfg(not(target_os = "emscripten"))] pub fn resolve_symname(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()> where - F: FnOnce(Option<&str>) -> io::Result<()> + F: FnOnce(Option<(&str, usize)>) -> io::Result<()> { - ::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| { - if symname.is_some() { - callback(symname) + ::sys_common::gnu::libbacktrace::resolve_symname(frame, |syminfo| { + if syminfo.is_some() { + callback(syminfo) } else { dladdr::resolve_symname(frame, callback, bc) } diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs index 9a8c48ff29fc7..7d6000212ebd6 100644 --- a/src/libstd/sys/wasm/backtrace.rs +++ b/src/libstd/sys/wasm/backtrace.rs @@ -23,7 +23,7 @@ pub fn unwind_backtrace(_frames: &mut [Frame]) pub fn resolve_symname(_frame: Frame, _callback: F, _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> + where F: FnOnce(Option<(&str, usize)>) -> io::Result<()> { unsupported() } diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 967df1c8a2de9..5f02100055ae6 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -27,7 +27,7 @@ type SymGetLineFromInlineContextFn = pub fn resolve_symname(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> + where F: FnOnce(Option<(&str, usize)>) -> io::Result<()> { let SymFromInlineContext = sym!(&context.dbghelp, "SymFromInlineContext", @@ -57,13 +57,15 @@ pub fn resolve_symname(frame: Frame, } else { false }; - let symname = if valid_range { + let syminfo = if valid_range { let ptr = info.Name.as_ptr() as *const c_char; - CStr::from_ptr(ptr).to_str().ok() + CStr::from_ptr(ptr).to_str().ok().map(|s| { + (s, (frame.symbol_addr as usize).wrapping_sub(displacement as usize)) + }) } else { None }; - callback(symname) + callback(syminfo) } } diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index a364a0392b399..52badc4c078b7 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -79,8 +79,8 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { let filtered_frames = &frames[..nb_frames - skipped_after]; for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() { - resolve_symname(*frame, |symname| { - output(w, index, *frame, symname, format) + resolve_symname(*frame, |syminfo| { + output(w, index, *frame, syminfo.map(|i| i.0), format) }, &context)?; let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| { output_fileline(w, file, line, format) @@ -105,14 +105,14 @@ fn filter_frames(frames: &[Frame], let skipped_before = 0; + // Look for the first occurence of `mark_start` + // There can be multiple in one backtrace + // Skip all frames after that let skipped_after = frames.len() - frames.iter().position(|frame| { let mut is_marker = false; - let _ = resolve_symname(*frame, |symname| { - if let Some(mangled_symbol_name) = symname { - // Use grep to find the concerned functions - if mangled_symbol_name.contains("__rust_begin_short_backtrace") { - is_marker = true; - } + let _ = resolve_symname(*frame, |syminfo| { + if syminfo.map(|i| i.1) == Some(MARK_START as usize) { + is_marker = true; } Ok(()) }, context); @@ -127,13 +127,27 @@ fn filter_frames(frames: &[Frame], (skipped_before, skipped_after) } +static MARK_START: fn(&mut FnMut()) = mark_start; -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. +/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1` #[inline(never)] -pub fn __rust_begin_short_backtrace(f: F) -> T - where F: FnOnce() -> T, F: Send, T: Send -{ - f() +fn mark_start(f: &mut FnMut()) { + f(); + unsafe { + asm!("" ::: "memory" : "volatile"); // A dummy statement to prevent tail call optimization + } +} + +/// Convenience wrapper for `mark_start` +#[unstable(feature = "rt", reason = "this is only exported for use in libtest", issue = "0")] +pub fn begin_short_backtrace R, R>(f: F) -> R { + let mut f = Some(f); + let mut r = None; + mark_start(&mut || { + let f = f.take().unwrap(); + r = Some(f()); + }); + r.unwrap() } /// Controls how the backtrace should be formated. diff --git a/src/libstd/sys_common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs index 6ad3af6aee1d5..8a9b49d85c6a1 100644 --- a/src/libstd/sys_common/gnu/libbacktrace.rs +++ b/src/libstd/sys_common/gnu/libbacktrace.rs @@ -63,9 +63,9 @@ where F: FnMut(&[u8], u32) -> io::Result<()> pub fn resolve_symname(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()> - where F: FnOnce(Option<&str>) -> io::Result<()> + where F: FnOnce(Option<(&str, usize)>) -> io::Result<()> { - let symname = { + let syminfo = { let state = unsafe { init_state() }; if state.is_null() { return Err(io::Error::new( @@ -73,8 +73,8 @@ pub fn resolve_symname(frame: Frame, "failed to allocate libbacktrace state") ) } - let mut data: *const libc::c_char = ptr::null(); - let data_addr = &mut data as *mut *const libc::c_char; + let mut data: (*const libc::c_char, _) = (ptr::null(), 0); + let data_addr = &mut data as *mut _; let ret = unsafe { backtrace_syminfo(state, frame.symbol_addr as libc::uintptr_t, @@ -82,15 +82,15 @@ pub fn resolve_symname(frame: Frame, error_cb, data_addr as *mut libc::c_void) }; - if ret == 0 || data.is_null() { + if ret == 0 || data.0.is_null() { None } else { unsafe { - CStr::from_ptr(data).to_str().ok() + CStr::from_ptr(data.0).to_str().ok().map(|s| (s, data.1)) } } }; - callback(symname) + callback(syminfo) } //////////////////////////////////////////////////////////////////////// @@ -145,10 +145,10 @@ extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char, extern fn syminfo_cb(data: *mut libc::c_void, _pc: libc::uintptr_t, symname: *const libc::c_char, - _symval: libc::uintptr_t, + symval: libc::uintptr_t, _symsize: libc::uintptr_t) { - let slot = data as *mut *const libc::c_char; - unsafe { *slot = symname; } + let slot = data as *mut (*const libc::c_char, usize); + unsafe { *slot = (symname, symval); } } extern fn pcinfo_cb(data: *mut libc::c_void, _pc: libc::uintptr_t, diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index ee49bf796b86f..caa3cfe6f9940 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -403,7 +403,7 @@ impl Builder { thread_info::set(imp::guard::current(), their_thread); #[cfg(feature = "backtrace")] let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { - ::sys_common::backtrace::__rust_begin_short_backtrace(f) + ::sys_common::backtrace::begin_short_backtrace(f) })); #[cfg(not(feature = "backtrace"))] let try_result = panic::catch_unwind(panic::AssertUnwindSafe(f)); diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index ffa27688cf1a7..8a1dd8562c261 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -40,6 +40,7 @@ #![feature(set_stdio)] #![feature(panic_unwind)] #![feature(staged_api)] +#![feature(rt)] extern crate getopts; extern crate term; @@ -72,6 +73,7 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time::{Instant, Duration}; use std::borrow::Cow; +use std::rt::begin_short_backtrace; const TEST_WARN_TIMEOUT_S: u64 = 60; const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode @@ -1344,14 +1346,14 @@ pub fn convert_benchmarks_to_tests(tests: Vec) -> Vec { DynTestFn(Box::new(move || { bench::run_once(|b| { - __rust_begin_short_backtrace(|| bench.run(b)) + begin_short_backtrace(|| bench.run(b)) }) })) } StaticBenchFn(benchfn) => { DynTestFn(Box::new(move || { bench::run_once(|b| { - __rust_begin_short_backtrace(|| benchfn(b)) + begin_short_backtrace(|| benchfn(b)) }) })) } @@ -1444,23 +1446,17 @@ pub fn run_test( } DynTestFn(f) => { let cb = move || { - __rust_begin_short_backtrace(f) + begin_short_backtrace(f) }; run_test_inner(desc, monitor_ch, opts.nocapture, Box::new(cb)) } StaticTestFn(f) => { run_test_inner(desc, monitor_ch, opts.nocapture, - Box::new(move || __rust_begin_short_backtrace(f))) + Box::new(move || begin_short_backtrace(f))) } } } -/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. -#[inline(never)] -fn __rust_begin_short_backtrace(f: F) { - f() -} - fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult { match (&desc.should_panic, task_result) { (&ShouldPanic::No, Ok(())) |