Skip to content

Commit 3245a47

Browse files
committed
Split separate stackwalk variants into their own functions
.. rather than having them be one giant match statement.
1 parent d39c66b commit 3245a47

File tree

2 files changed

+238
-204
lines changed

2 files changed

+238
-204
lines changed

Diff for: src/libstd/sys/windows/backtrace/mod.rs

+118-76
Original file line numberDiff line numberDiff line change
@@ -46,27 +46,38 @@ mod printing;
4646
#[path = "backtrace_gnu.rs"]
4747
pub mod gnu;
4848

49-
pub use self::printing::{resolve_symname, foreach_symbol_fileline};
49+
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
5050

5151
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
5252
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
5353

5454
// Fetch the symbols necessary from dbghelp.dll
5555
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
5656
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
57+
58+
// enum for holding the StackWalk function. Different from StackWalkVariant
59+
// below, since there's no need to pass the function itself into
60+
// the BacktraceContext
61+
enum sw_fn_local {
62+
SWExFn(StackWalkExFn),
63+
SW64Fn(StackWalk64Fn),
64+
}
5765
// StackWalkEx might not be present and we'll fall back to StackWalk64
58-
let ResStackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn);
59-
let ResStackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
66+
let (StackWalkFn, variant) =
67+
sym!(dbghelp, "StackWalkEx", StackWalkExFn)
68+
.map(|f| (sw_fn_local::SWExFn(f), StackWalkVariant::StackWalkEx))
69+
.or_else(|_|
70+
sym!(dbghelp, "StackWalk64", StackWalk64Fn)
71+
.map(|f| (sw_fn_local::SW64Fn(f), StackWalkVariant::StackWalk64))
72+
)?;
6073

6174
// Allocate necessary structures for doing the stack walk
6275
let process = unsafe { c::GetCurrentProcess() };
63-
let thread = unsafe { c::GetCurrentThread() };
64-
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
65-
unsafe { c::RtlCaptureContext(&mut context) };
6676

6777
let backtrace_context = BacktraceContext {
6878
handle: process,
6979
SymCleanup,
80+
StackWalkVariant: variant,
7081
dbghelp,
7182
};
7283

@@ -77,81 +88,102 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
7788
}
7889

7990
// And now that we're done with all the setup, do the stack walking!
80-
match (ResStackWalkEx, ResStackWalk64) {
81-
(Ok(StackWalkEx), _) => {
82-
let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() };
83-
frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
84-
let image = init_frame_ex(&mut frame, &context);
85-
86-
let mut i = 0;
87-
unsafe {
88-
while i < frames.len()
89-
&& StackWalkEx(
90-
image,
91-
process,
92-
thread,
93-
&mut frame,
94-
&mut context,
95-
ptr::null_mut(),
96-
ptr::null_mut(),
97-
ptr::null_mut(),
98-
ptr::null_mut(),
99-
0,
100-
) == c::TRUE
101-
{
102-
let addr = (frame.AddrPC.Offset - 1) as *const u8;
103-
104-
frames[i] = Frame {
105-
symbol_addr: addr,
106-
exact_position: addr,
107-
inline_context: frame.InlineFrameContext,
108-
};
109-
i += 1;
110-
}
111-
}
91+
match StackWalkFn {
92+
sw_fn_local::SWExFn(f) => set_frames_ex(f, frames, backtrace_context, process),
93+
sw_fn_local::SW64Fn(f) => set_frames_64(f, frames, backtrace_context, process),
94+
}
95+
}
11296

113-
Ok((i, backtrace_context))
97+
fn set_frames_ex(
98+
StackWalkEx: StackWalkExFn,
99+
frames: &mut [Frame],
100+
backtrace_context: BacktraceContext,
101+
process: c::HANDLE,
102+
) -> io::Result<(usize, BacktraceContext)> {
103+
let thread = unsafe { c::GetCurrentProcess() };
104+
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
105+
unsafe { c::RtlCaptureContext(&mut context) };
106+
107+
let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() };
108+
frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
109+
let image = init_frame_ex(&mut frame, &context);
110+
111+
let mut i = 0;
112+
unsafe {
113+
while i < frames.len()
114+
&& StackWalkEx(
115+
image,
116+
process,
117+
thread,
118+
&mut frame,
119+
&mut context,
120+
ptr::null_mut(),
121+
ptr::null_mut(),
122+
ptr::null_mut(),
123+
ptr::null_mut(),
124+
0,
125+
) == c::TRUE
126+
{
127+
let addr = (frame.AddrPC.Offset - 1) as *const u8;
128+
129+
frames[i] = Frame {
130+
symbol_addr: addr,
131+
exact_position: addr,
132+
inline_context: frame.InlineFrameContext,
133+
};
134+
i += 1;
114135
}
115-
(_, Ok(StackWalk64)) => {
116-
let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
117-
let image = init_frame_64(&mut frame, &context);
118-
119-
// Start from -1 to avoid printing this stack frame, which will
120-
// always be exactly the same.
121-
let mut i = 0;
122-
unsafe {
123-
while i < frames.len()
124-
&& StackWalk64(
125-
image,
126-
process,
127-
thread,
128-
&mut frame,
129-
&mut context,
130-
ptr::null_mut(),
131-
ptr::null_mut(),
132-
ptr::null_mut(),
133-
ptr::null_mut(),
134-
) == c::TRUE
135-
{
136-
let addr = frame.AddrPC.Offset;
137-
if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0
138-
{
139-
break;
140-
}
141-
142-
frames[i] = Frame {
143-
symbol_addr: (addr - 1) as *const u8,
144-
exact_position: (addr - 1) as *const u8,
145-
inline_context: 0,
146-
};
147-
i += 1;
148-
}
136+
}
137+
138+
Ok((i, backtrace_context))
139+
}
140+
141+
fn set_frames_64(
142+
StackWalk64: StackWalk64Fn,
143+
frames: &mut [Frame],
144+
backtrace_context: BacktraceContext,
145+
process: c::HANDLE,
146+
) -> io::Result<(usize, BacktraceContext)> {
147+
let thread = unsafe { c::GetCurrentProcess() };
148+
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
149+
unsafe { c::RtlCaptureContext(&mut context) };
150+
151+
let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
152+
let image = init_frame_64(&mut frame, &context);
153+
154+
// Start from -1 to avoid printing this stack frame, which will
155+
// always be exactly the same.
156+
let mut i = 0;
157+
unsafe {
158+
while i < frames.len()
159+
&& StackWalk64(
160+
image,
161+
process,
162+
thread,
163+
&mut frame,
164+
&mut context,
165+
ptr::null_mut(),
166+
ptr::null_mut(),
167+
ptr::null_mut(),
168+
ptr::null_mut(),
169+
) == c::TRUE
170+
{
171+
let addr = frame.AddrPC.Offset;
172+
if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0
173+
{
174+
break;
149175
}
150176

151-
Ok((i, backtrace_context))
177+
frames[i] = Frame {
178+
symbol_addr: (addr - 1) as *const u8,
179+
exact_position: (addr - 1) as *const u8,
180+
inline_context: 0,
181+
};
182+
i += 1;
152183
}
153-
(Err(e), _) => Err(e),
154184
}
185+
186+
Ok((i, backtrace_context))
155187
}
156188

157189
type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
@@ -226,16 +258,26 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
226258
c::IMAGE_FILE_MACHINE_AMD64
227259
}
228260

261+
enum StackWalkVariant {
262+
StackWalkEx,
263+
StackWalk64,
264+
}
265+
266+
229267
pub struct BacktraceContext {
230268
handle: c::HANDLE,
231269
SymCleanup: SymCleanupFn,
232270
// Only used in printing for msvc and not gnu
233271
#[allow(dead_code)]
272+
StackWalkVariant: StackWalkVariant,
273+
#[allow(dead_code)]
234274
dbghelp: DynamicLibrary,
235275
}
236276

237277
impl Drop for BacktraceContext {
238278
fn drop(&mut self) {
239-
unsafe { (self.SymCleanup)(self.handle); }
279+
unsafe {
280+
(self.SymCleanup)(self.handle);
281+
}
240282
}
241283
}

0 commit comments

Comments
 (0)