Skip to content

Commit 425b1ac

Browse files
committed
[WIP]
1 parent f3af31c commit 425b1ac

File tree

4 files changed

+49
-242
lines changed

4 files changed

+49
-242
lines changed

src/backtrace/dbghelp.rs

Lines changed: 45 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@
1111
1212
#![allow(bad_style)]
1313

14-
use super::super::{dbghelp, windows::*};
14+
use super::super::windows::*;
1515
use core::ffi::c_void;
16-
use core::mem;
1716

1817
#[derive(Clone, Copy)]
19-
pub enum StackFrame {
20-
New(STACKFRAME_EX),
21-
Old(STACKFRAME64),
18+
pub struct StackFrame {
19+
ip: *mut c_void,
2220
}
2321

2422
#[derive(Clone, Copy)]
@@ -34,11 +32,11 @@ unsafe impl Sync for Frame {}
3432

3533
impl Frame {
3634
pub fn ip(&self) -> *mut c_void {
37-
self.addr_pc().Offset as *mut _
35+
self.stack_frame.ip
3836
}
3937

4038
pub fn sp(&self) -> *mut c_void {
41-
self.addr_stack().Offset as *mut _
39+
core::ptr::null_mut()
4240
}
4341

4442
pub fn symbol_address(&self) -> *mut c_void {
@@ -48,60 +46,12 @@ impl Frame {
4846
pub fn module_base_address(&self) -> Option<*mut c_void> {
4947
Some(self.base_address)
5048
}
51-
52-
fn addr_pc(&self) -> &ADDRESS64 {
53-
match self.stack_frame {
54-
StackFrame::New(ref new) => &new.AddrPC,
55-
StackFrame::Old(ref old) => &old.AddrPC,
56-
}
57-
}
58-
59-
fn addr_pc_mut(&mut self) -> &mut ADDRESS64 {
60-
match self.stack_frame {
61-
StackFrame::New(ref mut new) => &mut new.AddrPC,
62-
StackFrame::Old(ref mut old) => &mut old.AddrPC,
63-
}
64-
}
65-
66-
fn addr_frame_mut(&mut self) -> &mut ADDRESS64 {
67-
match self.stack_frame {
68-
StackFrame::New(ref mut new) => &mut new.AddrFrame,
69-
StackFrame::Old(ref mut old) => &mut old.AddrFrame,
70-
}
71-
}
72-
73-
fn addr_stack(&self) -> &ADDRESS64 {
74-
match self.stack_frame {
75-
StackFrame::New(ref new) => &new.AddrStack,
76-
StackFrame::Old(ref old) => &old.AddrStack,
77-
}
78-
}
79-
80-
fn addr_stack_mut(&mut self) -> &mut ADDRESS64 {
81-
match self.stack_frame {
82-
StackFrame::New(ref mut new) => &mut new.AddrStack,
83-
StackFrame::Old(ref mut old) => &mut old.AddrStack,
84-
}
85-
}
8649
}
8750

88-
#[repr(C, align(16))] // required by `CONTEXT`, is a FIXME in winapi right now
89-
struct MyContext(CONTEXT);
90-
9151
#[inline(always)]
9252
pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
9353
// Allocate necessary structures for doing the stack walk
9454
let process = GetCurrentProcess();
95-
let thread = GetCurrentThread();
96-
97-
let mut context = mem::zeroed::<MyContext>();
98-
RtlCaptureContext(&mut context.0);
99-
100-
// Ensure this process's symbols are initialized
101-
let dbghelp = match dbghelp::init() {
102-
Ok(dbghelp) => dbghelp,
103-
Err(()) => return, // oh well...
104-
};
10555

10656
// On x86_64 and ARM64 we opt to not use the default `Sym*` functions from
10757
// dbghelp for getting the function table and module base. Instead we use
@@ -114,144 +64,58 @@ pub unsafe fn trace(cb: &mut dyn FnMut(&super::Frame) -> bool) {
11464
cfg_if::cfg_if! {
11565
if #[cfg(target_pointer_width = "64")] {
11666
use core::ptr;
117-
118-
unsafe extern "system" fn function_table_access(_process: HANDLE, addr: DWORD64) -> PVOID {
119-
let mut base = 0;
120-
RtlLookupFunctionEntry(addr, &mut base, ptr::null_mut()).cast()
121-
}
122-
12367
unsafe extern "system" fn get_module_base(_process: HANDLE, addr: DWORD64) -> DWORD64 {
12468
let mut base = 0;
12569
RtlLookupFunctionEntry(addr, &mut base, ptr::null_mut());
12670
base
12771
}
12872
} else {
129-
let function_table_access = dbghelp.SymFunctionTableAccess64();
73+
use super::super::dbghelp;
74+
// Ensure this process's symbols are initialized
75+
let dbghelp = match dbghelp::init() {
76+
Ok(dbghelp) => dbghelp,
77+
Err(()) => return, // oh well...
78+
};
13079
let get_module_base = dbghelp.SymGetModuleBase64();
13180
}
13281
}
13382

134-
let process_handle = GetCurrentProcess();
135-
136-
// Attempt to use `StackWalkEx` if we can, but fall back to `StackWalk64`
137-
// since it's in theory supported on more systems.
138-
match (*dbghelp.dbghelp()).StackWalkEx() {
139-
Some(StackWalkEx) => {
140-
let mut inner: STACKFRAME_EX = mem::zeroed();
141-
inner.StackFrameSize = mem::size_of::<STACKFRAME_EX>() as DWORD;
142-
let mut frame = super::Frame {
143-
inner: Frame {
144-
stack_frame: StackFrame::New(inner),
145-
base_address: 0 as _,
146-
},
147-
};
148-
let image = init_frame(&mut frame.inner, &context.0);
149-
let frame_ptr = match &mut frame.inner.stack_frame {
150-
StackFrame::New(ptr) => ptr as *mut STACKFRAME_EX,
151-
_ => unreachable!(),
152-
};
153-
154-
while StackWalkEx(
155-
image as DWORD,
156-
process,
157-
thread,
158-
frame_ptr,
159-
&mut context.0 as *mut CONTEXT as *mut _,
160-
None,
161-
Some(function_table_access),
162-
Some(get_module_base),
163-
None,
164-
0,
165-
) == TRUE
166-
{
167-
frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _;
168-
169-
if !cb(&frame) {
170-
break;
171-
}
83+
extern "system" {
84+
fn RtlCaptureStackBackTrace(
85+
FramesToSkip: u32,
86+
FramesToCapture: u32,
87+
BackTrace: *mut *mut c_void,
88+
BackTraceHash: *mut u32,
89+
) -> u16;
90+
}
91+
let mut frame = super::Frame {
92+
inner: Frame {
93+
stack_frame: StackFrame {
94+
ip: core::ptr::null_mut(),
95+
},
96+
base_address: 0 as _,
97+
},
98+
};
99+
const BUFFER_SIZE: u16 = 64;
100+
let mut backtrace = [core::ptr::null_mut(); BUFFER_SIZE as usize];
101+
let mut skip: u32 = 0;
102+
loop {
103+
let len = RtlCaptureStackBackTrace(
104+
skip,
105+
BUFFER_SIZE as u32,
106+
backtrace.as_mut_ptr(),
107+
core::ptr::null_mut(),
108+
);
109+
for &ip in backtrace[..len as usize].iter() {
110+
frame.inner.stack_frame.ip = ip;
111+
frame.inner.base_address = get_module_base(process, ip as _) as _;
112+
if !cb(&frame) {
113+
break;
172114
}
173115
}
174-
None => {
175-
let mut frame = super::Frame {
176-
inner: Frame {
177-
stack_frame: StackFrame::Old(mem::zeroed()),
178-
base_address: 0 as _,
179-
},
180-
};
181-
let image = init_frame(&mut frame.inner, &context.0);
182-
let frame_ptr = match &mut frame.inner.stack_frame {
183-
StackFrame::Old(ptr) => ptr as *mut STACKFRAME64,
184-
_ => unreachable!(),
185-
};
186-
187-
while dbghelp.StackWalk64()(
188-
image as DWORD,
189-
process,
190-
thread,
191-
frame_ptr,
192-
&mut context.0 as *mut CONTEXT as *mut _,
193-
None,
194-
Some(function_table_access),
195-
Some(get_module_base),
196-
None,
197-
) == TRUE
198-
{
199-
frame.inner.base_address = get_module_base(process_handle, frame.ip() as _) as _;
200-
201-
if !cb(&frame) {
202-
break;
203-
}
204-
}
116+
if len < BUFFER_SIZE || skip > u32::MAX - len as u32 {
117+
break;
205118
}
119+
skip += len as u32;
206120
}
207121
}
208-
209-
#[cfg(target_arch = "x86_64")]
210-
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
211-
frame.addr_pc_mut().Offset = ctx.Rip as u64;
212-
frame.addr_pc_mut().Mode = AddrModeFlat;
213-
frame.addr_stack_mut().Offset = ctx.Rsp as u64;
214-
frame.addr_stack_mut().Mode = AddrModeFlat;
215-
frame.addr_frame_mut().Offset = ctx.Rbp as u64;
216-
frame.addr_frame_mut().Mode = AddrModeFlat;
217-
218-
IMAGE_FILE_MACHINE_AMD64
219-
}
220-
221-
#[cfg(target_arch = "x86")]
222-
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
223-
frame.addr_pc_mut().Offset = ctx.Eip as u64;
224-
frame.addr_pc_mut().Mode = AddrModeFlat;
225-
frame.addr_stack_mut().Offset = ctx.Esp as u64;
226-
frame.addr_stack_mut().Mode = AddrModeFlat;
227-
frame.addr_frame_mut().Offset = ctx.Ebp as u64;
228-
frame.addr_frame_mut().Mode = AddrModeFlat;
229-
230-
IMAGE_FILE_MACHINE_I386
231-
}
232-
233-
#[cfg(target_arch = "aarch64")]
234-
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
235-
frame.addr_pc_mut().Offset = ctx.Pc as u64;
236-
frame.addr_pc_mut().Mode = AddrModeFlat;
237-
frame.addr_stack_mut().Offset = ctx.Sp as u64;
238-
frame.addr_stack_mut().Mode = AddrModeFlat;
239-
unsafe {
240-
frame.addr_frame_mut().Offset = ctx.u.s().Fp as u64;
241-
}
242-
frame.addr_frame_mut().Mode = AddrModeFlat;
243-
IMAGE_FILE_MACHINE_ARM64
244-
}
245-
246-
#[cfg(target_arch = "arm")]
247-
fn init_frame(frame: &mut Frame, ctx: &CONTEXT) -> WORD {
248-
frame.addr_pc_mut().Offset = ctx.Pc as u64;
249-
frame.addr_pc_mut().Mode = AddrModeFlat;
250-
frame.addr_stack_mut().Offset = ctx.Sp as u64;
251-
frame.addr_stack_mut().Mode = AddrModeFlat;
252-
unsafe {
253-
frame.addr_frame_mut().Offset = ctx.R11 as u64;
254-
}
255-
frame.addr_frame_mut().Mode = AddrModeFlat;
256-
IMAGE_FILE_MACHINE_ARMNT
257-
}

src/backtrace/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,6 @@ cfg_if::cfg_if! {
153153
mod dbghelp;
154154
use self::dbghelp::trace as trace_imp;
155155
pub(crate) use self::dbghelp::Frame as FrameImp;
156-
#[cfg(target_env = "msvc")] // only used in dbghelp symbolize
157-
pub(crate) use self::dbghelp::StackFrame;
158156
} else {
159157
mod noop;
160158
use self::noop::trace as trace_imp;

src/dbghelp.rs

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ use core::ptr;
3434
mod dbghelp {
3535
use crate::windows::*;
3636
pub use winapi::um::dbghelp::{
37-
StackWalk64, StackWalkEx, SymCleanup, SymFromAddrW, SymFunctionTableAccess64,
38-
SymGetLineFromAddrW64, SymGetModuleBase64, SymGetOptions, SymInitializeW, SymSetOptions,
37+
SymCleanup, SymFromAddrW, SymFunctionTableAccess64, SymGetLineFromAddrW64,
38+
SymGetModuleBase64, SymGetOptions, SymInitializeW, SymSetOptions,
3939
};
4040

4141
extern "system" {
@@ -165,17 +165,6 @@ dbghelp! {
165165
invade: BOOL
166166
) -> BOOL;
167167
fn SymCleanup(handle: HANDLE) -> BOOL;
168-
fn StackWalk64(
169-
MachineType: DWORD,
170-
hProcess: HANDLE,
171-
hThread: HANDLE,
172-
StackFrame: LPSTACKFRAME64,
173-
ContextRecord: PVOID,
174-
ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64,
175-
FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64,
176-
GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64,
177-
TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64
178-
) -> BOOL;
179168
fn SymFunctionTableAccess64(
180169
hProcess: HANDLE,
181170
AddrBase: DWORD64
@@ -196,18 +185,6 @@ dbghelp! {
196185
pdwDisplacement: PDWORD,
197186
Line: PIMAGEHLP_LINEW64
198187
) -> BOOL;
199-
fn StackWalkEx(
200-
MachineType: DWORD,
201-
hProcess: HANDLE,
202-
hThread: HANDLE,
203-
StackFrame: LPSTACKFRAME_EX,
204-
ContextRecord: PVOID,
205-
ReadMemoryRoutine: PREAD_PROCESS_MEMORY_ROUTINE64,
206-
FunctionTableAccessRoutine: PFUNCTION_TABLE_ACCESS_ROUTINE64,
207-
GetModuleBaseRoutine: PGET_MODULE_BASE_ROUTINE64,
208-
TranslateAddress: PTRANSLATE_ADDRESS_ROUTINE64,
209-
Flags: DWORD
210-
) -> BOOL;
211188
fn SymFromInlineContextW(
212189
hProcess: HANDLE,
213190
Address: DWORD64,

src/symbolize/dbghelp.rs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
1818
#![allow(bad_style)]
1919

20-
use super::super::{backtrace::StackFrame, dbghelp, windows::*};
20+
use super::super::{dbghelp, windows::*};
2121
use super::{BytesOrWideString, ResolveWhat, SymbolName};
2222
use core::char;
2323
use core::ffi::c_void;
@@ -80,42 +80,10 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
8080

8181
match what {
8282
ResolveWhat::Address(_) => resolve_without_inline(&dbghelp, what.address_or_ip(), cb),
83-
ResolveWhat::Frame(frame) => match &frame.inner.stack_frame {
84-
StackFrame::New(frame) => resolve_with_inline(&dbghelp, frame, cb),
85-
StackFrame::Old(_) => resolve_without_inline(&dbghelp, frame.ip(), cb),
86-
},
83+
ResolveWhat::Frame(frame) => resolve_without_inline(&dbghelp, frame.ip(), cb),
8784
}
8885
}
8986

90-
unsafe fn resolve_with_inline(
91-
dbghelp: &dbghelp::Init,
92-
frame: &STACKFRAME_EX,
93-
cb: &mut dyn FnMut(&super::Symbol),
94-
) {
95-
do_resolve(
96-
|info| {
97-
dbghelp.SymFromInlineContextW()(
98-
GetCurrentProcess(),
99-
super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64,
100-
frame.InlineFrameContext,
101-
&mut 0,
102-
info,
103-
)
104-
},
105-
|line| {
106-
dbghelp.SymGetLineFromInlineContextW()(
107-
GetCurrentProcess(),
108-
super::adjust_ip(frame.AddrPC.Offset as *mut _) as u64,
109-
frame.InlineFrameContext,
110-
0,
111-
&mut 0,
112-
line,
113-
)
114-
},
115-
cb,
116-
)
117-
}
118-
11987
unsafe fn resolve_without_inline(
12088
dbghelp: &dbghelp::Init,
12189
addr: *mut c_void,

0 commit comments

Comments
 (0)