@@ -47,7 +47,7 @@ mod printing;
47
47
pub mod gnu;
48
48
49
49
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 } ;
51
51
52
52
pub fn unwind_backtrace ( frames : & mut [ Frame ] ) -> io:: Result < ( usize , BacktraceContext ) > {
53
53
let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
@@ -56,20 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
56
56
let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
57
57
let SymCleanup = sym ! ( dbghelp, "SymCleanup" , SymCleanupFn ) ?;
58
58
59
-
60
59
// StackWalkEx might not be present and we'll fall back to StackWalk64
61
60
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
+ }
67
64
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
+ }
73
68
Err ( ..) => return Err ( e) ,
74
69
} ,
75
70
} ;
@@ -92,101 +87,38 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
92
87
93
88
// And now that we're done with all the setup, do the stack walking!
94
89
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
+ }
113
93
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) )
138
96
}
139
97
}
140
-
141
- Ok ( ( i, backtrace_context) )
142
98
}
143
99
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 ( ) } ;
150
102
let thread = unsafe { c:: GetCurrentProcess ( ) } ;
151
103
let mut context: c:: CONTEXT = unsafe { mem:: zeroed ( ) } ;
152
104
unsafe { c:: RtlCaptureContext ( & mut context) } ;
105
+ let mut frame = W :: Item :: new ( ) ;
106
+ let image = frame. init ( & context) ;
153
107
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.
159
108
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
187
120
}
188
-
189
- Ok ( ( i, backtrace_context) )
121
+ Ok ( i)
190
122
}
191
123
192
124
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(
217
149
* mut c_void ,
218
150
) -> c:: BOOL ;
219
151
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 ;
229
156
}
230
157
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 ;
240
215
}
241
216
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
+ }
251
246
}
252
247
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
+ }
262
277
}
263
278
264
279
enum StackWalkVariant {
265
280
StackWalkEx ( StackWalkExFn , printing:: PrintingFnsEx ) ,
266
281
StackWalk64 ( StackWalk64Fn , printing:: PrintingFns64 ) ,
267
282
}
268
283
269
-
270
284
pub struct BacktraceContext {
271
285
handle : c:: HANDLE ,
272
286
SymCleanup : SymCleanupFn ,
0 commit comments