2 * NT exception handling routines
4 * Copyright 1999 Turchanov Sergey
5 * Copyright 1999 Alexandre Julliard
13 #include "wine/exception.h"
14 #include "stackframe.h"
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(seh
);
21 /* Exception record for handling exceptions happening inside exception handlers */
24 EXCEPTION_FRAME frame
;
25 EXCEPTION_FRAME
*prevFrame
;
29 /*******************************************************************
32 * Handler for exceptions happening inside a handler.
34 static DWORD
EXC_RaiseHandler( EXCEPTION_RECORD
*rec
, EXCEPTION_FRAME
*frame
,
35 CONTEXT
*context
, EXCEPTION_FRAME
**dispatcher
)
37 if (rec
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
))
38 return ExceptionContinueSearch
;
39 /* We shouldn't get here so we store faulty frame in dispatcher */
40 *dispatcher
= ((EXC_NESTED_FRAME
*)frame
)->prevFrame
;
41 return ExceptionNestedException
;
45 /*******************************************************************
48 * Handler for exceptions happening inside an unwind handler.
50 static DWORD
EXC_UnwindHandler( EXCEPTION_RECORD
*rec
, EXCEPTION_FRAME
*frame
,
51 CONTEXT
*context
, EXCEPTION_FRAME
**dispatcher
)
53 if (!(rec
->ExceptionFlags
& (EH_UNWINDING
| EH_EXIT_UNWIND
)))
54 return ExceptionContinueSearch
;
55 /* We shouldn't get here so we store faulty frame in dispatcher */
56 *dispatcher
= ((EXC_NESTED_FRAME
*)frame
)->prevFrame
;
57 return ExceptionCollidedUnwind
;
61 /*******************************************************************
64 * Call an exception handler, setting up an exception frame to catch exceptions
65 * happening during the handler execution.
66 * Please do not change the first 4 parameters order in any way - some exceptions handlers
67 * rely on Base Pointer (EBP) to have a fixed position related to the exception frame
69 static DWORD
EXC_CallHandler( EXCEPTION_RECORD
*record
, EXCEPTION_FRAME
*frame
,
70 CONTEXT
*context
, EXCEPTION_FRAME
**dispatcher
,
71 PEXCEPTION_HANDLER handler
, PEXCEPTION_HANDLER nested_handler
)
73 EXC_NESTED_FRAME newframe
;
76 newframe
.frame
.Handler
= nested_handler
;
77 newframe
.prevFrame
= frame
;
78 EXC_push_frame( &newframe
.frame
);
79 TRACE( "calling handler at %p code=%lx flags=%lx\n",
80 handler
, record
->ExceptionCode
, record
->ExceptionFlags
);
81 ret
= handler( record
, frame
, context
, dispatcher
);
82 TRACE( "handler returned %lx\n", ret
);
83 EXC_pop_frame( &newframe
.frame
);
88 /**********************************************************************
91 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
93 static inline int send_debug_event( EXCEPTION_RECORD
*rec
, int first_chance
, CONTEXT
*context
)
95 struct exception_event_request
*req
= get_req_buffer();
97 req
->first
= first_chance
;
98 req
->context
= *context
;
99 if (!server_call_noerr( REQ_EXCEPTION_EVENT
)) *context
= req
->context
;
104 /*******************************************************************
105 * EXC_DefaultHandling
107 * Default handling for exceptions. Called when we didn't find a suitable handler.
109 static void EXC_DefaultHandling( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
111 if (send_debug_event( rec
, FALSE
, context
) == DBG_CONTINUE
) return; /* continue execution */
113 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
114 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
115 else if (rec
->ExceptionCode
== EXCEPTION_NONCONTINUABLE_EXCEPTION
)
116 ERR("Process attempted to continue execution after noncontinuable exception.\n");
118 ERR("Unhandled exception code %lx flags %lx addr %p\n",
119 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
120 TerminateProcess( GetCurrentProcess(), 1 );
124 /***********************************************************************
125 * EXC_RtlRaiseException / RtlRaiseException (NTDLL.464)
127 DEFINE_REGS_ENTRYPOINT_1( RtlRaiseException
, EXC_RtlRaiseException
, EXCEPTION_RECORD
* )
128 void WINAPI
EXC_RtlRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
130 PEXCEPTION_FRAME frame
, dispatch
, nested_frame
;
131 EXCEPTION_RECORD newrec
;
134 TRACE( "code=%lx flags=%lx\n", rec
->ExceptionCode
, rec
->ExceptionFlags
);
136 if (send_debug_event( rec
, TRUE
, context
) == DBG_CONTINUE
) return; /* continue execution */
138 frame
= NtCurrentTeb()->except
;
140 while (frame
!= (PEXCEPTION_FRAME
)0xFFFFFFFF)
142 /* Check frame address */
143 if (((void*)frame
< NtCurrentTeb()->stack_low
) ||
144 ((void*)(frame
+1) > NtCurrentTeb()->stack_top
) ||
147 rec
->ExceptionFlags
|= EH_STACK_INVALID
;
152 res
= EXC_CallHandler( rec
, frame
, context
, &dispatch
, frame
->Handler
, EXC_RaiseHandler
);
153 if (frame
== nested_frame
)
155 /* no longer nested */
157 rec
->ExceptionFlags
&= ~EH_NESTED_CALL
;
162 case ExceptionContinueExecution
:
163 if (!(rec
->ExceptionFlags
& EH_NONCONTINUABLE
)) return;
164 newrec
.ExceptionCode
= STATUS_NONCONTINUABLE_EXCEPTION
;
165 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
166 newrec
.ExceptionRecord
= rec
;
167 newrec
.NumberParameters
= 0;
168 RtlRaiseException( &newrec
); /* never returns */
170 case ExceptionContinueSearch
:
172 case ExceptionNestedException
:
173 if (nested_frame
< dispatch
) nested_frame
= dispatch
;
174 rec
->ExceptionFlags
|= EH_NESTED_CALL
;
177 newrec
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
178 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
179 newrec
.ExceptionRecord
= rec
;
180 newrec
.NumberParameters
= 0;
181 RtlRaiseException( &newrec
); /* never returns */
186 EXC_DefaultHandling( rec
, context
);
190 /*******************************************************************
191 * EXC_RtlUnwind / RtlUnwind (KERNEL32.590) (NTDLL.518)
193 DEFINE_REGS_ENTRYPOINT_4( RtlUnwind
, EXC_RtlUnwind
,
194 PEXCEPTION_FRAME
, LPVOID
, PEXCEPTION_RECORD
, DWORD
)
195 void WINAPI
EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame
, LPVOID unusedEip
,
196 PEXCEPTION_RECORD pRecord
, DWORD returnEax
,
199 EXCEPTION_RECORD record
, newrec
;
200 PEXCEPTION_FRAME frame
, dispatch
;
203 context
->Eax
= returnEax
;
206 /* build an exception record, if we do not have one */
209 record
.ExceptionCode
= STATUS_UNWIND
;
210 record
.ExceptionFlags
= 0;
211 record
.ExceptionRecord
= NULL
;
212 record
.ExceptionAddress
= GET_IP(context
);
213 record
.NumberParameters
= 0;
217 pRecord
->ExceptionFlags
|= EH_UNWINDING
| (pEndFrame
? 0 : EH_EXIT_UNWIND
);
219 TRACE( "code=%lx flags=%lx\n", pRecord
->ExceptionCode
, pRecord
->ExceptionFlags
);
221 /* get chain of exception frames */
222 frame
= NtCurrentTeb()->except
;
223 while ((frame
!= (PEXCEPTION_FRAME
)0xffffffff) && (frame
!= pEndFrame
))
225 /* Check frame address */
226 if (pEndFrame
&& (frame
> pEndFrame
))
228 newrec
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
229 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
230 newrec
.ExceptionRecord
= pRecord
;
231 newrec
.NumberParameters
= 0;
232 RtlRaiseException( &newrec
); /* never returns */
234 if (((void*)frame
< NtCurrentTeb()->stack_low
) ||
235 ((void*)(frame
+1) > NtCurrentTeb()->stack_top
) ||
238 newrec
.ExceptionCode
= STATUS_BAD_STACK
;
239 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
240 newrec
.ExceptionRecord
= pRecord
;
241 newrec
.NumberParameters
= 0;
242 RtlRaiseException( &newrec
); /* never returns */
246 switch(EXC_CallHandler( pRecord
, frame
, context
, &dispatch
,
247 frame
->Handler
, EXC_UnwindHandler
))
249 case ExceptionContinueSearch
:
251 case ExceptionCollidedUnwind
:
255 newrec
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
256 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
257 newrec
.ExceptionRecord
= pRecord
;
258 newrec
.NumberParameters
= 0;
259 RtlRaiseException( &newrec
); /* never returns */
262 frame
= EXC_pop_frame( frame
);
267 /*******************************************************************
268 * EXC_NtRaiseException / NtRaiseException (NTDLL.175)
270 DEFINE_REGS_ENTRYPOINT_3( NtRaiseException
, EXC_NtRaiseException
,
271 EXCEPTION_RECORD
*, CONTEXT
*, BOOL
)
272 void WINAPI
EXC_NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*ctx
,
273 BOOL first
, CONTEXT
*context
)
275 EXC_RtlRaiseException( rec
, ctx
);
280 /***********************************************************************
281 * RtlRaiseStatus (NTDLL.465)
283 * Raise an exception with ExceptionCode = status
285 void WINAPI
RtlRaiseStatus( NTSTATUS status
)
287 EXCEPTION_RECORD ExceptionRec
;
289 ExceptionRec
.ExceptionCode
= status
;
290 ExceptionRec
.ExceptionFlags
= EH_NONCONTINUABLE
;
291 ExceptionRec
.ExceptionRecord
= NULL
;
292 ExceptionRec
.NumberParameters
= 0;
293 RtlRaiseException( &ExceptionRec
);