@@ -47,7 +47,7 @@ mod printing;
4747pub mod gnu;
4848
4949pub 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 } ;
5151
5252pub fn unwind_backtrace ( frames : & mut [ Frame ] ) -> io:: Result < ( usize , BacktraceContext ) > {
5353 let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
@@ -56,20 +56,15 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
5656 let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
5757 let SymCleanup = sym ! ( dbghelp, "SymCleanup" , SymCleanupFn ) ?;
5858
59-
6059 // StackWalkEx might not be present and we'll fall back to StackWalk64
6160 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+ }
6764 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+ }
7368 Err ( ..) => return Err ( e) ,
7469 } ,
7570 } ;
@@ -92,101 +87,38 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
9287
9388 // And now that we're done with all the setup, do the stack walking!
9489 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+ }
11393
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) )
13896 }
13997 }
140-
141- Ok ( ( i, backtrace_context) )
14298}
14399
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 ( ) } ;
150102 let thread = unsafe { c:: GetCurrentProcess ( ) } ;
151103 let mut context: c:: CONTEXT = unsafe { mem:: zeroed ( ) } ;
152104 unsafe { c:: RtlCaptureContext ( & mut context) } ;
105+ let mut frame = W :: Item :: new ( ) ;
106+ let image = frame. init ( & context) ;
153107
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.
159108 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
187120 }
188-
189- Ok ( ( i, backtrace_context) )
121+ Ok ( i)
190122}
191123
192124type SymInitializeFn = unsafe extern "system" fn ( c:: HANDLE , * mut c_void , c:: BOOL ) -> c:: BOOL ;
@@ -217,56 +149,138 @@ type StackWalk64Fn = unsafe extern "system" fn(
217149 * mut c_void ,
218150) -> c:: BOOL ;
219151
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 ;
229156}
230157
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 ;
240215}
241216
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+ }
251246}
252247
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+ }
262277}
263278
264279enum StackWalkVariant {
265280 StackWalkEx ( StackWalkExFn , printing:: PrintingFnsEx ) ,
266281 StackWalk64 ( StackWalk64Fn , printing:: PrintingFns64 ) ,
267282}
268283
269-
270284pub struct BacktraceContext {
271285 handle : c:: HANDLE ,
272286 SymCleanup : SymCleanupFn ,
0 commit comments