diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 8f945470b7e94..ea0228cc6b9ab 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 1955f3ec9a28f..49497590f4a4e 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,28 @@ 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(); + #[cfg(not(target_arch = "asmjs"))] + 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 formatted. 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 71aee673cfe3e..4bc226fe9bc54 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 b8be1aeff1742..855e96697b4bf 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -39,6 +39,7 @@ #![feature(panic_unwind)] #![feature(staged_api)] #![feature(termination_trait_lib)] +#![feature(rt)] extern crate getopts; #[cfg(any(unix, target_os = "cloudabi"))] @@ -73,6 +74,7 @@ use std::thread; use std::time::{Duration, Instant}; use std::borrow::Cow; use std::process; +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 @@ -1353,10 +1355,10 @@ pub fn convert_benchmarks_to_tests(tests: Vec) -> Vec DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b))) + bench::run_once(|b| begin_short_backtrace(|| bench.run(b))) })), StaticBenchFn(benchfn) => DynTestFn(Box::new(move || { - bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b))) + bench::run_once(|b| begin_short_backtrace(|| benchfn(b))) })), f => f, }; @@ -1443,24 +1445,18 @@ pub fn run_test( }); } DynTestFn(f) => { - let cb = move || __rust_begin_short_backtrace(f); + let cb = move || 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(())) | (&ShouldPanic::Yes, Err(_)) => TrOk,