Auto merge of #47252 - Zoxc:backtrace-win, r=alexcrichton
Print inlined functions on Windows Split from https://github.com/rust-lang/rust/pull/45637 r? @alexcrichton
This commit is contained in:
commit
a97cd17f5d
10 changed files with 62 additions and 50 deletions
|
@ -77,6 +77,7 @@ extern "C" fn trace_fn(
|
||||||
cx.frames[cx.idx] = Frame {
|
cx.frames[cx.idx] = Frame {
|
||||||
symbol_addr: symaddr as *mut u8,
|
symbol_addr: symaddr as *mut u8,
|
||||||
exact_position: ip as *mut u8,
|
exact_position: ip as *mut u8,
|
||||||
|
inline_context: 0,
|
||||||
};
|
};
|
||||||
cx.idx += 1;
|
cx.idx += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
|
||||||
cx.frames[cx.idx] = Frame {
|
cx.frames[cx.idx] = Frame {
|
||||||
symbol_addr: symaddr as *mut u8,
|
symbol_addr: symaddr as *mut u8,
|
||||||
exact_position: ip as *mut u8,
|
exact_position: ip as *mut u8,
|
||||||
|
inline_context: 0,
|
||||||
};
|
};
|
||||||
cx.idx += 1;
|
cx.idx += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ pub fn unwind_backtrace(frames: &mut [Frame])
|
||||||
*to = Frame {
|
*to = Frame {
|
||||||
exact_position: *from as *mut u8,
|
exact_position: *from as *mut u8,
|
||||||
symbol_addr: *from as *mut u8,
|
symbol_addr: *from as *mut u8,
|
||||||
|
inline_context: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Ok((nb_frames as usize, BacktraceContext))
|
Ok((nb_frames as usize, BacktraceContext))
|
||||||
|
|
|
@ -98,6 +98,7 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
|
||||||
cx.frames[cx.idx] = Frame {
|
cx.frames[cx.idx] = Frame {
|
||||||
symbol_addr: symaddr as *mut u8,
|
symbol_addr: symaddr as *mut u8,
|
||||||
exact_position: ip as *mut u8,
|
exact_position: ip as *mut u8,
|
||||||
|
inline_context: 0,
|
||||||
};
|
};
|
||||||
cx.idx += 1;
|
cx.idx += 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,14 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame])
|
||||||
// Fetch the symbols necessary from dbghelp.dll
|
// Fetch the symbols necessary from dbghelp.dll
|
||||||
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
|
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
|
||||||
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
|
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
|
// Allocate necessary structures for doing the stack walk
|
||||||
let process = unsafe { c::GetCurrentProcess() };
|
let process = unsafe { c::GetCurrentProcess() };
|
||||||
let thread = unsafe { c::GetCurrentThread() };
|
let thread = unsafe { c::GetCurrentThread() };
|
||||||
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
|
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
|
||||||
unsafe { c::RtlCaptureContext(&mut context) };
|
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 image = init_frame(&mut frame, &context);
|
||||||
|
|
||||||
let backtrace_context = BacktraceContext {
|
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!
|
// 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;
|
let mut i = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
while i < frames.len() &&
|
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(),
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
ptr::null_mut()) == c::TRUE
|
ptr::null_mut(),
|
||||||
|
0) == c::TRUE
|
||||||
{
|
{
|
||||||
let addr = frame.AddrPC.Offset;
|
let addr = (frame.AddrPC.Offset - 1) as *const u8;
|
||||||
if addr == frame.AddrReturn.Offset || addr == 0 ||
|
|
||||||
frame.AddrReturn.Offset == 0 { break }
|
|
||||||
|
|
||||||
frames[i] = Frame {
|
frames[i] = Frame {
|
||||||
symbol_addr: (addr - 1) as *const u8,
|
symbol_addr: addr,
|
||||||
exact_position: (addr - 1) as *const u8,
|
exact_position: addr,
|
||||||
|
inline_context: frame.InlineFrameContext,
|
||||||
};
|
};
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
@ -111,14 +110,14 @@ type SymInitializeFn =
|
||||||
type SymCleanupFn =
|
type SymCleanupFn =
|
||||||
unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
|
unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
|
||||||
|
|
||||||
type StackWalk64Fn =
|
type StackWalkExFn =
|
||||||
unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
|
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,
|
||||||
*mut c_void, *mut c_void) -> c::BOOL;
|
*mut c_void, *mut c_void, c::DWORD) -> c::BOOL;
|
||||||
|
|
||||||
#[cfg(target_arch = "x86")]
|
#[cfg(target_arch = "x86")]
|
||||||
fn init_frame(frame: &mut c::STACKFRAME64,
|
fn init_frame(frame: &mut c::STACKFRAME_EX,
|
||||||
ctx: &c::CONTEXT) -> c::DWORD {
|
ctx: &c::CONTEXT) -> c::DWORD {
|
||||||
frame.AddrPC.Offset = ctx.Eip as u64;
|
frame.AddrPC.Offset = ctx.Eip as u64;
|
||||||
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
|
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
|
||||||
|
@ -130,7 +129,7 @@ fn init_frame(frame: &mut c::STACKFRAME64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[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 {
|
ctx: &c::CONTEXT) -> c::DWORD {
|
||||||
frame.AddrPC.Offset = ctx.Rip as u64;
|
frame.AddrPC.Offset = ctx.Rip as u64;
|
||||||
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
|
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
|
||||||
|
|
|
@ -16,12 +16,12 @@ use sys::c;
|
||||||
use sys::backtrace::BacktraceContext;
|
use sys::backtrace::BacktraceContext;
|
||||||
use sys_common::backtrace::Frame;
|
use sys_common::backtrace::Frame;
|
||||||
|
|
||||||
type SymFromAddrFn =
|
type SymFromInlineContextFn =
|
||||||
unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
|
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
|
||||||
*mut c::SYMBOL_INFO) -> c::BOOL;
|
*mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
|
||||||
type SymGetLineFromAddr64Fn =
|
type SymGetLineFromInlineContextFn =
|
||||||
unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
|
unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
|
||||||
*mut c::IMAGEHLP_LINE64) -> c::BOOL;
|
u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
|
||||||
|
|
||||||
/// Converts a pointer to symbol to its string value.
|
/// Converts a pointer to symbol to its string value.
|
||||||
pub fn resolve_symname<F>(frame: Frame,
|
pub fn resolve_symname<F>(frame: Frame,
|
||||||
|
@ -29,7 +29,9 @@ pub fn resolve_symname<F>(frame: Frame,
|
||||||
context: &BacktraceContext) -> io::Result<()>
|
context: &BacktraceContext) -> io::Result<()>
|
||||||
where F: FnOnce(Option<&str>) -> io::Result<()>
|
where F: FnOnce(Option<&str>) -> io::Result<()>
|
||||||
{
|
{
|
||||||
let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
|
let SymFromInlineContext = sym!(&context.dbghelp,
|
||||||
|
"SymFromInlineContext",
|
||||||
|
SymFromInlineContextFn)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut info: c::SYMBOL_INFO = mem::zeroed();
|
let mut info: c::SYMBOL_INFO = mem::zeroed();
|
||||||
|
@ -40,12 +42,22 @@ pub fn resolve_symname<F>(frame: Frame,
|
||||||
info.SizeOfStruct = 88;
|
info.SizeOfStruct = 88;
|
||||||
|
|
||||||
let mut displacement = 0u64;
|
let mut displacement = 0u64;
|
||||||
let ret = SymFromAddr(context.handle,
|
let ret = SymFromInlineContext(context.handle,
|
||||||
frame.symbol_addr as u64,
|
frame.symbol_addr as u64,
|
||||||
&mut displacement,
|
frame.inline_context,
|
||||||
&mut info);
|
&mut displacement,
|
||||||
|
&mut info);
|
||||||
let symname = if ret == c::TRUE {
|
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;
|
let ptr = info.Name.as_ptr() as *const c_char;
|
||||||
CStr::from_ptr(ptr).to_str().ok()
|
CStr::from_ptr(ptr).to_str().ok()
|
||||||
} else {
|
} else {
|
||||||
|
@ -61,19 +73,21 @@ pub fn foreach_symbol_fileline<F>(frame: Frame,
|
||||||
-> io::Result<bool>
|
-> io::Result<bool>
|
||||||
where F: FnMut(&[u8], u32) -> io::Result<()>
|
where F: FnMut(&[u8], u32) -> io::Result<()>
|
||||||
{
|
{
|
||||||
let SymGetLineFromAddr64 = sym!(&context.dbghelp,
|
let SymGetLineFromInlineContext = sym!(&context.dbghelp,
|
||||||
"SymGetLineFromAddr64",
|
"SymGetLineFromInlineContext",
|
||||||
SymGetLineFromAddr64Fn)?;
|
SymGetLineFromInlineContextFn)?;
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
|
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
|
||||||
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
|
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
|
||||||
|
|
||||||
let mut displacement = 0u32;
|
let mut displacement = 0u32;
|
||||||
let ret = SymGetLineFromAddr64(context.handle,
|
let ret = SymGetLineFromInlineContext(context.handle,
|
||||||
frame.exact_position as u64,
|
frame.exact_position as u64,
|
||||||
&mut displacement,
|
frame.inline_context,
|
||||||
&mut line);
|
0,
|
||||||
|
&mut displacement,
|
||||||
|
&mut line);
|
||||||
if ret == c::TRUE {
|
if ret == c::TRUE {
|
||||||
let name = CStr::from_ptr(line.Filename).to_bytes();
|
let name = CStr::from_ptr(line.Filename).to_bytes();
|
||||||
f(name, line.LineNumber as u32)?;
|
f(name, line.LineNumber as u32)?;
|
||||||
|
|
|
@ -619,7 +619,7 @@ pub struct ADDRESS64 {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[cfg(feature = "backtrace")]
|
#[cfg(feature = "backtrace")]
|
||||||
pub struct STACKFRAME64 {
|
pub struct STACKFRAME_EX {
|
||||||
pub AddrPC: ADDRESS64,
|
pub AddrPC: ADDRESS64,
|
||||||
pub AddrReturn: ADDRESS64,
|
pub AddrReturn: ADDRESS64,
|
||||||
pub AddrFrame: ADDRESS64,
|
pub AddrFrame: ADDRESS64,
|
||||||
|
@ -631,6 +631,8 @@ pub struct STACKFRAME64 {
|
||||||
pub Virtual: BOOL,
|
pub Virtual: BOOL,
|
||||||
pub Reserved: [u64; 3],
|
pub Reserved: [u64; 3],
|
||||||
pub KdHelp: KDHELP64,
|
pub KdHelp: KDHELP64,
|
||||||
|
pub StackFrameSize: DWORD,
|
||||||
|
pub InlineFrameContext: DWORD,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
@ -41,6 +41,8 @@ pub struct Frame {
|
||||||
pub exact_position: *const u8,
|
pub exact_position: *const u8,
|
||||||
/// Address of the enclosing function.
|
/// Address of the enclosing function.
|
||||||
pub symbol_addr: *const u8,
|
pub symbol_addr: *const u8,
|
||||||
|
/// Which inlined function is this frame referring to
|
||||||
|
pub inline_context: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Max number of frames to print.
|
/// Max number of frames to print.
|
||||||
|
@ -64,6 +66,7 @@ fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
|
||||||
let mut frames = [Frame {
|
let mut frames = [Frame {
|
||||||
exact_position: ptr::null(),
|
exact_position: ptr::null(),
|
||||||
symbol_addr: ptr::null(),
|
symbol_addr: ptr::null(),
|
||||||
|
inline_context: 0,
|
||||||
}; MAX_NB_FRAMES];
|
}; MAX_NB_FRAMES];
|
||||||
let (nb_frames, context) = unwind_backtrace(&mut frames)?;
|
let (nb_frames, context) = unwind_backtrace(&mut frames)?;
|
||||||
let (skipped_before, skipped_after) =
|
let (skipped_before, skipped_after) =
|
||||||
|
|
|
@ -15,9 +15,7 @@ pub fn callback<F>(f: F) where F: FnOnce((&'static str, u32)) {
|
||||||
f((file!(), line!()))
|
f((file!(), line!()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVM does not yet output the required debug info to support showing inlined
|
// We emit the wrong location for the caller here when inlined on MSVC
|
||||||
// function calls in backtraces when targeting MSVC, so disable inlining in
|
|
||||||
// this case.
|
|
||||||
#[cfg_attr(not(target_env = "msvc"), inline(always))]
|
#[cfg_attr(not(target_env = "msvc"), inline(always))]
|
||||||
#[cfg_attr(target_env = "msvc", inline(never))]
|
#[cfg_attr(target_env = "msvc", inline(never))]
|
||||||
pub fn callback_inlined<F>(f: F) where F: FnOnce((&'static str, u32)) {
|
pub fn callback_inlined<F>(f: F) where F: FnOnce((&'static str, u32)) {
|
||||||
|
|
|
@ -62,10 +62,7 @@ type Pos = (&'static str, u32);
|
||||||
// this goes to stdout and each line has to be occurred
|
// this goes to stdout and each line has to be occurred
|
||||||
// in the following backtrace to stderr with a correct order.
|
// in the following backtrace to stderr with a correct order.
|
||||||
fn dump_filelines(filelines: &[Pos]) {
|
fn dump_filelines(filelines: &[Pos]) {
|
||||||
// Skip top frame for MSVC, because it sees the macro rather than
|
for &(file, line) in filelines.iter().rev() {
|
||||||
// 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
|
// extract a basename
|
||||||
let basename = file.split(&['/', '\\'][..]).last().unwrap();
|
let basename = file.split(&['/', '\\'][..]).last().unwrap();
|
||||||
println!("{}:{}", basename, line);
|
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
|
// We emit the wrong location for the caller here when inlined on MSVC
|
||||||
// function calls in backtraces when targeting MSVC, so disable inlining in
|
|
||||||
// this case.
|
|
||||||
#[cfg_attr(not(target_env = "msvc"), inline(always))]
|
#[cfg_attr(not(target_env = "msvc"), inline(always))]
|
||||||
#[cfg_attr(target_env = "msvc", inline(never))]
|
#[cfg_attr(target_env = "msvc", inline(never))]
|
||||||
fn inner_inlined(counter: &mut i32, main_pos: Pos, outer_pos: Pos) {
|
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::str;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
let mut template = Command::new(me);
|
|
||||||
template.env("RUST_BACKTRACE", "full");
|
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
loop {
|
loop {
|
||||||
let out = Command::new(me)
|
let out = Command::new(me)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue