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 * Default handling for exceptions. Called when we didn't find a suitable handler.
93 static void EXC_DefaultHandling( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
95 if ((PROCESS_Current()->flags
& PDB32_DEBUGGED
) &&
96 (DEBUG_SendExceptionEvent( rec
, FALSE
, context
) == DBG_CONTINUE
))
97 return; /* continue execution */
99 if (wine_debugger( rec
, context
, FALSE
) == DBG_CONTINUE
)
100 return; /* continue execution */
102 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
103 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
104 else if (rec
->ExceptionCode
== EXCEPTION_NONCONTINUABLE_EXCEPTION
)
105 ERR("Process attempted to continue execution after noncontinuable exception.\n");
107 ERR("Unhandled exception code %lx flags %lx addr %p\n",
108 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
109 TerminateProcess( GetCurrentProcess(), 1 );
113 /***********************************************************************
114 * EXC_RtlRaiseException / RtlRaiseException (NTDLL.464)
116 DEFINE_REGS_ENTRYPOINT_1( RtlRaiseException
, EXC_RtlRaiseException
, EXCEPTION_RECORD
* )
117 void WINAPI
EXC_RtlRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
119 PEXCEPTION_FRAME frame
, dispatch
, nested_frame
;
120 EXCEPTION_RECORD newrec
;
123 TRACE( "code=%lx flags=%lx\n", rec
->ExceptionCode
, rec
->ExceptionFlags
);
125 if ((PROCESS_Current()->flags
& PDB32_DEBUGGED
) &&
126 (DEBUG_SendExceptionEvent( rec
, TRUE
, context
) == DBG_CONTINUE
))
127 return; /* continue execution */
129 if (wine_debugger( rec
, context
, TRUE
) == DBG_CONTINUE
)
130 return; /* continue execution */
132 frame
= NtCurrentTeb()->except
;
134 while (frame
!= (PEXCEPTION_FRAME
)0xFFFFFFFF)
136 /* Check frame address */
137 if (((void*)frame
< NtCurrentTeb()->stack_low
) ||
138 ((void*)(frame
+1) > NtCurrentTeb()->stack_top
) ||
141 rec
->ExceptionFlags
|= EH_STACK_INVALID
;
146 res
= EXC_CallHandler( rec
, frame
, context
, &dispatch
, frame
->Handler
, EXC_RaiseHandler
);
147 if (frame
== nested_frame
)
149 /* no longer nested */
151 rec
->ExceptionFlags
&= ~EH_NESTED_CALL
;
156 case ExceptionContinueExecution
:
157 if (!(rec
->ExceptionFlags
& EH_NONCONTINUABLE
)) return;
158 newrec
.ExceptionCode
= STATUS_NONCONTINUABLE_EXCEPTION
;
159 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
160 newrec
.ExceptionRecord
= rec
;
161 newrec
.NumberParameters
= 0;
162 RtlRaiseException( &newrec
); /* never returns */
164 case ExceptionContinueSearch
:
166 case ExceptionNestedException
:
167 if (nested_frame
< dispatch
) nested_frame
= dispatch
;
168 rec
->ExceptionFlags
|= EH_NESTED_CALL
;
171 newrec
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
172 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
173 newrec
.ExceptionRecord
= rec
;
174 newrec
.NumberParameters
= 0;
175 RtlRaiseException( &newrec
); /* never returns */
180 EXC_DefaultHandling( rec
, context
);
184 /*******************************************************************
185 * EXC_RtlUnwind / RtlUnwind (KERNEL32.590) (NTDLL.518)
187 DEFINE_REGS_ENTRYPOINT_4( RtlUnwind
, EXC_RtlUnwind
,
188 PEXCEPTION_FRAME
, LPVOID
, PEXCEPTION_RECORD
, DWORD
)
189 void WINAPI
EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame
, LPVOID unusedEip
,
190 PEXCEPTION_RECORD pRecord
, DWORD returnEax
,
193 EXCEPTION_RECORD record
, newrec
;
194 PEXCEPTION_FRAME frame
, dispatch
;
197 context
->Eax
= returnEax
;
200 /* build an exception record, if we do not have one */
203 record
.ExceptionCode
= STATUS_UNWIND
;
204 record
.ExceptionFlags
= 0;
205 record
.ExceptionRecord
= NULL
;
206 record
.ExceptionAddress
= GET_IP(context
);
207 record
.NumberParameters
= 0;
211 pRecord
->ExceptionFlags
|= EH_UNWINDING
| (pEndFrame
? 0 : EH_EXIT_UNWIND
);
213 TRACE( "code=%lx flags=%lx\n", pRecord
->ExceptionCode
, pRecord
->ExceptionFlags
);
215 /* get chain of exception frames */
216 frame
= NtCurrentTeb()->except
;
217 while ((frame
!= (PEXCEPTION_FRAME
)0xffffffff) && (frame
!= pEndFrame
))
219 /* Check frame address */
220 if (pEndFrame
&& (frame
> pEndFrame
))
222 newrec
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
223 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
224 newrec
.ExceptionRecord
= pRecord
;
225 newrec
.NumberParameters
= 0;
226 RtlRaiseException( &newrec
); /* never returns */
228 if (((void*)frame
< NtCurrentTeb()->stack_low
) ||
229 ((void*)(frame
+1) > NtCurrentTeb()->stack_top
) ||
232 newrec
.ExceptionCode
= STATUS_BAD_STACK
;
233 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
234 newrec
.ExceptionRecord
= pRecord
;
235 newrec
.NumberParameters
= 0;
236 RtlRaiseException( &newrec
); /* never returns */
240 switch(EXC_CallHandler( pRecord
, frame
, context
, &dispatch
,
241 frame
->Handler
, EXC_UnwindHandler
))
243 case ExceptionContinueSearch
:
245 case ExceptionCollidedUnwind
:
249 newrec
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
250 newrec
.ExceptionFlags
= EH_NONCONTINUABLE
;
251 newrec
.ExceptionRecord
= pRecord
;
252 newrec
.NumberParameters
= 0;
253 RtlRaiseException( &newrec
); /* never returns */
256 frame
= EXC_pop_frame( frame
);
261 /*******************************************************************
262 * EXC_NtRaiseException / NtRaiseException (NTDLL.175)
264 DEFINE_REGS_ENTRYPOINT_3( NtRaiseException
, EXC_NtRaiseException
,
265 EXCEPTION_RECORD
*, CONTEXT
*, BOOL
)
266 void WINAPI
EXC_NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*ctx
,
267 BOOL first
, CONTEXT
*context
)
269 EXC_RtlRaiseException( rec
, ctx
);
274 /***********************************************************************
275 * RtlRaiseStatus (NTDLL.465)
277 * Raise an exception with ExceptionCode = status
279 void WINAPI
RtlRaiseStatus( NTSTATUS status
)
281 EXCEPTION_RECORD ExceptionRec
;
283 ExceptionRec
.ExceptionCode
= status
;
284 ExceptionRec
.ExceptionFlags
= EH_NONCONTINUABLE
;
285 ExceptionRec
.ExceptionRecord
= NULL
;
286 ExceptionRec
.NumberParameters
= 0;
287 RtlRaiseException( &ExceptionRec
);
291 /***********************************************************************
292 * EXC_DebugBreak / DebugBreak (KERNEL32.181)
294 DEFINE_REGS_ENTRYPOINT_0( DebugBreak
, EXC_DebugBreak
)
295 void WINAPI
EXC_DebugBreak( CONTEXT
*context
)
297 EXCEPTION_RECORD rec
;
299 rec
.ExceptionCode
= EXCEPTION_BREAKPOINT
;
300 rec
.ExceptionFlags
= 0;
301 rec
.ExceptionRecord
= NULL
;
302 rec
.NumberParameters
= 0;
303 EXC_RtlRaiseException( &rec
, context
);
307 /***********************************************************************
308 * DebugBreak16 (KERNEL.203)
310 void WINAPI
DebugBreak16( CONTEXT86
*context
)
313 EXC_DebugBreak( context
);
314 #endif /* defined(__i386__) */