Skip to content

Commit a0b1501

Browse files
committed
Make stackwalking generic instead of matching on enum variants.
1 parent c0b280f commit a0b1501

File tree

1 file changed

+147
-133
lines changed
  • src/libstd/sys/windows/backtrace

1 file changed

+147
-133
lines changed

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

+147-133
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ mod printing;
4747
pub mod gnu;
4848

4949
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
50-
use self::printing::{load_printing_fns_ex, load_printing_fns_64};
50+
use self::printing::{load_printing_fns_64, load_printing_fns_ex};
5151

5252
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
5353
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
@@ -56,20 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
5656
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
5757
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
5858

59-
6059
// StackWalkEx might not be present and we'll fall back to StackWalk64
6160
let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
62-
Ok(StackWalkEx) =>
63-
StackWalkVariant::StackWalkEx(
64-
StackWalkEx,
65-
load_printing_fns_ex(&dbghelp)?,
66-
),
61+
Ok(StackWalkEx) => {
62+
StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?)
63+
}
6764
Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
68-
Ok(StackWalk64) =>
69-
StackWalkVariant::StackWalk64(
70-
StackWalk64,
71-
load_printing_fns_64(&dbghelp)?,
72-
),
65+
Ok(StackWalk64) => {
66+
StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?)
67+
}
7368
Err(..) => return Err(e),
7469
},
7570
};
@@ -92,101 +87,38 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
9287

9388
// And now that we're done with all the setup, do the stack walking!
9489
match backtrace_context.StackWalkVariant {
95-
StackWalkVariant::StackWalkEx(f, _) => set_frames_ex(f, frames, backtrace_context, process),
96-
StackWalkVariant::StackWalk64(f, _) => set_frames_64(f, frames, backtrace_context, process),
97-
}
98-
}
99-
100-
fn set_frames_ex(
101-
StackWalkEx: StackWalkExFn,
102-
frames: &mut [Frame],
103-
backtrace_context: BacktraceContext,
104-
process: c::HANDLE,
105-
) -> io::Result<(usize, BacktraceContext)> {
106-
let thread = unsafe { c::GetCurrentProcess() };
107-
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
108-
unsafe { c::RtlCaptureContext(&mut context) };
109-
110-
let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() };
111-
frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
112-
let image = init_frame_ex(&mut frame, &context);
90+
StackWalkVariant::StackWalkEx(StackWalkEx, _) => {
91+
set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context))
92+
}
11393

114-
let mut i = 0;
115-
unsafe {
116-
while i < frames.len()
117-
&& StackWalkEx(
118-
image,
119-
process,
120-
thread,
121-
&mut frame,
122-
&mut context,
123-
ptr::null_mut(),
124-
ptr::null_mut(),
125-
ptr::null_mut(),
126-
ptr::null_mut(),
127-
0,
128-
) == c::TRUE
129-
{
130-
let addr = (frame.AddrPC.Offset - 1) as *const u8;
131-
132-
frames[i] = Frame {
133-
symbol_addr: addr,
134-
exact_position: addr,
135-
inline_context: frame.InlineFrameContext,
136-
};
137-
i += 1;
94+
StackWalkVariant::StackWalk64(StackWalk64, _) => {
95+
set_frames(StackWalk64, frames).map(|i| (i, backtrace_context))
13896
}
13997
}
140-
141-
Ok((i, backtrace_context))
14298
}
14399

144-
fn set_frames_64(
145-
StackWalk64: StackWalk64Fn,
146-
frames: &mut [Frame],
147-
backtrace_context: BacktraceContext,
148-
process: c::HANDLE,
149-
) -> io::Result<(usize, BacktraceContext)> {
100+
fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> {
101+
let process = unsafe { c::GetCurrentProcess() };
150102
let thread = unsafe { c::GetCurrentProcess() };
151103
let mut context: c::CONTEXT = unsafe { mem::zeroed() };
152104
unsafe { c::RtlCaptureContext(&mut context) };
105+
let mut frame = W::Item::new();
106+
let image = frame.init(&context);
153107

154-
let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
155-
let image = init_frame_64(&mut frame, &context);
156-
157-
// Start from -1 to avoid printing this stack frame, which will
158-
// always be exactly the same.
159108
let mut i = 0;
160-
unsafe {
161-
while i < frames.len()
162-
&& StackWalk64(
163-
image,
164-
process,
165-
thread,
166-
&mut frame,
167-
&mut context,
168-
ptr::null_mut(),
169-
ptr::null_mut(),
170-
ptr::null_mut(),
171-
ptr::null_mut(),
172-
) == c::TRUE
173-
{
174-
let addr = frame.AddrPC.Offset;
175-
if addr == frame.AddrReturn.Offset || addr == 0 || frame.AddrReturn.Offset == 0
176-
{
177-
break;
178-
}
179-
180-
frames[i] = Frame {
181-
symbol_addr: (addr - 1) as *const u8,
182-
exact_position: (addr - 1) as *const u8,
183-
inline_context: 0,
184-
};
185-
i += 1;
186-
}
109+
while i < frames.len()
110+
&& StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
111+
{
112+
let addr = frame.get_addr();
113+
frames[i] = Frame {
114+
symbol_addr: addr,
115+
exact_position: addr,
116+
inline_context: 0,
117+
};
118+
119+
i += 1
187120
}
188-
189-
Ok((i, backtrace_context))
121+
Ok(i)
190122
}
191123

192124
type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
@@ -217,56 +149,138 @@ type StackWalk64Fn = unsafe extern "system" fn(
217149
*mut c_void,
218150
) -> c::BOOL;
219151

220-
#[cfg(target_arch = "x86")]
221-
fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD {
222-
frame.AddrPC.Offset = ctx.Eip as u64;
223-
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
224-
frame.AddrStack.Offset = ctx.Esp as u64;
225-
frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
226-
frame.AddrFrame.Offset = ctx.Ebp as u64;
227-
frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
228-
c::IMAGE_FILE_MACHINE_I386
152+
trait StackWalker {
153+
type Item: StackFrame;
154+
155+
fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL;
229156
}
230157

231-
#[cfg(target_arch = "x86_64")]
232-
fn init_frame_ex(frame: &mut c::STACKFRAME_EX, ctx: &c::CONTEXT) -> c::DWORD {
233-
frame.AddrPC.Offset = ctx.Rip as u64;
234-
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
235-
frame.AddrStack.Offset = ctx.Rsp as u64;
236-
frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
237-
frame.AddrFrame.Offset = ctx.Rbp as u64;
238-
frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
239-
c::IMAGE_FILE_MACHINE_AMD64
158+
impl StackWalker for StackWalkExFn {
159+
type Item = c::STACKFRAME_EX;
160+
fn walk(
161+
&self,
162+
image: c::DWORD,
163+
process: c::HANDLE,
164+
thread: c::HANDLE,
165+
frame: &mut Self::Item,
166+
context: &mut c::CONTEXT,
167+
) -> c::BOOL {
168+
unsafe {
169+
self(
170+
image,
171+
process,
172+
thread,
173+
frame,
174+
context,
175+
ptr::null_mut(),
176+
ptr::null_mut(),
177+
ptr::null_mut(),
178+
ptr::null_mut(),
179+
0,
180+
)
181+
}
182+
}
183+
}
184+
185+
impl StackWalker for StackWalk64Fn {
186+
type Item = c::STACKFRAME64;
187+
fn walk(
188+
&self,
189+
image: c::DWORD,
190+
process: c::HANDLE,
191+
thread: c::HANDLE,
192+
frame: &mut Self::Item,
193+
context: &mut c::CONTEXT,
194+
) -> c::BOOL {
195+
unsafe {
196+
self(
197+
image,
198+
process,
199+
thread,
200+
frame,
201+
context,
202+
ptr::null_mut(),
203+
ptr::null_mut(),
204+
ptr::null_mut(),
205+
ptr::null_mut(),
206+
)
207+
}
208+
}
209+
}
210+
211+
trait StackFrame {
212+
fn new() -> Self;
213+
fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD;
214+
fn get_addr(&self) -> *const u8;
240215
}
241216

242-
#[cfg(target_arch = "x86")]
243-
fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
244-
frame.AddrPC.Offset = ctx.Eip as u64;
245-
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
246-
frame.AddrStack.Offset = ctx.Esp as u64;
247-
frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
248-
frame.AddrFrame.Offset = ctx.Ebp as u64;
249-
frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
250-
c::IMAGE_FILE_MACHINE_I386
217+
impl StackFrame for c::STACKFRAME_EX {
218+
fn new() -> c::STACKFRAME_EX {
219+
unsafe { mem::zeroed() }
220+
}
221+
222+
#[cfg(target_arch = "x86")]
223+
fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
224+
self.AddrPC.Offset = ctx.Eip as u64;
225+
self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
226+
self.AddrStack.Offset = ctx.Esp as u64;
227+
self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
228+
self.AddrFrame.Offset = ctx.Ebp as u64;
229+
self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
230+
c::IMAGE_FILE_MACHINE_I386
231+
}
232+
#[cfg(target_arch = "x86_64")]
233+
fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
234+
self.AddrPC.Offset = ctx.Rip as u64;
235+
self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
236+
self.AddrStack.Offset = ctx.Rsp as u64;
237+
self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
238+
self.AddrFrame.Offset = ctx.Rbp as u64;
239+
self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
240+
c::IMAGE_FILE_MACHINE_AMD64
241+
}
242+
243+
fn get_addr(&self) -> *const u8 {
244+
(self.AddrPC.Offset - 1) as *const u8
245+
}
251246
}
252247

253-
#[cfg(target_arch = "x86_64")]
254-
fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
255-
frame.AddrPC.Offset = ctx.Rip as u64;
256-
frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
257-
frame.AddrStack.Offset = ctx.Rsp as u64;
258-
frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
259-
frame.AddrFrame.Offset = ctx.Rbp as u64;
260-
frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
261-
c::IMAGE_FILE_MACHINE_AMD64
248+
impl StackFrame for c::STACKFRAME64 {
249+
fn new() -> c::STACKFRAME64 {
250+
unsafe { mem::zeroed() }
251+
}
252+
253+
#[cfg(target_arch = "x86")]
254+
fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
255+
self.AddrPC.Offset = ctx.Eip as u64;
256+
self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
257+
self.AddrStack.Offset = ctx.Esp as u64;
258+
self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
259+
self.AddrFrame.Offset = ctx.Ebp as u64;
260+
self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
261+
c::IMAGE_FILE_MACHINE_I386
262+
}
263+
#[cfg(target_arch = "x86_64")]
264+
fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
265+
self.AddrPC.Offset = ctx.Rip as u64;
266+
self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
267+
self.AddrStack.Offset = ctx.Rsp as u64;
268+
self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
269+
self.AddrFrame.Offset = ctx.Rbp as u64;
270+
self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
271+
c::IMAGE_FILE_MACHINE_AMD64
272+
}
273+
274+
fn get_addr(&self) -> *const u8 {
275+
(self.AddrPC.Offset - 1) as *const u8
276+
}
262277
}
263278

264279
enum StackWalkVariant {
265280
StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
266281
StackWalk64(StackWalk64Fn, printing::PrintingFns64),
267282
}
268283

269-
270284
pub struct BacktraceContext {
271285
handle: c::HANDLE,
272286
SymCleanup: SymCleanupFn,

0 commit comments

Comments
 (0)