2 * NT exception handling routines
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
15 #include "wine/exception.h"
16 #include "stackframe.h"
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(seh
);
23 /* Exception record for handling exceptions happening inside exception handlers */
26 EXCEPTION_FRAME frame
;
27 EXCEPTION_FRAME
*prevFrame
;
31 # define GET_IP(context) ((LPVOID)(context)->Eip)
34 # define GET_IP(context) ((LPVOID)(context)->pc)
37 # error You must define GET_IP for this CPU
40 void WINAPI
EXC_RtlRaiseException( PEXCEPTION_RECORD
, PCONTEXT
);
41 void WINAPI
EXC_RtlUnwind( PEXCEPTION_FRAME
, LPVOID
,
42 PEXCEPTION_RECORD
, DWORD
, PCONTEXT
);
43 void WINAPI
EXC_NtRaiseException( PEXCEPTION_RECORD
, PCONTEXT
,
46 /*******************************************************************
49 * Handler for exceptions happening inside a handler.
51 static DWORD
EXC_RaiseHandler( EXCEPTION_RECORD
*rec
, EXCEPTION_FRAME
*frame
,
52 CONTEXT
*context
, EXCEPTION_FRAME
**dispatcher
)
54 if (rec
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
55 return ExceptionContinueSearch
;
56 /* We shouldn't get here so we store faulty frame in dispatcher */
57 *dispatcher
= ((EXC_NESTED_FRAME
*)frame
)->prevFrame
;
58 return ExceptionNestedException
;
62 /*******************************************************************
65 * Handler for exceptions happening inside an unwind handler.
67 static DWORD
EXC_UnwindHandler( EXCEPTION_RECORD
*rec
, EXCEPTION_FRAME
*frame
,
68 CONTEXT
*context
, EXCEPTION_FRAME
**dispatcher
)
70 if (!(rec
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
)))
71 return ExceptionContinueSearch
;
72 /* We shouldn't get here so we store faulty frame in dispatcher */
73 *dispatcher
= ((EXC_NESTED_FRAME
*)frame
)->prevFrame
;
74 return ExceptionCollidedUnwind
;
78 /*******************************************************************
81 * Call an exception handler, setting up an exception frame to catch exceptions
82 * happening during the handler execution.
83 * Please do not change the first 4 parameters order in any way - some exceptions handlers
84 * rely on Base Pointer (EBP) to have a fixed position related to the exception frame
86 static DWORD
EXC_CallHandler( EXCEPTION_RECORD
*record
, EXCEPTION_FRAME
*frame
,
87 CONTEXT
*context
, EXCEPTION_FRAME
**dispatcher
,
88 PEXCEPTION_HANDLER handler
, PEXCEPTION_HANDLER nested_handler
)
90 EXC_NESTED_FRAME newframe
;
93 newframe
.frame
.Handler
= nested_handler
;
94 newframe
.prevFrame
= frame
;
95 __wine_push_frame( &newframe
.frame
);
96 TRACE( "calling handler at %p code=%lx flags=%lx\n",
97 handler
, record
->ExceptionCode
, record
->ExceptionFlags
);
98 ret
= handler( record
, frame
, context
, dispatcher
);
99 TRACE( "handler returned %lx\n", ret
);
100 __wine_pop_frame( &newframe
.frame
);
105 /**********************************************************************
108 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
110 static int send_debug_event( EXCEPTION_RECORD
*rec
, int first_chance
, CONTEXT
*context
)
115 SERVER_START_VAR_REQ( queue_exception_event
, sizeof(*rec
)+sizeof(*context
) )
117 CONTEXT
*context_ptr
= server_data_ptr(req
);
118 EXCEPTION_RECORD
*rec_ptr
= (EXCEPTION_RECORD
*)(context_ptr
+ 1);
119 req
->first
= first_chance
;
121 *context_ptr
= *context
;
122 if (!SERVER_CALL()) handle
= req
->handle
;
125 if (!handle
) return 0; /* no debugger present or other error */
127 /* No need to wait on the handle since the process gets suspended
128 * once the event is passed to the debugger, so when we get back
129 * here the event has been continued already.
131 SERVER_START_VAR_REQ( get_exception_status
, sizeof(*context
) )
133 req
->handle
= handle
;
134 if (!SERVER_CALL()) *context
= *(CONTEXT
*)server_data_ptr(req
);
143 /*******************************************************************
144 * EXC_DefaultHandling
146 * Default handling for exceptions. Called when we didn't find a suitable handler.
148 static void EXC_DefaultHandling( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
150 if (send_debug_event( rec
, FALSE
, context
) == DBG_CONTINUE
) return; /* continue execution */
152 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
153 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
154 else if (rec
->ExceptionCode
== EXCEPTION_NONCONTINUABLE_EXCEPTION
)
155 ERR("Process attempted to continue execution after noncontinuable exception.\n");
157 ERR("Unhandled exception code %lx flags %lx addr %p\n",
158 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
159 NtTerminateProcess( NtCurrentProcess(), 1 );
163 /***********************************************************************
164 * EXC_RtlRaiseException / RtlRaiseException (NTDLL.464)
166 DEFINE_REGS_ENTRYPOINT_1( RtlRaiseException
, EXC_RtlRaiseException
, EXCEPTION_RECORD
* )
167 void WINAPI
EXC_RtlRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
169 PEXCEPTION_FRAME frame
, dispatch
, nested_frame
;
170 EXCEPTION_RECORD newrec
;
173 TRACE( "code=%lx flags=%lx\n", rec
->ExceptionCode
, rec
->ExceptionFlags
);
175 if (send_debug_event( rec
, TRUE
, context
) == DBG_CONTINUE
) return; /* continue execution */
177 frame
= NtCurrentTeb()->except
;
179 while (frame
!= (PEXCEPTION_FRAME
)0xFFFFFFFF)
181 /* Check frame address */
182 if (((void*)frame
< NtCurrentTeb()->stack_low
) ||
183 ((void*)(frame
+1) > NtCurrentTeb()->stack_top
) ||
186 rec
->ExceptionFlags
|= EH_STACK_INVALID
;
191 res
= EXC_CallHandler( rec
, frame
, context
, &dispatch
, frame
->Handler
, EXC_RaiseHandler
);
192 if (frame
== nested_frame
)
194 /* no longer nested */
196 rec
->ExceptionFlags
&= ~EH_NESTED_CALL
;
201 case ExceptionContinueExecution
:
202 if (!(rec
->ExceptionFlags
& EH_NONCONTINUABLE
)) return;
203 newrec
.ExceptionCode
= STATUS_NONCONTINUABLE_EXCEPTION
;
204 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
205 newrec
.ExceptionRecord
= rec
;
206 newrec
.NumberParameters
= 0;
207 RtlRaiseException( &newrec
); /* never returns */
209 case ExceptionContinueSearch
:
211 case ExceptionNestedException
:
212 if (nested_frame
< dispatch
) nested_frame
= dispatch
;
213 rec
->ExceptionFlags
|= EH_NESTED_CALL
;
216 newrec
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
217 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
218 newrec
.ExceptionRecord
= rec
;
219 newrec
.NumberParameters
= 0;
220 RtlRaiseException( &newrec
); /* never returns */
225 EXC_DefaultHandling( rec
, context
);
229 /*******************************************************************
230 * EXC_RtlUnwind / RtlUnwind (KERNEL32.590) (NTDLL.518)
232 DEFINE_REGS_ENTRYPOINT_4( RtlUnwind
, EXC_RtlUnwind
,
233 PEXCEPTION_FRAME
, LPVOID
, PEXCEPTION_RECORD
, DWORD
)
234 void WINAPI
EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame
, LPVOID unusedEip
,
235 PEXCEPTION_RECORD pRecord
, DWORD returnEax
,
238 EXCEPTION_RECORD record
, newrec
;
239 PEXCEPTION_FRAME frame
, dispatch
;
242 context
->Eax
= returnEax
;
245 /* build an exception record, if we do not have one */
248 record
.ExceptionCode
= STATUS_UNWIND
;
249 record
.ExceptionFlags
= 0;
250 record
.ExceptionRecord
= NULL
;
251 record
.ExceptionAddress
= GET_IP(context
);
252 record
.NumberParameters
= 0;
256 pRecord
->ExceptionFlags
|= EH_UNWINDING
| (pEndFrame
? 0 : EH_EXIT_UNWIND
);
258 TRACE( "code=%lx flags=%lx\n", pRecord
->ExceptionCode
, pRecord
->ExceptionFlags
);
260 /* get chain of exception frames */
261 frame
= NtCurrentTeb()->except
;
262 while ((frame
!= (PEXCEPTION_FRAME
)0xffffffff) && (frame
!= pEndFrame
))
264 /* Check frame address */
265 if (pEndFrame
&& (frame
> pEndFrame
))
267 newrec
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
268 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
269 newrec
.ExceptionRecord
= pRecord
;
270 newrec
.NumberParameters
= 0;
271 RtlRaiseException( &newrec
); /* never returns */
273 if (((void*)frame
< NtCurrentTeb()->stack_low
) ||
274 ((void*)(frame
+1) > NtCurrentTeb()->stack_top
) ||
277 newrec
.ExceptionCode
= STATUS_BAD_STACK
;
278 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
279 newrec
.ExceptionRecord
= pRecord
;
280 newrec
.NumberParameters
= 0;
281 RtlRaiseException( &newrec
); /* never returns */
285 switch(EXC_CallHandler( pRecord
, frame
, context
, &dispatch
,
286 frame
->Handler
, EXC_UnwindHandler
))
288 case ExceptionContinueSearch
:
290 case ExceptionCollidedUnwind
:
294 newrec
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
295 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
296 newrec
.ExceptionRecord
= pRecord
;
297 newrec
.NumberParameters
= 0;
298 RtlRaiseException( &newrec
); /* never returns */
301 frame
= __wine_pop_frame( frame
);
306 /*******************************************************************
307 * EXC_NtRaiseException / NtRaiseException (NTDLL.175)
309 DEFINE_REGS_ENTRYPOINT_3( NtRaiseException
, EXC_NtRaiseException
,
310 EXCEPTION_RECORD
*, CONTEXT
*, BOOL
)
311 void WINAPI
EXC_NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*ctx
,
312 BOOL first
, CONTEXT
*context
)
314 EXC_RtlRaiseException( rec
, ctx
);
319 /***********************************************************************
320 * RtlRaiseStatus (NTDLL.465)
322 * Raise an exception with ExceptionCode = status
324 void WINAPI
RtlRaiseStatus( NTSTATUS status
)
326 EXCEPTION_RECORD ExceptionRec
;
328 ExceptionRec
.ExceptionCode
= status
;
329 ExceptionRec
.ExceptionFlags
= EH_NONCONTINUABLE
;
330 ExceptionRec
.ExceptionRecord
= NULL
;
331 ExceptionRec
.NumberParameters
= 0;
332 RtlRaiseException( &ExceptionRec
);
336 /*************************************************************
337 * __wine_exception_handler
339 * Exception handler for exception blocks declared in Wine code.
341 DWORD
__wine_exception_handler( EXCEPTION_RECORD
*record
, EXCEPTION_FRAME
*frame
,
342 CONTEXT
*context
, LPVOID pdispatcher
)
344 __WINE_FRAME
*wine_frame
= (__WINE_FRAME
*)frame
;
346 if (record
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
| EH_NESTED_CALL
))
347 return ExceptionContinueSearch
;
348 if (wine_frame
->u
.filter
)
350 EXCEPTION_POINTERS ptrs
;
351 ptrs
.ExceptionRecord
= record
;
352 ptrs
.ContextRecord
= context
;
353 switch(wine_frame
->u
.filter( &ptrs
))
355 case EXCEPTION_CONTINUE_SEARCH
:
356 return ExceptionContinueSearch
;
357 case EXCEPTION_CONTINUE_EXECUTION
:
358 return ExceptionContinueExecution
;
359 case EXCEPTION_EXECUTE_HANDLER
:
362 MESSAGE( "Invalid return value from exception filter\n" );
366 /* hack to make GetExceptionCode() work in handler */
367 wine_frame
->ExceptionCode
= record
->ExceptionCode
;
368 wine_frame
->ExceptionRecord
= wine_frame
;
370 RtlUnwind( frame
, 0, record
, 0 );
371 __wine_pop_frame( frame
);
372 longjmp( wine_frame
->jmp
, 1 );
376 /*************************************************************
377 * __wine_finally_handler
379 * Exception handler for try/finally blocks declared in Wine code.
381 DWORD
__wine_finally_handler( EXCEPTION_RECORD
*record
, EXCEPTION_FRAME
*frame
,
382 CONTEXT
*context
, LPVOID pdispatcher
)
384 __WINE_FRAME
*wine_frame
= (__WINE_FRAME
*)frame
;
386 if (!(record
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
)))
387 return ExceptionContinueSearch
;
388 wine_frame
->u
.finally_func( FALSE
);
389 return ExceptionContinueSearch
;