@@ -46,27 +46,38 @@ 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 } ;
5050
5151pub fn unwind_backtrace ( frames : & mut [ Frame ] ) -> io:: Result < ( usize , BacktraceContext ) > {
5252 let dbghelp = DynamicLibrary :: open ( "dbghelp.dll" ) ?;
5353
5454 // Fetch the symbols necessary from dbghelp.dll
5555 let SymInitialize = sym ! ( dbghelp, "SymInitialize" , SymInitializeFn ) ?;
5656 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+ }
5765 // 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+ ) ?;
6073
6174 // Allocate necessary structures for doing the stack walk
6275 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) } ;
6676
6777 let backtrace_context = BacktraceContext {
6878 handle : process,
6979 SymCleanup ,
80+ StackWalkVariant : variant,
7081 dbghelp,
7182 } ;
7283
@@ -77,81 +88,102 @@ pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceCon
7788 }
7889
7990 // 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+ }
11296
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 ;
114135 }
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 ;
149175 }
150176
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 ;
152183 }
153- ( Err ( e) , _) => Err ( e) ,
154184 }
185+
186+ Ok ( ( i, backtrace_context) )
155187}
156188
157189type 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 {
226258 c:: IMAGE_FILE_MACHINE_AMD64
227259}
228260
261+ enum StackWalkVariant {
262+ StackWalkEx ,
263+ StackWalk64 ,
264+ }
265+
266+
229267pub struct BacktraceContext {
230268 handle : c:: HANDLE ,
231269 SymCleanup : SymCleanupFn ,
232270 // Only used in printing for msvc and not gnu
233271 #[ allow( dead_code) ]
272+ StackWalkVariant : StackWalkVariant ,
273+ #[ allow( dead_code) ]
234274 dbghelp : DynamicLibrary ,
235275}
236276
237277impl Drop for BacktraceContext {
238278 fn drop ( & mut self ) {
239- unsafe { ( self . SymCleanup ) ( self . handle ) ; }
279+ unsafe {
280+ ( self . SymCleanup ) ( self . handle ) ;
281+ }
240282 }
241283}
0 commit comments