From 634f8cc06a88eb978c5e52390014740c4bab1e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 15 Nov 2017 18:01:09 +0100 Subject: [PATCH] Print inlined functions on Windows --- src/libstd/sys/cloudabi/backtrace.rs | 1 + src/libstd/sys/redox/backtrace/tracing.rs | 1 + .../unix/backtrace/tracing/backtrace_fn.rs | 1 + .../sys/unix/backtrace/tracing/gcc_s.rs | 1 + src/libstd/sys/windows/backtrace/mod.rs | 31 ++++++----- .../sys/windows/backtrace/printing/msvc.rs | 54 ++++++++++++------- src/libstd/sys/windows/c.rs | 4 +- src/libstd/sys_common/backtrace.rs | 3 ++ src/test/run-pass/backtrace-debuginfo-aux.rs | 4 +- src/test/run-pass/backtrace-debuginfo.rs | 12 +---- 10 files changed, 62 insertions(+), 50 deletions(-) diff --git a/src/libstd/sys/cloudabi/backtrace.rs b/src/libstd/sys/cloudabi/backtrace.rs index 33d931792375d..1b970187558c8 100644 --- a/src/libstd/sys/cloudabi/backtrace.rs +++ b/src/libstd/sys/cloudabi/backtrace.rs @@ -77,6 +77,7 @@ extern "C" fn trace_fn( 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/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs index 0a174b3c3f586..bb70ca360370e 100644 --- a/src/libstd/sys/redox/backtrace/tracing.rs +++ b/src/libstd/sys/redox/backtrace/tracing.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/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs index 400d39cd4bdcb..6293eeb4ed649 100644 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -38,6 +38,7 @@ pub fn unwind_backtrace(frames: &mut [Frame]) *to = Frame { exact_position: *from as *mut u8, symbol_addr: *from as *mut u8, + inline_context: 0, }; } Ok((nb_frames as usize, BacktraceContext)) 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..967df1c8a2de9 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -16,12 +16,12 @@ 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::ULONG, + *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL; +type SymGetLineFromInlineContextFn = + unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, + u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL; /// Converts a pointer to symbol to its string value. pub fn resolve_symname(frame: Frame, @@ -29,7 +29,9 @@ pub fn resolve_symname(frame: Frame, context: &BacktraceContext) -> io::Result<()> where F: FnOnce(Option<&str>) -> 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,12 +42,22 @@ 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 symname = if valid_range { let ptr = info.Name.as_ptr() as *const c_char; CStr::from_ptr(ptr).to_str().ok() } else { @@ -61,19 +73,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, + 0, + &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 66b44f1402fc6..6d929f21365cf 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -619,7 +619,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, @@ -631,6 +631,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 36cbce2df75b5..a364a0392b399 100644 --- a/src/libstd/sys_common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs @@ -41,6 +41,8 @@ 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. @@ -64,6 +66,7 @@ fn _print(w: &mut Write, format: PrintFormat) -> 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) = diff --git a/src/test/run-pass/backtrace-debuginfo-aux.rs b/src/test/run-pass/backtrace-debuginfo-aux.rs index 1236acf351121..cb7ef7e30062c 100644 --- a/src/test/run-pass/backtrace-debuginfo-aux.rs +++ b/src/test/run-pass/backtrace-debuginfo-aux.rs @@ -15,9 +15,7 @@ pub fn callback(f: F) where F: FnOnce((&'static str, u32)) { f((file!(), line!())) } -// LLVM does not yet output the required debug info to support showing inlined -// function calls in backtraces when targeting MSVC, so disable inlining in -// this case. +// We emit the wrong location for the caller here when inlined on MSVC #[cfg_attr(not(target_env = "msvc"), inline(always))] #[cfg_attr(target_env = "msvc", inline(never))] pub fn callback_inlined(f: F) where F: FnOnce((&'static str, u32)) { diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 2f1c5c0574ad2..e8b5f3490e50e 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -62,10 +62,7 @@ type Pos = (&'static str, u32); // this goes to stdout and each line has to be occurred // in the following backtrace to stderr with a correct order. fn dump_filelines(filelines: &[Pos]) { - // Skip top frame for MSVC, because it sees the macro rather than - // the containing function. - let skip = if cfg!(target_env = "msvc") {1} else {0}; - for &(file, line) in filelines.iter().rev().skip(skip) { + for &(file, line) in filelines.iter().rev() { // extract a basename let basename = file.split(&['/', '\\'][..]).last().unwrap(); println!("{}:{}", basename, line); @@ -84,9 +81,7 @@ fn inner(counter: &mut i32, main_pos: Pos, outer_pos: Pos) { }); } -// LLVM does not yet output the required debug info to support showing inlined -// function calls in backtraces when targeting MSVC, so disable inlining in -// this case. +// We emit the wrong location for the caller here when inlined on MSVC #[cfg_attr(not(target_env = "msvc"), inline(always))] #[cfg_attr(target_env = "msvc", inline(never))] fn inner_inlined(counter: &mut i32, main_pos: Pos, outer_pos: Pos) { @@ -137,9 +132,6 @@ fn run_test(me: &str) { use std::str; use std::process::Command; - let mut template = Command::new(me); - template.env("RUST_BACKTRACE", "full"); - let mut i = 0; loop { let out = Command::new(me)