11
11
12
12
#![ allow( bad_style) ]
13
13
14
- use super :: super :: { dbghelp , windows:: * } ;
14
+ use super :: super :: windows:: * ;
15
15
use core:: ffi:: c_void;
16
- use core:: mem;
17
16
18
17
#[ derive( Clone , Copy ) ]
19
- pub enum StackFrame {
20
- New ( STACKFRAME_EX ) ,
21
- Old ( STACKFRAME64 ) ,
18
+ pub struct StackFrame {
19
+ ip : * mut c_void ,
22
20
}
23
21
24
22
#[ derive( Clone , Copy ) ]
@@ -34,11 +32,11 @@ unsafe impl Sync for Frame {}
34
32
35
33
impl Frame {
36
34
pub fn ip ( & self ) -> * mut c_void {
37
- self . addr_pc ( ) . Offset as * mut _
35
+ self . stack_frame . ip
38
36
}
39
37
40
38
pub fn sp ( & self ) -> * mut c_void {
41
- self . addr_stack ( ) . Offset as * mut _
39
+ core :: ptr :: null_mut ( )
42
40
}
43
41
44
42
pub fn symbol_address ( & self ) -> * mut c_void {
@@ -48,60 +46,12 @@ impl Frame {
48
46
pub fn module_base_address ( & self ) -> Option < * mut c_void > {
49
47
Some ( self . base_address )
50
48
}
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
- }
86
49
}
87
50
88
- #[ repr( C , align( 16 ) ) ] // required by `CONTEXT`, is a FIXME in winapi right now
89
- struct MyContext ( CONTEXT ) ;
90
-
91
51
#[ inline( always) ]
92
52
pub unsafe fn trace ( cb : & mut dyn FnMut ( & super :: Frame ) -> bool ) {
93
53
// Allocate necessary structures for doing the stack walk
94
54
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
- } ;
105
55
106
56
// On x86_64 and ARM64 we opt to not use the default `Sym*` functions from
107
57
// 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) {
114
64
cfg_if:: cfg_if! {
115
65
if #[ cfg( target_pointer_width = "64" ) ] {
116
66
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
-
123
67
unsafe extern "system" fn get_module_base( _process: HANDLE , addr: DWORD64 ) -> DWORD64 {
124
68
let mut base = 0 ;
125
69
RtlLookupFunctionEntry ( addr, & mut base, ptr:: null_mut( ) ) ;
126
70
base
127
71
}
128
72
} 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
+ } ;
130
79
let get_module_base = dbghelp. SymGetModuleBase64 ( ) ;
131
80
}
132
81
}
133
82
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 ;
172
114
}
173
115
}
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 ;
205
118
}
119
+ skip += len as u32 ;
206
120
}
207
121
}
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
- }
0 commit comments