@@ -46,110 +46,257 @@ mod printing;
46
46
#[ path = "backtrace_gnu.rs" ]
47
47
pub mod gnu;
48
48
49
- pub use self :: printing:: { resolve_symname, foreach_symbol_fileline} ;
49
+ pub use self :: printing:: { foreach_symbol_fileline, resolve_symname} ;
50
+ use self :: printing:: { load_printing_fns_64, load_printing_fns_ex} ;
50
51
51
- pub fn unwind_backtrace ( frames : & mut [ Frame ] )
52
- -> io:: Result < ( usize , BacktraceContext ) >
53
- {
52
+ pub fn unwind_backtrace ( frames : & mut [ Frame ] ) -> io:: Result < ( usize , BacktraceContext ) > {
54
53
let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
55
54
56
55
// Fetch the symbols necessary from dbghelp.dll
57
56
let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
58
57
let SymCleanup = sym ! ( dbghelp, "SymCleanup" , SymCleanupFn ) ?;
59
- let StackWalkEx = sym ! ( dbghelp, "StackWalkEx" , StackWalkExFn ) ?;
58
+
59
+ // StackWalkEx might not be present and we'll fall back to StackWalk64
60
+ let sw_var = match sym ! ( dbghelp, "StackWalkEx" , StackWalkExFn ) {
61
+ Ok ( StackWalkEx ) => {
62
+ StackWalkVariant :: StackWalkEx ( StackWalkEx , load_printing_fns_ex ( & dbghelp) ?)
63
+ }
64
+ Err ( e) => match sym ! ( dbghelp, "StackWalk64" , StackWalk64Fn ) {
65
+ Ok ( StackWalk64 ) => {
66
+ StackWalkVariant :: StackWalk64 ( StackWalk64 , load_printing_fns_64 ( & dbghelp) ?)
67
+ }
68
+ Err ( ..) => return Err ( e) ,
69
+ } ,
70
+ } ;
60
71
61
72
// Allocate necessary structures for doing the stack walk
62
73
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) } ;
66
- let mut frame: c:: STACKFRAME_EX = unsafe { mem:: zeroed ( ) } ;
67
- frame. StackFrameSize = mem:: size_of_val ( & frame) as c:: DWORD ;
68
- let image = init_frame ( & mut frame, & context) ;
69
74
70
75
let backtrace_context = BacktraceContext {
71
76
handle : process,
72
77
SymCleanup ,
78
+ StackWalkVariant : sw_var,
73
79
dbghelp,
74
80
} ;
75
81
76
82
// Initialize this process's symbols
77
83
let ret = unsafe { SymInitialize ( process, ptr:: null_mut ( ) , c:: TRUE ) } ;
78
84
if ret != c:: TRUE {
79
- return Ok ( ( 0 , backtrace_context) )
85
+ return Ok ( ( 0 , backtrace_context) ) ;
80
86
}
81
87
82
88
// And now that we're done with all the setup, do the stack walking!
89
+ match backtrace_context. StackWalkVariant {
90
+ StackWalkVariant :: StackWalkEx ( StackWalkEx , _) => {
91
+ set_frames ( StackWalkEx , frames) . map ( |i| ( i, backtrace_context) )
92
+ }
93
+
94
+ StackWalkVariant :: StackWalk64 ( StackWalk64 , _) => {
95
+ set_frames ( StackWalk64 , frames) . map ( |i| ( i, backtrace_context) )
96
+ }
97
+ }
98
+ }
99
+
100
+ fn set_frames < W : StackWalker > ( StackWalk : W , frames : & mut [ Frame ] ) -> io:: Result < usize > {
101
+ let process = unsafe { c:: GetCurrentProcess ( ) } ;
102
+ let thread = unsafe { c:: GetCurrentProcess ( ) } ;
103
+ let mut context: c:: CONTEXT = unsafe { mem:: zeroed ( ) } ;
104
+ unsafe { c:: RtlCaptureContext ( & mut context) } ;
105
+ let mut frame = W :: Item :: new ( ) ;
106
+ let image = frame. init ( & context) ;
107
+
83
108
let mut i = 0 ;
84
- unsafe {
85
- while i < frames. len ( ) &&
86
- StackWalkEx ( image, process, thread, & mut frame, & mut context,
87
- ptr:: null_mut ( ) ,
88
- ptr:: null_mut ( ) ,
89
- ptr:: null_mut ( ) ,
90
- ptr:: null_mut ( ) ,
91
- 0 ) == c:: TRUE
92
- {
93
- let addr = ( frame. AddrPC . Offset - 1 ) as * const u8 ;
94
-
95
- frames[ i] = Frame {
96
- symbol_addr : addr,
97
- exact_position : addr,
98
- inline_context : frame. InlineFrameContext ,
99
- } ;
100
- i += 1 ;
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
120
+ }
121
+ Ok ( i)
122
+ }
123
+
124
+ type SymInitializeFn = unsafe extern "system" fn ( c:: HANDLE , * mut c_void , c:: BOOL ) -> c:: BOOL ;
125
+ type SymCleanupFn = unsafe extern "system" fn ( c:: HANDLE ) -> c:: BOOL ;
126
+
127
+ type StackWalkExFn = unsafe extern "system" fn (
128
+ c:: DWORD ,
129
+ c:: HANDLE ,
130
+ c:: HANDLE ,
131
+ * mut c:: STACKFRAME_EX ,
132
+ * mut c:: CONTEXT ,
133
+ * mut c_void ,
134
+ * mut c_void ,
135
+ * mut c_void ,
136
+ * mut c_void ,
137
+ c:: DWORD ,
138
+ ) -> c:: BOOL ;
139
+
140
+ type StackWalk64Fn = unsafe extern "system" fn (
141
+ c:: DWORD ,
142
+ c:: HANDLE ,
143
+ c:: HANDLE ,
144
+ * mut c:: STACKFRAME64 ,
145
+ * mut c:: CONTEXT ,
146
+ * mut c_void ,
147
+ * mut c_void ,
148
+ * mut c_void ,
149
+ * mut c_void ,
150
+ ) -> c:: BOOL ;
151
+
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 ;
156
+ }
157
+
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
+ )
101
181
}
102
182
}
183
+ }
103
184
104
- Ok ( ( i, backtrace_context) )
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
+ }
105
209
}
106
210
107
- type SymInitializeFn =
108
- unsafe extern "system" fn ( c:: HANDLE , * mut c_void ,
109
- c:: BOOL ) -> c:: BOOL ;
110
- type SymCleanupFn =
111
- unsafe extern "system" fn ( c:: HANDLE ) -> c:: BOOL ;
112
-
113
- type StackWalkExFn =
114
- unsafe extern "system" fn ( c:: DWORD , c:: HANDLE , c:: HANDLE ,
115
- * mut c:: STACKFRAME_EX , * mut c:: CONTEXT ,
116
- * mut c_void , * mut c_void ,
117
- * mut c_void , * mut c_void , c:: DWORD ) -> c:: BOOL ;
118
-
119
- #[ cfg( target_arch = "x86" ) ]
120
- fn init_frame ( frame : & mut c:: STACKFRAME_EX ,
121
- ctx : & c:: CONTEXT ) -> c:: DWORD {
122
- frame. AddrPC . Offset = ctx. Eip as u64 ;
123
- frame. AddrPC . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
124
- frame. AddrStack . Offset = ctx. Esp as u64 ;
125
- frame. AddrStack . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
126
- frame. AddrFrame . Offset = ctx. Ebp as u64 ;
127
- frame. AddrFrame . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
128
- c:: IMAGE_FILE_MACHINE_I386
211
+ trait StackFrame {
212
+ fn new ( ) -> Self ;
213
+ fn init ( & mut self , ctx : & c:: CONTEXT ) -> c:: DWORD ;
214
+ fn get_addr ( & self ) -> * const u8 ;
129
215
}
130
216
131
- #[ cfg( target_arch = "x86_64" ) ]
132
- fn init_frame ( frame : & mut c:: STACKFRAME_EX ,
133
- ctx : & c:: CONTEXT ) -> c:: DWORD {
134
- frame. AddrPC . Offset = ctx. Rip as u64 ;
135
- frame. AddrPC . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
136
- frame. AddrStack . Offset = ctx. Rsp as u64 ;
137
- frame. AddrStack . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
138
- frame. AddrFrame . Offset = ctx. Rbp as u64 ;
139
- frame. AddrFrame . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
140
- c:: IMAGE_FILE_MACHINE_AMD64
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
+ }
246
+ }
247
+
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
+ }
277
+ }
278
+
279
+ enum StackWalkVariant {
280
+ StackWalkEx ( StackWalkExFn , printing:: PrintingFnsEx ) ,
281
+ StackWalk64 ( StackWalk64Fn , printing:: PrintingFns64 ) ,
141
282
}
142
283
143
284
pub struct BacktraceContext {
144
285
handle : c:: HANDLE ,
145
286
SymCleanup : SymCleanupFn ,
146
287
// Only used in printing for msvc and not gnu
288
+ // The gnu version is effectively a ZST dummy.
289
+ #[ allow( dead_code) ]
290
+ StackWalkVariant : StackWalkVariant ,
291
+ // keeping DynamycLibrary loaded until its functions no longer needed
147
292
#[ allow( dead_code) ]
148
293
dbghelp : DynamicLibrary ,
149
294
}
150
295
151
296
impl Drop for BacktraceContext {
152
297
fn drop ( & mut self ) {
153
- unsafe { ( self . SymCleanup ) ( self . handle ) ; }
298
+ unsafe {
299
+ ( self . SymCleanup ) ( self . handle ) ;
300
+ }
154
301
}
155
302
}
0 commit comments