@@ -48,24 +48,21 @@ pub mod gnu;
48
48
49
49
pub use self :: printing:: { resolve_symname, foreach_symbol_fileline} ;
50
50
51
- pub fn unwind_backtrace ( frames : & mut [ Frame ] )
52
- -> io:: Result < ( usize , BacktraceContext ) >
53
- {
51
+ pub fn unwind_backtrace ( frames : & mut [ Frame ] ) -> io:: Result < ( usize , BacktraceContext ) > {
54
52
let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
55
53
56
54
// Fetch the symbols necessary from dbghelp.dll
57
55
let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
58
56
let SymCleanup = sym ! ( dbghelp, "SymCleanup" , SymCleanupFn ) ?;
59
- let StackWalkEx = sym ! ( dbghelp, "StackWalkEx" , StackWalkExFn ) ?;
57
+ // 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 ) ;
60
60
61
61
// Allocate necessary structures for doing the stack walk
62
62
let process = unsafe { c:: GetCurrentProcess ( ) } ;
63
63
let thread = unsafe { c:: GetCurrentThread ( ) } ;
64
64
let mut context: c:: CONTEXT = unsafe { mem:: zeroed ( ) } ;
65
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
66
70
67
let backtrace_context = BacktraceContext {
71
68
handle : process,
@@ -76,49 +73,139 @@ pub fn unwind_backtrace(frames: &mut [Frame])
76
73
// Initialize this process's symbols
77
74
let ret = unsafe { SymInitialize ( process, ptr:: null_mut ( ) , c:: TRUE ) } ;
78
75
if ret != c:: TRUE {
79
- return Ok ( ( 0 , backtrace_context) )
76
+ return Ok ( ( 0 , backtrace_context) ) ;
80
77
}
81
78
82
79
// And now that we're done with all the setup, do the stack walking!
83
- 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 ;
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
+ }
112
+
113
+ Ok ( ( i, backtrace_context) )
101
114
}
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
+ }
149
+ }
150
+
151
+ Ok ( ( i, backtrace_context) )
152
+ }
153
+ ( Err ( e) , _) => Err ( e) ,
102
154
}
103
-
104
- Ok ( ( i, backtrace_context) )
105
155
}
106
156
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 ;
157
+ type SymInitializeFn = unsafe extern "system" fn ( c:: HANDLE , * mut c_void , c:: BOOL ) -> c:: BOOL ;
158
+ type SymCleanupFn = unsafe extern "system" fn ( c:: HANDLE ) -> c:: BOOL ;
159
+
160
+ type StackWalkExFn = unsafe extern "system" fn (
161
+ c:: DWORD ,
162
+ c:: HANDLE ,
163
+ c:: HANDLE ,
164
+ * mut c:: STACKFRAME_EX ,
165
+ * mut c:: CONTEXT ,
166
+ * mut c_void ,
167
+ * mut c_void ,
168
+ * mut c_void ,
169
+ * mut c_void ,
170
+ c:: DWORD ,
171
+ ) -> c:: BOOL ;
172
+
173
+ type StackWalk64Fn = unsafe extern "system" fn (
174
+ c:: DWORD ,
175
+ c:: HANDLE ,
176
+ c:: HANDLE ,
177
+ * mut c:: STACKFRAME64 ,
178
+ * mut c:: CONTEXT ,
179
+ * mut c_void ,
180
+ * mut c_void ,
181
+ * mut c_void ,
182
+ * mut c_void ,
183
+ ) -> c:: BOOL ;
112
184
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 ;
185
+ #[ cfg( target_arch = "x86" ) ]
186
+ fn init_frame_ex ( frame : & mut c:: STACKFRAME_EX , ctx : & c:: CONTEXT ) -> c:: DWORD {
187
+ frame. AddrPC . Offset = ctx. Eip as u64 ;
188
+ frame. AddrPC . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
189
+ frame. AddrStack . Offset = ctx. Esp as u64 ;
190
+ frame. AddrStack . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
191
+ frame. AddrFrame . Offset = ctx. Ebp as u64 ;
192
+ frame. AddrFrame . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
193
+ c:: IMAGE_FILE_MACHINE_I386
194
+ }
195
+
196
+ #[ cfg( target_arch = "x86_64" ) ]
197
+ fn init_frame_ex ( frame : & mut c:: STACKFRAME_EX , ctx : & c:: CONTEXT ) -> c:: DWORD {
198
+ frame. AddrPC . Offset = ctx. Rip as u64 ;
199
+ frame. AddrPC . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
200
+ frame. AddrStack . Offset = ctx. Rsp as u64 ;
201
+ frame. AddrStack . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
202
+ frame. AddrFrame . Offset = ctx. Rbp as u64 ;
203
+ frame. AddrFrame . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
204
+ c:: IMAGE_FILE_MACHINE_AMD64
205
+ }
118
206
119
207
#[ cfg( target_arch = "x86" ) ]
120
- fn init_frame ( frame : & mut c:: STACKFRAME_EX ,
121
- ctx : & c:: CONTEXT ) -> c:: DWORD {
208
+ fn init_frame_64 ( frame : & mut c:: STACKFRAME64 , ctx : & c:: CONTEXT ) -> c:: DWORD {
122
209
frame. AddrPC . Offset = ctx. Eip as u64 ;
123
210
frame. AddrPC . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
124
211
frame. AddrStack . Offset = ctx. Esp as u64 ;
@@ -129,8 +216,7 @@ fn init_frame(frame: &mut c::STACKFRAME_EX,
129
216
}
130
217
131
218
#[ cfg( target_arch = "x86_64" ) ]
132
- fn init_frame ( frame : & mut c:: STACKFRAME_EX ,
133
- ctx : & c:: CONTEXT ) -> c:: DWORD {
219
+ fn init_frame_64 ( frame : & mut c:: STACKFRAME64 , ctx : & c:: CONTEXT ) -> c:: DWORD {
134
220
frame. AddrPC . Offset = ctx. Rip as u64 ;
135
221
frame. AddrPC . Mode = c:: ADDRESS_MODE :: AddrModeFlat ;
136
222
frame. AddrStack . Offset = ctx. Rsp as u64 ;
0 commit comments