@@ -46,27 +46,38 @@ 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
50
51
51
pub fn unwind_backtrace ( frames : & mut [ Frame ] ) -> io:: Result < ( usize , BacktraceContext ) > {
52
52
let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
53
53
54
54
// Fetch the symbols necessary from dbghelp.dll
55
55
let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
56
56
let SymCleanup = sym ! ( dbghelp, "SymCleanup" , SymCleanupFn ) ?;
57
+
58
+ // enum for holding the StackWalk function. Different from StackWalkVariant
59
+ // below, since there's no need to pass the function itself into
60
+ // the BacktraceContext
61
+ enum sw_fn_local {
62
+ SWExFn ( StackWalkExFn ) ,
63
+ SW64Fn ( StackWalk64Fn ) ,
64
+ }
57
65
// StackWalkEx might not be present and we'll fall back to StackWalk64
58
- let ResStackWalkEx = sym ! ( dbghelp, "StackWalkEx" , StackWalkExFn ) ;
59
- let ResStackWalk64 = sym ! ( dbghelp, "StackWalk64" , StackWalk64Fn ) ;
66
+ let ( StackWalkFn , variant) =
67
+ sym ! ( dbghelp, "StackWalkEx" , StackWalkExFn )
68
+ . map ( |f| ( sw_fn_local:: SWExFn ( f) , StackWalkVariant :: StackWalkEx ) )
69
+ . or_else ( |_|
70
+ sym ! ( dbghelp, "StackWalk64" , StackWalk64Fn )
71
+ . map ( |f| ( sw_fn_local:: SW64Fn ( f) , StackWalkVariant :: StackWalk64 ) )
72
+ ) ?;
60
73
61
74
// Allocate necessary structures for doing the stack walk
62
75
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
76
67
77
let backtrace_context = BacktraceContext {
68
78
handle : process,
69
79
SymCleanup ,
80
+ StackWalkVariant : variant,
70
81
dbghelp,
71
82
} ;
72
83
@@ -77,81 +88,102 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
77
88
}
78
89
79
90
// And now that we're done with all the setup, do the stack walking!
80
- match ( ResStackWalkEx , ResStackWalk64 ) {
81
- ( Ok ( StackWalkEx ) , _) => {
82
- let mut frame: c:: STACKFRAME_EX = unsafe { mem:: zeroed ( ) } ;
83
- frame. StackFrameSize = mem:: size_of_val ( & frame) as c:: DWORD ;
84
- let image = init_frame_ex ( & mut frame, & context) ;
85
-
86
- let mut i = 0 ;
87
- unsafe {
88
- while i < frames. len ( )
89
- && StackWalkEx (
90
- image,
91
- process,
92
- thread,
93
- & mut frame,
94
- & mut context,
95
- ptr:: null_mut ( ) ,
96
- ptr:: null_mut ( ) ,
97
- ptr:: null_mut ( ) ,
98
- ptr:: null_mut ( ) ,
99
- 0 ,
100
- ) == c:: TRUE
101
- {
102
- let addr = ( frame. AddrPC . Offset - 1 ) as * const u8 ;
103
-
104
- frames[ i] = Frame {
105
- symbol_addr : addr,
106
- exact_position : addr,
107
- inline_context : frame. InlineFrameContext ,
108
- } ;
109
- i += 1 ;
110
- }
111
- }
91
+ match StackWalkFn {
92
+ sw_fn_local:: SWExFn ( f) => set_frames_ex ( f, frames, backtrace_context, process) ,
93
+ sw_fn_local:: SW64Fn ( f) => set_frames_64 ( f, frames, backtrace_context, process) ,
94
+ }
95
+ }
112
96
113
- Ok ( ( i, backtrace_context) )
97
+ fn set_frames_ex (
98
+ StackWalkEx : StackWalkExFn ,
99
+ frames : & mut [ Frame ] ,
100
+ backtrace_context : BacktraceContext ,
101
+ process : c:: HANDLE ,
102
+ ) -> io:: Result < ( usize , BacktraceContext ) > {
103
+ let thread = unsafe { c:: GetCurrentProcess ( ) } ;
104
+ let mut context: c:: CONTEXT = unsafe { mem:: zeroed ( ) } ;
105
+ unsafe { c:: RtlCaptureContext ( & mut context) } ;
106
+
107
+ let mut frame: c:: STACKFRAME_EX = unsafe { mem:: zeroed ( ) } ;
108
+ frame. StackFrameSize = mem:: size_of_val ( & frame) as c:: DWORD ;
109
+ let image = init_frame_ex ( & mut frame, & context) ;
110
+
111
+ let mut i = 0 ;
112
+ unsafe {
113
+ while i < frames. len ( )
114
+ && StackWalkEx (
115
+ image,
116
+ process,
117
+ thread,
118
+ & mut frame,
119
+ & mut context,
120
+ ptr:: null_mut ( ) ,
121
+ ptr:: null_mut ( ) ,
122
+ ptr:: null_mut ( ) ,
123
+ ptr:: null_mut ( ) ,
124
+ 0 ,
125
+ ) == c:: TRUE
126
+ {
127
+ let addr = ( frame. AddrPC . Offset - 1 ) as * const u8 ;
128
+
129
+ frames[ i] = Frame {
130
+ symbol_addr : addr,
131
+ exact_position : addr,
132
+ inline_context : frame. InlineFrameContext ,
133
+ } ;
134
+ i += 1 ;
114
135
}
115
- ( _, Ok ( StackWalk64 ) ) => {
116
- let mut frame: c:: STACKFRAME64 = unsafe { mem:: zeroed ( ) } ;
117
- let image = init_frame_64 ( & mut frame, & context) ;
118
-
119
- // Start from -1 to avoid printing this stack frame, which will
120
- // always be exactly the same.
121
- let mut i = 0 ;
122
- unsafe {
123
- while i < frames. len ( )
124
- && StackWalk64 (
125
- image,
126
- process,
127
- thread,
128
- & mut frame,
129
- & mut context,
130
- ptr:: null_mut ( ) ,
131
- ptr:: null_mut ( ) ,
132
- ptr:: null_mut ( ) ,
133
- ptr:: null_mut ( ) ,
134
- ) == c:: TRUE
135
- {
136
- let addr = frame. AddrPC . Offset ;
137
- if addr == frame. AddrReturn . Offset || addr == 0 || frame. AddrReturn . Offset == 0
138
- {
139
- break ;
140
- }
141
-
142
- frames[ i] = Frame {
143
- symbol_addr : ( addr - 1 ) as * const u8 ,
144
- exact_position : ( addr - 1 ) as * const u8 ,
145
- inline_context : 0 ,
146
- } ;
147
- i += 1 ;
148
- }
136
+ }
137
+
138
+ Ok ( ( i, backtrace_context) )
139
+ }
140
+
141
+ fn set_frames_64 (
142
+ StackWalk64 : StackWalk64Fn ,
143
+ frames : & mut [ Frame ] ,
144
+ backtrace_context : BacktraceContext ,
145
+ process : c:: HANDLE ,
146
+ ) -> io:: Result < ( usize , BacktraceContext ) > {
147
+ let thread = unsafe { c:: GetCurrentProcess ( ) } ;
148
+ let mut context: c:: CONTEXT = unsafe { mem:: zeroed ( ) } ;
149
+ unsafe { c:: RtlCaptureContext ( & mut context) } ;
150
+
151
+ let mut frame: c:: STACKFRAME64 = unsafe { mem:: zeroed ( ) } ;
152
+ let image = init_frame_64 ( & mut frame, & context) ;
153
+
154
+ // Start from -1 to avoid printing this stack frame, which will
155
+ // always be exactly the same.
156
+ let mut i = 0 ;
157
+ unsafe {
158
+ while i < frames. len ( )
159
+ && StackWalk64 (
160
+ image,
161
+ process,
162
+ thread,
163
+ & mut frame,
164
+ & mut context,
165
+ ptr:: null_mut ( ) ,
166
+ ptr:: null_mut ( ) ,
167
+ ptr:: null_mut ( ) ,
168
+ ptr:: null_mut ( ) ,
169
+ ) == c:: TRUE
170
+ {
171
+ let addr = frame. AddrPC . Offset ;
172
+ if addr == frame. AddrReturn . Offset || addr == 0 || frame. AddrReturn . Offset == 0
173
+ {
174
+ break ;
149
175
}
150
176
151
- Ok ( ( i, backtrace_context) )
177
+ frames[ i] = Frame {
178
+ symbol_addr : ( addr - 1 ) as * const u8 ,
179
+ exact_position : ( addr - 1 ) as * const u8 ,
180
+ inline_context : 0 ,
181
+ } ;
182
+ i += 1 ;
152
183
}
153
- ( Err ( e) , _) => Err ( e) ,
154
184
}
185
+
186
+ Ok ( ( i, backtrace_context) )
155
187
}
156
188
157
189
type SymInitializeFn = unsafe extern "system" fn ( c:: HANDLE , * mut c_void , c:: BOOL ) -> c:: BOOL ;
@@ -226,16 +258,26 @@ fn init_frame_64(frame: &mut c::STACKFRAME64, ctx: &c::CONTEXT) -> c::DWORD {
226
258
c:: IMAGE_FILE_MACHINE_AMD64
227
259
}
228
260
261
+ enum StackWalkVariant {
262
+ StackWalkEx ,
263
+ StackWalk64 ,
264
+ }
265
+
266
+
229
267
pub struct BacktraceContext {
230
268
handle : c:: HANDLE ,
231
269
SymCleanup : SymCleanupFn ,
232
270
// Only used in printing for msvc and not gnu
233
271
#[ allow( dead_code) ]
272
+ StackWalkVariant : StackWalkVariant ,
273
+ #[ allow( dead_code) ]
234
274
dbghelp : DynamicLibrary ,
235
275
}
236
276
237
277
impl Drop for BacktraceContext {
238
278
fn drop ( & mut self ) {
239
- unsafe { ( self . SymCleanup ) ( self . handle ) ; }
279
+ unsafe {
280
+ ( self . SymCleanup ) ( self . handle ) ;
281
+ }
240
282
}
241
283
}
0 commit comments