]> git.lizzy.rs Git - rust.git/commitdiff
Print inlined functions on Windows
authorJohn Kåre Alsaker <john.kare.alsaker@gmail.com>
Wed, 15 Nov 2017 17:01:09 +0000 (18:01 +0100)
committerJohn Kåre Alsaker <john.kare.alsaker@gmail.com>
Fri, 26 Jan 2018 03:49:54 +0000 (04:49 +0100)
src/libstd/sys/cloudabi/backtrace.rs
src/libstd/sys/redox/backtrace/tracing.rs
src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
src/libstd/sys/windows/backtrace/mod.rs
src/libstd/sys/windows/backtrace/printing/msvc.rs
src/libstd/sys/windows/c.rs
src/libstd/sys_common/backtrace.rs
src/test/run-pass/backtrace-debuginfo-aux.rs
src/test/run-pass/backtrace-debuginfo.rs

index 33d931792375d4270dd9966da933eeb7985d82a1..1b970187558c83603dfd039b4bd69cf71d71fd06 100644 (file)
@@ -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;
     }
index 0a174b3c3f58687b33d55a5769962d8f0491d823..bb70ca360370edce10f800bda91c9595f337db90 100644 (file)
@@ -98,6 +98,7 @@ pub fn unwind_backtrace(frames: &mut [Frame])
         cx.frames[cx.idx] = Frame {
             symbol_addr: symaddr as *mut u8,
             exact_position: ip as *mut u8,
+            inline_context: 0,
         };
         cx.idx += 1;
     }
index 400d39cd4bdcbcb93334cf73479cc11b19433050..6293eeb4ed649e327e1f899693fa88f3825d9b2c 100644 (file)
@@ -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))
index 000c08d2e0d198d33c81eb47eebf6f188a63ba3c..1b92fc0e6ad09d0e1f8d3b16b215e9061108a702 100644 (file)
@@ -98,6 +98,7 @@ pub fn unwind_backtrace(frames: &mut [Frame])
         cx.frames[cx.idx] = Frame {
             symbol_addr: symaddr as *mut u8,
             exact_position: ip as *mut u8,
+            inline_context: 0,
         };
         cx.idx += 1;
     }
index 176891fff23f8fbcd3fb2d8f3234a3159dca921b..82498ad4d58202bc1aeac8e014139f74a44dca33 100644 (file)
@@ -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 @@ pub fn unwind_backtrace(frames: &mut [Frame])
 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;
index 5a49b77af8e75a39c92d7b27a99e02d122c94cbd..967df1c8a2de9bddabf36dd4cbcc7eecb19ba674 100644 (file)
 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<F>(frame: Frame,
@@ -29,7 +29,9 @@ pub fn resolve_symname<F>(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<F>(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<F>(frame: Frame,
     -> io::Result<bool>
     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::<c::IMAGEHLP_LINE64>() 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)?;
index 66b44f1402fc6989df09805b7153d0b95b2cb651..6d929f21365cf65815baba420c586f2e7f32db89 100644 (file)
@@ -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)]
index 36cbce2df75b522b2cbf0b27afce88968d0bc6c9..a364a0392b39957d28c139b1e4a42c6c427f0360 100644 (file)
@@ -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) =
index 1236acf35112181ef840f2f65ee4199a19ec3b4d..cb7ef7e30062ccefc540bfd47d9da3ea45b83d15 100644 (file)
@@ -15,9 +15,7 @@ pub fn callback<F>(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: F) where F: FnOnce((&'static str, u32)) {
index 2f1c5c0574ad25b7b10bc26b820d5ad9ea1fc3fb..e8b5f3490e50e290ce6f2ec0d5fd2e9c28cda996 100644 (file)
@@ -62,10 +62,7 @@ macro_rules! check {
 // 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)