diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 4170d91e5fce2..c83cbd2e6b674 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -48,25 +48,38 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! { // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the // output binary, saving up to a few kilobytes. let (expr, file, line, col) = *expr_file_line_col; - panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col)) + panic_dispatch(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col), &(panic as usize)) } #[cold] #[inline(never)] #[lang = "panic_bounds_check"] fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), - index: usize, len: usize) -> ! { - panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", - len, index), file_line_col) + index: usize, len: usize) -> ! { + panic_dispatch(format_args!("index out of bounds: the len is {} but the index is {}", + len, index), + file_line_col, + &(panic_bounds_check as usize)) } #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + panic_dispatch(fmt, file_line_col, &(panic_fmt as usize)); +} + +#[cold] +fn panic_dispatch(fmt: fmt::Arguments, + file_line_col: &(&'static str, u32, u32), + entry_point: &usize) -> ! { #[allow(improper_ctypes)] extern { #[lang = "panic_fmt"] #[unwind] - fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; + fn panic_impl(fmt: fmt::Arguments, + file: &'static str, + line: u32, + col: u32, + entry_point: &usize) -> !; } let (file, line, col) = *file_line_col; - unsafe { panic_impl(fmt, file, line, col) } -} + unsafe { panic_impl(fmt, file, line, col, entry_point) } +} \ No newline at end of file diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 80ce15944a5c3..be18fae278c30 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -181,6 +181,7 @@ pub fn take_hook() -> Box { pub struct PanicInfo<'a> { payload: &'a (Any + Send), location: Location<'a>, + entry_point: usize, } impl<'a> PanicInfo<'a> { @@ -378,7 +379,7 @@ fn default_hook(info: &PanicInfo) { static FIRST_PANIC: AtomicBool = AtomicBool::new(true); if let Some(format) = log_backtrace { - let _ = backtrace::print(err, format); + let _ = backtrace::print(err, format, info.entry_point); } else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) { let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace."); } @@ -494,8 +495,9 @@ pub fn panicking() -> bool { pub extern fn rust_begin_panic(msg: fmt::Arguments, file: &'static str, line: u32, - col: u32) -> ! { - begin_panic_fmt(&msg, &(file, line, col)) + col: u32, + entry_point: &usize) -> ! { + rust_panic_fmt(&msg, &(file, line, col), entry_point) } /// The entry point for panicking with a formatted message. @@ -508,8 +510,14 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments, reason = "used by the panic! macro", issue = "0")] #[inline(never)] #[cold] -pub fn begin_panic_fmt(msg: &fmt::Arguments, - file_line_col: &(&'static str, u32, u32)) -> ! { +pub fn begin_panic_fmt(msg: &fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { + rust_panic_fmt(msg, file_line_col, &(begin_panic_fmt as usize)) +} + +#[cold] +fn rust_panic_fmt(msg: &fmt::Arguments, + file_line_col: &(&'static str, u32, u32), + entry_point: &usize) -> ! { use fmt::Write; // We do two allocations here, unfortunately. But (a) they're @@ -519,7 +527,7 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments, let mut s = String::new(); let _ = s.write_fmt(*msg); - begin_panic(s, file_line_col) + rust_panic_with_hook(Box::new(s), file_line_col, entry_point) } /// This is the entry point of panicking for panic!() and assert!(). @@ -535,7 +543,7 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 // be performed in the parent of this thread instead of the thread that's // panicking. - rust_panic_with_hook(Box::new(msg), file_line_col) + rust_panic_with_hook(Box::new(msg), file_line_col, &(begin_panic:: as usize)) } /// Executes the primary logic for a panic, including checking for recursive @@ -547,7 +555,8 @@ pub fn begin_panic(msg: M, file_line_col: &(&'static str, u32, u3 #[inline(never)] #[cold] fn rust_panic_with_hook(msg: Box, - file_line_col: &(&'static str, u32, u32)) -> ! { + file_line_col: &(&'static str, u32, u32), + entry_point: &usize) -> ! { let (file, line, col) = *file_line_col; let panics = update_panic_count(1); @@ -571,6 +580,7 @@ fn rust_panic_with_hook(msg: Box, line, col, }, + entry_point: *entry_point, }; HOOK_LOCK.read(); match HOOK { diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs index 40b24cedcdcf5..073d0b3e53d99 100644 --- a/src/libstd/rt.rs +++ b/src/libstd/rt.rs @@ -26,6 +26,14 @@ // Reexport 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::mark_start as mark_backtrace_start; + +#[cfg(not(feature = "backtrace"))] +pub fn mark_backtrace_start(f: &mut FnMut()) { + f(); +} + #[cfg(not(test))] #[lang = "start"] fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize { @@ -56,7 +64,8 @@ fn lang_start(main: fn(), argc: isize, argv: *const *const u8) -> isize { // Let's run some code! #[cfg(feature = "backtrace")] let res = panic::catch_unwind(|| { - ::sys_common::backtrace::__rust_begin_short_backtrace(main) + let mut main = main; + ::sys_common::backtrace::mark_start(&mut main) }); #[cfg(not(feature = "backtrace"))] let res = panic::catch_unwind(mem::transmute::<_, fn()>(main)); 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/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index 000c08d2e0d19..1b92fc0e6ad09 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -98,6 +98,7 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, cx.frames[cx.idx] = Frame { symbol_addr: symaddr as *mut u8, exact_position: ip as *mut u8, + inline_context: 0, }; cx.idx += 1; } diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 176891fff23f8..82498ad4d5820 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -56,14 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) // Fetch the symbols necessary from dbghelp.dll let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?; let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?; - let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?; + let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?; // Allocate necessary structures for doing the stack walk let process = unsafe { c::GetCurrentProcess() }; let thread = unsafe { c::GetCurrentThread() }; let mut context: c::CONTEXT = unsafe { mem::zeroed() }; unsafe { c::RtlCaptureContext(&mut context) }; - let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() }; + let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() }; + frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD; let image = init_frame(&mut frame, &context); let backtrace_context = BacktraceContext { @@ -79,24 +80,22 @@ pub fn unwind_backtrace(frames: &mut [Frame]) } // And now that we're done with all the setup, do the stack walking! - // Start from -1 to avoid printing this stack frame, which will - // always be exactly the same. let mut i = 0; unsafe { while i < frames.len() && - StackWalk64(image, process, thread, &mut frame, &mut context, + StackWalkEx(image, process, thread, &mut frame, &mut context, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), - ptr::null_mut()) == c::TRUE + ptr::null_mut(), + 0) == c::TRUE { - let addr = frame.AddrPC.Offset; - if addr == frame.AddrReturn.Offset || addr == 0 || - frame.AddrReturn.Offset == 0 { break } + let addr = (frame.AddrPC.Offset - 1) as *const u8; frames[i] = Frame { - symbol_addr: (addr - 1) as *const u8, - exact_position: (addr - 1) as *const u8, + symbol_addr: addr, + exact_position: addr, + inline_context: frame.InlineFrameContext, }; i += 1; } @@ -111,14 +110,14 @@ type SymInitializeFn = type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL; -type StackWalk64Fn = +type StackWalkExFn = unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE, - *mut c::STACKFRAME64, *mut c::CONTEXT, + *mut c::STACKFRAME_EX, *mut c::CONTEXT, *mut c_void, *mut c_void, - *mut c_void, *mut c_void) -> c::BOOL; + *mut c_void, *mut c_void, c::DWORD) -> c::BOOL; #[cfg(target_arch = "x86")] -fn init_frame(frame: &mut c::STACKFRAME64, +fn init_frame(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Eip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; @@ -130,7 +129,7 @@ fn init_frame(frame: &mut c::STACKFRAME64, } #[cfg(target_arch = "x86_64")] -fn init_frame(frame: &mut c::STACKFRAME64, +fn init_frame(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD { frame.AddrPC.Offset = ctx.Rip as u64; frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 5a49b77af8e75..a94bed1c01c7b 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -12,24 +12,27 @@ use ffi::CStr; use io; use libc::{c_ulong, c_char}; use mem; +use ptr; use sys::c; use sys::backtrace::BacktraceContext; use sys_common::backtrace::Frame; -type SymFromAddrFn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u64, - *mut c::SYMBOL_INFO) -> c::BOOL; -type SymGetLineFromAddr64Fn = - unsafe extern "system" fn(c::HANDLE, u64, *mut u32, - *mut c::IMAGEHLP_LINE64) -> c::BOOL; +type SymFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::DWORD, + *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymGetLineFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::DWORD, c::HMODULE, + *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL; /// Converts a pointer to symbol to its string value. 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 SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?; + let SymFromInlineContext = sym!(&context.dbghelp, + "SymFromInlineContext", + SymFromInlineContextFn)?; unsafe { let mut info: c::SYMBOL_INFO = mem::zeroed(); @@ -40,18 +43,30 @@ pub fn resolve_symname(frame: Frame, info.SizeOfStruct = 88; let mut displacement = 0u64; - let ret = SymFromAddr(context.handle, - frame.symbol_addr as u64, - &mut displacement, - &mut info); - - let symname = if ret == c::TRUE { + let ret = SymFromInlineContext(context.handle, + frame.symbol_addr as u64, + frame.inline_context, + &mut displacement, + &mut info); + let valid_range = if ret == c::TRUE && + frame.symbol_addr as usize >= info.Address as usize { + if info.Size != 0 { + (frame.symbol_addr as usize) < info.Address as usize + info.Size as usize + } else { + true + } + } else { + false + }; + 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, info.Address as usize) + }) } else { None }; - callback(symname) + callback(syminfo) } } @@ -61,19 +76,21 @@ pub fn foreach_symbol_fileline(frame: Frame, -> io::Result where F: FnMut(&[u8], u32) -> io::Result<()> { - let SymGetLineFromAddr64 = sym!(&context.dbghelp, - "SymGetLineFromAddr64", - SymGetLineFromAddr64Fn)?; + let SymGetLineFromInlineContext = sym!(&context.dbghelp, + "SymGetLineFromInlineContext", + SymGetLineFromInlineContextFn)?; unsafe { let mut line: c::IMAGEHLP_LINE64 = mem::zeroed(); line.SizeOfStruct = ::mem::size_of::() as u32; let mut displacement = 0u32; - let ret = SymGetLineFromAddr64(context.handle, - frame.exact_position as u64, - &mut displacement, - &mut line); + let ret = SymGetLineFromInlineContext(context.handle, + frame.exact_position as u64, + frame.inline_context, + ptr::null_mut(), + &mut displacement, + &mut line); if ret == c::TRUE { let name = CStr::from_ptr(line.Filename).to_bytes(); f(name, line.LineNumber as u32)?; diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 6e0cccff00193..29ac5f118c53d 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -624,7 +624,7 @@ pub struct ADDRESS64 { #[repr(C)] #[cfg(feature = "backtrace")] -pub struct STACKFRAME64 { +pub struct STACKFRAME_EX { pub AddrPC: ADDRESS64, pub AddrReturn: ADDRESS64, pub AddrFrame: ADDRESS64, @@ -636,6 +636,8 @@ pub struct STACKFRAME64 { pub Virtual: BOOL, pub Reserved: [u64; 3], pub KdHelp: KDHELP64, + pub StackFrameSize: DWORD, + pub InlineFrameContext: DWORD, } #[repr(C)] diff --git a/src/libstd/sys_common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index b5cf6d7d34fcc..0bed23ac85374 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -41,33 +41,36 @@ pub struct Frame { pub exact_position: *const u8, /// Address of the enclosing function. pub symbol_addr: *const u8, + /// Which inlined function is this frame referring to + pub inline_context: u32, } /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; /// Prints the current backtrace. -pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +pub fn print(w: &mut Write, format: PrintFormat, entry_point: usize) -> io::Result<()> { static LOCK: Mutex = Mutex::new(); // Use a lock to prevent mixed output in multithreading context. // Some platforms also requires it, like `SymFromAddr` on Windows. unsafe { LOCK.lock(); - let res = _print(w, format); + let res = _print(w, format, entry_point); LOCK.unlock(); res } } -fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { +fn _print(w: &mut Write, format: PrintFormat, entry_point: usize) -> io::Result<()> { let mut frames = [Frame { exact_position: ptr::null(), symbol_addr: ptr::null(), + inline_context: 0, }; MAX_NB_FRAMES]; let (nb_frames, context) = unwind_backtrace(&mut frames)?; let (skipped_before, skipped_after) = - filter_frames(&frames[..nb_frames], format, &context); + filter_frames(&frames[..nb_frames], format, &context, entry_point); if skipped_before + skipped_after > 0 { writeln!(w, "note: Some details are omitted, \ run with `RUST_BACKTRACE=full` for a verbose backtrace.")?; @@ -76,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) @@ -94,22 +97,32 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> { /// backtrace, according to the backtrace format. fn filter_frames(frames: &[Frame], format: PrintFormat, - context: &BacktraceContext) -> (usize, usize) + context: &BacktraceContext, + entry_point: usize) -> (usize, usize) { if format == PrintFormat::Full { return (0, 0); } - let skipped_before = 0; + // Look for the first occurence of a panic entry point + // Skip all frames before that + let skipped_before = frames.iter().position(|frame| { + let mut addr = None; + let _ = resolve_symname(*frame, |syminfo| { + addr = syminfo.map(|a| a.1); + Ok(()) + }, context); + addr == Some(entry_point) + }).map(|p| p + 1).unwrap_or(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); @@ -124,13 +137,16 @@ 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 + 'static, T: Send + 'static -{ - f() +#[unstable(feature = "rt", reason = "this is only exported for use in libtest", issue = "0")] +pub fn mark_start(f: &mut FnMut()) { + f(); + unsafe { + asm!("" ::: "memory" : "volatile"); // A dummy statement to prevent tail call optimization + } } /// 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 75c6bd5d2a2ba..8abf67967d7d8 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 = ptr::null(); - let data_addr = &mut data as *mut *const libc::c_char; + let mut data = (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..a579df14e72cc 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -403,7 +403,13 @@ 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) + let mut f = Some(f); + let mut r = None; + ::sys_common::backtrace::mark_start(&mut || { + let f = f.take().unwrap(); + r = Some(f()); + }); + r.unwrap() })); #[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 0d837c470a223..b79696b79556f 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; @@ -1331,14 +1332,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)) }) })) } @@ -1440,20 +1441,25 @@ pub fn run_test(opts: &TestOpts, } 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() +/// Clean the backtrace by using std::rt::mark_backtrace_start +fn begin_short_backtrace(f: F) { + let mut f = Some(f); + let mut r = None; + std::rt::mark_backtrace_start(&mut || { + let f = f.take().unwrap(); + r = Some(f()); + }); + r.unwrap() } fn calc_result(desc: &TestDesc, task_result: Result<(), Box>) -> TestResult {