Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Print inlined functions on Windows #47252

Merged
merged 1 commit into from
Jan 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/libstd/sys/cloudabi/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions src/libstd/sys/redox/backtrace/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions src/libstd/sys/unix/backtrace/tracing/gcc_s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
31 changes: 15 additions & 16 deletions src/libstd/sys/windows/backtrace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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;
Expand Down
54 changes: 34 additions & 20 deletions src/libstd/sys/windows/backtrace/printing/msvc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,22 @@ 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<F>(frame: Frame,
callback: F,
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();
Expand All @@ -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 {
Expand All @@ -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)?;
Expand Down
4 changes: 3 additions & 1 deletion src/libstd/sys/windows/c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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)]
Expand Down
3 changes: 3 additions & 0 deletions src/libstd/sys_common/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) =
Expand Down
4 changes: 1 addition & 3 deletions src/test/run-pass/backtrace-debuginfo-aux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
12 changes: 2 additions & 10 deletions src/test/run-pass/backtrace-debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down