@@ -46,110 +46,257 @@ mod printing;
4646#[ path = "backtrace_gnu.rs" ]
4747pub mod gnu;
4848
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} ;
5051
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 ) > {
5453 let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
5554
5655 // Fetch the symbols necessary from dbghelp.dll
5756 let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
5857 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+ } ;
6071
6172 // Allocate necessary structures for doing the stack walk
6273 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) ;
6974
7075 let backtrace_context = BacktraceContext {
7176 handle : process,
7277 SymCleanup ,
78+ StackWalkVariant : sw_var,
7379 dbghelp,
7480 } ;
7581
7682 // Initialize this process's symbols
7783 let ret = unsafe { SymInitialize ( process, ptr:: null_mut ( ) , c:: TRUE ) } ;
7884 if ret != c:: TRUE {
79- return Ok ( ( 0 , backtrace_context) )
85+ return Ok ( ( 0 , backtrace_context) ) ;
8086 }
8187
8288 // 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+
83108 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+ )
101181 }
102182 }
183+ }
103184
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+ }
105209}
106210
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 ;
129215}
130216
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 ) ,
141282}
142283
143284pub struct BacktraceContext {
144285 handle : c:: HANDLE ,
145286 SymCleanup : SymCleanupFn ,
146287 // 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
147292 #[ allow( dead_code) ]
148293 dbghelp : DynamicLibrary ,
149294}
150295
151296impl Drop for BacktraceContext {
152297 fn drop ( & mut self ) {
153- unsafe { ( self . SymCleanup ) ( self . handle ) ; }
298+ unsafe {
299+ ( self . SymCleanup ) ( self . handle ) ;
300+ }
154301 }
155302}
0 commit comments