Skip to content

Commit 13d806c

Browse files
committed
Print inlined functions on Windows
1 parent f5f8d0e commit 13d806c

File tree

5 files changed

+68
-46
lines changed

5 files changed

+68
-46
lines changed

src/libstd/sys/unix/backtrace/tracing/gcc_s.rs

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
9898
cx.frames[cx.idx] = Frame {
9999
symbol_addr: symaddr as *mut u8,
100100
exact_position: ip as *mut u8,
101+
inline_context: 0,
101102
};
102103
cx.idx += 1;
103104
}

src/libstd/sys/windows/backtrace/mod.rs

+15-16
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame])
5656
// Fetch the symbols necessary from dbghelp.dll
5757
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
5858
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
59-
let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?;
59+
let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?;
6060

6161
// Allocate necessary structures for doing the stack walk
6262
let process = unsafe { c::GetCurrentProcess() };
6363
let thread = unsafe { c::GetCurrentThread() };
6464
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
6565
unsafe { c::RtlCaptureContext(&mut context) };
66-
let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
66+
let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() };
67+
frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
6768
let image = init_frame(&mut frame, &context);
6869

6970
let backtrace_context = BacktraceContext {
@@ -79,24 +80,22 @@ pub fn unwind_backtrace(frames: &mut [Frame])
7980
}
8081

8182
// And now that we're done with all the setup, do the stack walking!
82-
// Start from -1 to avoid printing this stack frame, which will
83-
// always be exactly the same.
8483
let mut i = 0;
8584
unsafe {
8685
while i < frames.len() &&
87-
StackWalk64(image, process, thread, &mut frame, &mut context,
86+
StackWalkEx(image, process, thread, &mut frame, &mut context,
8887
ptr::null_mut(),
8988
ptr::null_mut(),
9089
ptr::null_mut(),
91-
ptr::null_mut()) == c::TRUE
90+
ptr::null_mut(),
91+
0) == c::TRUE
9292
{
93-
let addr = frame.AddrPC.Offset;
94-
if addr == frame.AddrReturn.Offset || addr == 0 ||
95-
frame.AddrReturn.Offset == 0 { break }
93+
let addr = (frame.AddrPC.Offset - 1) as *const u8;
9694

9795
frames[i] = Frame {
98-
symbol_addr: (addr - 1) as *const u8,
99-
exact_position: (addr - 1) as *const u8,
96+
symbol_addr: addr,
97+
exact_position: addr,
98+
inline_context: frame.InlineFrameContext,
10099
};
101100
i += 1;
102101
}
@@ -111,14 +110,14 @@ type SymInitializeFn =
111110
type SymCleanupFn =
112111
unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
113112

114-
type StackWalk64Fn =
113+
type StackWalkExFn =
115114
unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
116-
*mut c::STACKFRAME64, *mut c::CONTEXT,
115+
*mut c::STACKFRAME_EX, *mut c::CONTEXT,
117116
*mut c_void, *mut c_void,
118-
*mut c_void, *mut c_void) -> c::BOOL;
117+
*mut c_void, *mut c_void, c::DWORD) -> c::BOOL;
119118

120119
#[cfg(target_arch = "x86")]
121-
fn init_frame(frame: &mut c::STACKFRAME64,
120+
fn init_frame(frame: &mut c::STACKFRAME_EX,
122121
ctx: &c::CONTEXT) -> c::DWORD {
123122
frame.AddrPC.Offset = ctx.Eip as u64;
124123
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
@@ -130,7 +129,7 @@ fn init_frame(frame: &mut c::STACKFRAME64,
130129
}
131130

132131
#[cfg(target_arch = "x86_64")]
133-
fn init_frame(frame: &mut c::STACKFRAME64,
132+
fn init_frame(frame: &mut c::STACKFRAME_EX,
134133
ctx: &c::CONTEXT) -> c::DWORD {
135134
frame.AddrPC.Offset = ctx.Rip as u64;
136135
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;

src/libstd/sys/windows/backtrace/printing/msvc.rs

+36-21
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,27 @@ use ffi::CStr;
1212
use io;
1313
use libc::{c_ulong, c_char};
1414
use mem;
15+
use ptr;
1516
use sys::c;
1617
use sys::backtrace::BacktraceContext;
1718
use sys_common::backtrace::Frame;
1819

19-
type SymFromAddrFn =
20-
unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
21-
*mut c::SYMBOL_INFO) -> c::BOOL;
22-
type SymGetLineFromAddr64Fn =
23-
unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
24-
*mut c::IMAGEHLP_LINE64) -> c::BOOL;
20+
type SymFromInlineContextFn =
21+
unsafe extern "system" fn(c::HANDLE, u64, c::DWORD,
22+
*mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
23+
type SymGetLineFromInlineContextFn =
24+
unsafe extern "system" fn(c::HANDLE, u64, c::DWORD, c::HMODULE,
25+
*mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
2526

2627
/// Converts a pointer to symbol to its string value.
2728
pub fn resolve_symname<F>(frame: Frame,
2829
callback: F,
2930
context: &BacktraceContext) -> io::Result<()>
3031
where F: FnOnce(Option<(&str, usize)>) -> io::Result<()>
3132
{
32-
let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
33+
let SymFromInlineContext = sym!(&context.dbghelp,
34+
"SymFromInlineContext",
35+
SymFromInlineContextFn)?;
3336

3437
unsafe {
3538
let mut info: c::SYMBOL_INFO = mem::zeroed();
@@ -40,15 +43,25 @@ pub fn resolve_symname<F>(frame: Frame,
4043
info.SizeOfStruct = 88;
4144

4245
let mut displacement = 0u64;
43-
let ret = SymFromAddr(context.handle,
44-
frame.symbol_addr as u64,
45-
&mut displacement,
46-
&mut info);
47-
48-
let syminfo = if ret == c::TRUE {
46+
let ret = SymFromInlineContext(context.handle,
47+
frame.symbol_addr as u64,
48+
frame.inline_context,
49+
&mut displacement,
50+
&mut info);
51+
let valid_range = if ret == c::TRUE &&
52+
frame.symbol_addr as usize >= info.Address as usize {
53+
if info.Size != 0 {
54+
(frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
55+
} else {
56+
true
57+
}
58+
} else {
59+
false
60+
};
61+
let syminfo = if valid_range {
4962
let ptr = info.Name.as_ptr() as *const c_char;
5063
CStr::from_ptr(ptr).to_str().ok().map(|s| {
51-
(s, (frame.symbol_addr as usize).wrapping_sub(displacement as usize))
64+
(s, info.Address as usize)
5265
})
5366
} else {
5467
None
@@ -63,19 +76,21 @@ pub fn foreach_symbol_fileline<F>(frame: Frame,
6376
-> io::Result<bool>
6477
where F: FnMut(&[u8], u32) -> io::Result<()>
6578
{
66-
let SymGetLineFromAddr64 = sym!(&context.dbghelp,
67-
"SymGetLineFromAddr64",
68-
SymGetLineFromAddr64Fn)?;
79+
let SymGetLineFromInlineContext = sym!(&context.dbghelp,
80+
"SymGetLineFromInlineContext",
81+
SymGetLineFromInlineContextFn)?;
6982

7083
unsafe {
7184
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
7285
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
7386

7487
let mut displacement = 0u32;
75-
let ret = SymGetLineFromAddr64(context.handle,
76-
frame.exact_position as u64,
77-
&mut displacement,
78-
&mut line);
88+
let ret = SymGetLineFromInlineContext(context.handle,
89+
frame.exact_position as u64,
90+
frame.inline_context,
91+
ptr::null_mut(),
92+
&mut displacement,
93+
&mut line);
7994
if ret == c::TRUE {
8095
let name = CStr::from_ptr(line.Filename).to_bytes();
8196
f(name, line.LineNumber as u32)?;

src/libstd/sys/windows/c.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ pub struct ADDRESS64 {
624624

625625
#[repr(C)]
626626
#[cfg(feature = "backtrace")]
627-
pub struct STACKFRAME64 {
627+
pub struct STACKFRAME_EX {
628628
pub AddrPC: ADDRESS64,
629629
pub AddrReturn: ADDRESS64,
630630
pub AddrFrame: ADDRESS64,
@@ -636,6 +636,8 @@ pub struct STACKFRAME64 {
636636
pub Virtual: BOOL,
637637
pub Reserved: [u64; 3],
638638
pub KdHelp: KDHELP64,
639+
pub StackFrameSize: DWORD,
640+
pub InlineFrameContext: DWORD,
639641
}
640642

641643
#[repr(C)]

src/libstd/sys_common/backtrace.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub struct Frame {
4141
pub exact_position: *const u8,
4242
/// Address of the enclosing function.
4343
pub symbol_addr: *const u8,
44+
/// Which inlined function is this frame referring to
45+
pub inline_context: u32,
4446
}
4547

4648
/// Max number of frames to print.
@@ -64,6 +66,7 @@ fn _print(w: &mut Write, format: PrintFormat, entry_point: usize) -> io::Result<
6466
let mut frames = [Frame {
6567
exact_position: ptr::null(),
6668
symbol_addr: ptr::null(),
69+
inline_context: 0,
6770
}; MAX_NB_FRAMES];
6871
let (nb_frames, context) = unwind_backtrace(&mut frames)?;
6972
let (skipped_before, skipped_after) =
@@ -101,6 +104,8 @@ fn filter_frames(frames: &[Frame],
101104
return (0, 0);
102105
}
103106

107+
// Look for the first occurence of a panic entry point
108+
// Skip all frames before that
104109
let skipped_before = frames.iter().position(|frame| {
105110
let mut addr = None;
106111
let _ = resolve_symname(*frame, |syminfo| {
@@ -110,16 +115,19 @@ fn filter_frames(frames: &[Frame],
110115
addr == Some(entry_point)
111116
}).map(|p| p + 1).unwrap_or(0);
112117

113-
let skipped_after = frames.iter().rev().position(|frame| {
118+
// Look for the first occurence of `mark_start`
119+
// There can be multiple in one backtrace
120+
// Skip all frames after that
121+
let skipped_after = frames.len() - frames.iter().position(|frame| {
114122
let mut is_marker = false;
115123
let _ = resolve_symname(*frame, |syminfo| {
116-
if syminfo.map(|i| i.1) == Some(MARK_START.0 as usize) {
124+
if syminfo.map(|i| i.1) == Some(MARK_START as usize) {
117125
is_marker = true;
118126
}
119127
Ok(())
120128
}, context);
121129
is_marker
122-
}).map(|p| p + 1).unwrap_or(0);
130+
}).unwrap_or(frames.len());
123131

124132
if skipped_before + skipped_after >= frames.len() {
125133
// Avoid showing completely empty backtraces
@@ -129,14 +137,11 @@ fn filter_frames(frames: &[Frame],
129137
(skipped_before, skipped_after)
130138
}
131139

132-
#[derive(Eq, PartialEq)]
133-
struct Function(*const ());
134-
unsafe impl Sync for Function {}
135-
136-
static MARK_START: Function = Function(mark_start as *const ());
140+
static MARK_START: fn(&mut FnMut()) = mark_start;
137141

138142
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`
139143
#[inline(never)]
144+
#[unstable(feature = "rt", reason = "this is only exported for use in libtest", issue = "0")]
140145
pub fn mark_start(f: &mut FnMut()) {
141146
f();
142147
unsafe {

0 commit comments

Comments
 (0)