diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 35e3c1d4663..9534a107d16 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -60,6 +60,9 @@ extern "system" { type SymFromAddrFn = extern "system" fn(libc::HANDLE, u64, *mut u64, *mut SYMBOL_INFO) -> libc::BOOL; +type SymGetLineFromAddr64Fn = + extern "system" fn(libc::HANDLE, u64, *mut u32, + *mut IMAGEHLP_LINE64) -> libc::BOOL; type SymInitializeFn = extern "system" fn(libc::HANDLE, *mut libc::c_void, libc::BOOL) -> libc::BOOL; @@ -99,6 +102,14 @@ struct SYMBOL_INFO { Name: [libc::c_char; MAX_SYM_NAME], } +#[repr(C)] +struct IMAGEHLP_LINE64 { + SizeOfStruct: u32, + Key: *const libc::c_void, + LineNumber: u32, + Filename: *const libc::c_char, + Address: u64, +} #[repr(C)] enum ADDRESS_MODE { diff --git a/src/libstd/sys/windows/printing/msvc.rs b/src/libstd/sys/windows/printing/msvc.rs index 25cef04ca96..81d19374fea 100644 --- a/src/libstd/sys/windows/printing/msvc.rs +++ b/src/libstd/sys/windows/printing/msvc.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use sys_common::backtrace::output; +use sys_common::backtrace::{output, output_fileline}; use ffi::CStr; use dynamic_lib::DynamicLibrary; -use super::{SymFromAddrFn, SYMBOL_INFO, MAX_SYM_NAME}; +use super::{SymFromAddrFn, SymGetLineFromAddr64Fn, SYMBOL_INFO, MAX_SYM_NAME, IMAGEHLP_LINE64}; use io; use io::prelude::*; use intrinsics; @@ -20,6 +20,7 @@ use libc; pub fn print(w: &mut Write, i: isize, addr: u64, dbghelp: &DynamicLibrary, process: libc::HANDLE) -> io::Result<()> { let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn); + let SymGetLineFromAddr64 = sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn); let mut info: SYMBOL_INFO = unsafe { intrinsics::init() }; info.MaxNameLen = MAX_SYM_NAME as libc::c_ulong; @@ -29,7 +30,7 @@ pub fn print(w: &mut Write, i: isize, addr: u64, dbghelp: &DynamicLibrary, proce info.SizeOfStruct = 88; let mut displacement = 0u64; - let ret = SymFromAddr(process, addr as u64, &mut displacement, &mut info); + let ret = SymFromAddr(process, addr, &mut displacement, &mut info); let name = if ret == libc::TRUE { let ptr = info.Name.as_ptr() as *const libc::c_char; @@ -38,5 +39,20 @@ pub fn print(w: &mut Write, i: isize, addr: u64, dbghelp: &DynamicLibrary, proce None }; - output(w, i, addr as usize as *mut libc::c_void, name) + try!(output(w, i, addr as usize as *mut libc::c_void, name)); + + // Now find out the filename and line number + let mut line: IMAGEHLP_LINE64 = unsafe { intrinsics::init() }; + line.SizeOfStruct = ::mem::size_of::() as u32; + + let mut displacement = 0u32; + let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line); + if ret == libc::TRUE { + output_fileline(w, + unsafe { CStr::from_ptr(line.Filename).to_bytes() }, + line.LineNumber as libc::c_int, + false) + } else { + Ok(()) + } } diff --git a/src/test/run-pass/backtrace-debuginfo-aux.rs b/src/test/run-pass/backtrace-debuginfo-aux.rs index f0d36ea976e..48df600214a 100644 --- a/src/test/run-pass/backtrace-debuginfo-aux.rs +++ b/src/test/run-pass/backtrace-debuginfo-aux.rs @@ -15,7 +15,11 @@ pub fn callback(f: F) where F: FnOnce((&'static str, u32)) { f((file!(), line!())) } -#[inline(always)] +// LLVM does not yet output the required debug info to support showing inlined +// function calls in backtraces when targetting MSVC, so disable inlining in +// this case. +#[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)) { f((file!(), line!())) } diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index 5feca9422f6..b6400c68f53 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -32,7 +32,7 @@ macro_rules! pos { not(target_os = "ios"), not(target_os = "android"), not(all(target_os = "linux", target_arch = "arm"))), - all(windows, target_env = "gnu", not(target_arch = "x86"))))] + all(windows, not(target_arch = "x86"))))] macro_rules! dump_and_die { ($($pos:expr),*) => ({ // FIXME(#18285): we cannot include the current position because @@ -48,7 +48,7 @@ macro_rules! dump_and_die { not(target_os = "ios"), not(target_os = "android"), not(all(target_os = "linux", target_arch = "arm"))), - all(windows, target_env = "gnu", not(target_arch = "x86")))))] + all(windows, not(target_arch = "x86")))))] macro_rules! dump_and_die { ($($pos:expr),*) => ({ let _ = [$($pos),*]; }) } @@ -69,7 +69,10 @@ 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]) { - for &(file, line) in filelines.iter().rev() { + // 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) { // extract a basename let basename = file.split(&['/', '\\'][..]).last().unwrap(); println!("{}:{}", basename, line); @@ -88,12 +91,18 @@ fn inner(counter: &mut i32, main_pos: Pos, outer_pos: Pos) { }); } -#[inline(always)] +// LLVM does not yet output the required debug info to support showing inlined +// function calls in backtraces when targetting MSVC, so disable inlining in +// this case. +#[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) { check!(counter; main_pos, outer_pos); check!(counter; main_pos, outer_pos); - #[inline(always)] + // Again, disable inlining for MSVC. + #[cfg_attr(not(target_env = "msvc"), inline(always))] + #[cfg_attr(target_env = "msvc", inline(never))] fn inner_further_inlined(counter: &mut i32, main_pos: Pos, outer_pos: Pos, inner_pos: Pos) { check!(counter; main_pos, outer_pos, inner_pos); }