cx.frames[cx.idx] = Frame {
symbol_addr: symaddr as *mut u8,
exact_position: ip as *mut u8,
+ inline_context: 0,
};
cx.idx += 1;
}
cx.frames[cx.idx] = Frame {
symbol_addr: symaddr as *mut u8,
exact_position: ip as *mut u8,
+ inline_context: 0,
};
cx.idx += 1;
}
*to = Frame {
exact_position: *from as *mut u8,
symbol_addr: *from as *mut u8,
+ inline_context: 0,
};
}
Ok((nb_frames as usize, BacktraceContext))
cx.frames[cx.idx] = Frame {
symbol_addr: symaddr as *mut u8,
exact_position: ip as *mut u8,
+ inline_context: 0,
};
cx.idx += 1;
}
// 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 {
}
// 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;
}
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;
}
#[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;
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,
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();
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 {
-> 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)?;
#[repr(C)]
#[cfg(feature = "backtrace")]
-pub struct STACKFRAME64 {
+pub struct STACKFRAME_EX {
pub AddrPC: ADDRESS64,
pub AddrReturn: ADDRESS64,
pub AddrFrame: ADDRESS64,
pub Virtual: BOOL,
pub Reserved: [u64; 3],
pub KdHelp: KDHELP64,
+ pub StackFrameSize: DWORD,
+ pub InlineFrameContext: DWORD,
}
#[repr(C)]
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.
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) =
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)) {
// 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);
});
}
-// 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) {
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)