3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: User-mode exception support for IA-32
6 * FILE: lib/ntdll/rtl/i386/exception.c
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
10 /* INCLUDES *****************************************************************/
12 #include <ddk/ntddk.h>
19 /* FUNCTIONS ***************************************************************/
21 /* Implemented in except.s */
24 RtlpCaptureContext(PCONTEXT pContext
);
26 #define SehpGetStackLimits(StackBase, StackLimit) \
28 (*(StackBase)) = NtCurrentTeb()->Tib->StackBase; \
29 (*(StackLimit)) = NtCurrentTeb()->Tib->StackLimit; \
32 #define SehpGetExceptionList() \
33 (PEXCEPTION_REGISTRATION)(NtCurrentTeb()->Tib.ExceptionList)
35 #define SehpSetExceptionList(NewExceptionList) \
36 NtCurrentTeb()->Tib.ExceptionList = (PVOID)(NewExceptionList)
41 DbgPrint("Value 0x%.08x\n", Value
);
45 /* Declare a few prototypes for the functions in except.s */
48 RtlpExecuteHandlerForException(
49 PEXCEPTION_RECORD ExceptionRecord
,
50 PEXCEPTION_REGISTRATION RegistrationFrame
,
52 PVOID DispatcherContext
,
53 PEXCEPTION_HANDLER ExceptionHandler
);
56 RtlpExecuteHandlerForUnwind(
57 PEXCEPTION_RECORD ExceptionRecord
,
58 PEXCEPTION_REGISTRATION RegistrationFrame
,
60 PVOID DispatcherContext
,
61 PEXCEPTION_HANDLER ExceptionHandler
);
66 VOID
RtlpDumpExceptionRegistrations(VOID
)
68 PEXCEPTION_REGISTRATION Current
;
70 DbgPrint("Dumping exception registrations:\n");
72 Current
= SehpGetExceptionList();
74 if ((ULONG_PTR
)Current
!= -1)
76 while ((ULONG_PTR
)Current
!= -1)
78 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current
, Current
->handler
);
79 Current
= Current
->prev
;
81 DbgPrint(" End-Of-List\n");
83 DbgPrint(" No exception registrations exists.\n");
90 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
93 PEXCEPTION_REGISTRATION RegistrationFrame
, NestedFrame
= NULL
, DispatcherContext
;
96 DPRINT("RtlpDispatchException()\n");
99 RtlpDumpExceptionRegistrations();
102 RegistrationFrame
= SehpGetExceptionList();
104 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame
);
106 while ((ULONG_PTR
)RegistrationFrame
!= -1)
108 EXCEPTION_RECORD ExceptionRecord2
;
109 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
111 // Make sure the registration frame is located within the stack
113 DPRINT("Error checking\n");
115 if (Teb
->Tib
.StackBase
> RegistrationFrameEnd
)
117 DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
118 Teb
->Tib
.StackBase
, RegistrationFrameEnd
);
119 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
120 return ExceptionContinueExecution
;
122 // FIXME: Stack top, correct?
123 if (Teb
->Tib
.StackLimit
< RegistrationFrameEnd
)
125 DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
126 Teb
->Tib
.StackLimit
, RegistrationFrameEnd
);
127 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
128 return ExceptionContinueExecution
;
131 // Make sure stack is DWORD aligned
132 if ((ULONG_PTR
)RegistrationFrame
& 3)
134 DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
135 RegistrationFrameEnd
);
136 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
137 return ExceptionContinueExecution
;
144 RtlpLogLastExceptionDisposition( hLog
, retValue
);
147 DPRINT("Calling handler at 0x%X\n", RegistrationFrame
->handler
);
148 DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord
);
149 DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame
);
150 DPRINT("Context 0x%X\n", Context
);
151 DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext
);
153 ReturnValue
= RtlpExecuteHandlerForException(
158 RegistrationFrame
->handler
);
160 DPRINT("Exception handler said 0x%X\n", ReturnValue
);
161 DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame
);
163 PULONG sp
= (PULONG
)((PVOID
)RegistrationFrame
- 0x08);
164 DPRINT("StandardESP == 0x%.08x\n", sp
[0]);
165 DPRINT("Exception Pointers == 0x%.08x\n", sp
[1]);
166 DPRINT("PrevFrame == 0x%.08x\n", sp
[2]);
167 DPRINT("Handler == 0x%.08x\n", sp
[3]);
168 DPRINT("ScopeTable == 0x%.08x\n", sp
[4]);
169 DPRINT("TryLevel == 0x%.08x\n", sp
[5]);
170 DPRINT("EBP == 0x%.08x\n", sp
[6]);
173 if (RegistrationFrame
== NestedFrame
)
175 ExceptionRecord
->ExceptionFlags
&= ~EXCEPTION_NESTED_CALL
; // Turn off flag
179 if (ReturnValue
== ExceptionContinueExecution
)
181 DPRINT("ReturnValue == ExceptionContinueExecution\n");
182 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
)
184 DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
186 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
187 ExceptionRecord2
.ExceptionCode
= STATUS_NONCONTINUABLE_EXCEPTION
;
188 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
189 ExceptionRecord2
.NumberParameters
= 0;
190 RtlRaiseException(&ExceptionRecord2
);
194 /* Copy the (possibly changed) context back to the trap frame and return */
195 ZwContinue(Context
, FALSE
);
196 return ExceptionContinueExecution
;
199 else if (ReturnValue
== ExceptionContinueSearch
)
201 DPRINT("ReturnValue == ExceptionContinueSearch\n");
203 /* Nothing to do here */
205 else if (ReturnValue
== ExceptionNestedException
)
207 DPRINT("ReturnValue == ExceptionNestedException\n");
209 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_NESTED_CALL
;
210 if (NestedFrame
< DispatcherContext
)
212 NestedFrame
= DispatcherContext
;
215 else /* if (ReturnValue == ExceptionCollidedUnwind) */
217 DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
219 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
220 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
221 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
222 ExceptionRecord2
.NumberParameters
= 0;
223 RtlRaiseException(&ExceptionRecord2
);
226 RegistrationFrame
= RegistrationFrame
->prev
; // Go to previous frame
229 /* No exception handler will handle this exception */
231 DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
233 ExceptionRecord
->ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
235 return ExceptionContinueExecution
;
243 RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame
,
245 PEXCEPTION_RECORD ExceptionRecord
,
248 PEXCEPTION_REGISTRATION ERHead
;
249 PEXCEPTION_RECORD pExceptRec
;
250 EXCEPTION_RECORD TempER
;
253 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame
);
256 RtlpDumpExceptionRegistrations();
259 ERHead
= SehpGetExceptionList();
261 DPRINT("ERHead is 0x%X\n", ERHead
);
263 if (ExceptionRecord
== NULL
) // The normal case
265 DPRINT("ExceptionRecord == NULL (normal)\n");
267 pExceptRec
= &TempER
;
268 pExceptRec
->ExceptionFlags
= 0;
269 pExceptRec
->ExceptionCode
= STATUS_UNWIND
;
270 pExceptRec
->ExceptionRecord
= NULL
;
271 pExceptRec
->ExceptionAddress
= ReturnAddress
;
272 pExceptRec
->ExceptionInformation
[0] = 0;
276 pExceptRec
= ExceptionRecord
;
279 if (RegistrationFrame
)
280 pExceptRec
->ExceptionFlags
|= EXCEPTION_UNWINDING
;
282 pExceptRec
->ExceptionFlags
|= (EXCEPTION_UNWINDING
|EXCEPTION_EXIT_UNWIND
);
285 DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec
->ExceptionFlags
);
286 if (pExceptRec
->ExceptionFlags
& EXCEPTION_UNWINDING
)
288 DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING
);
290 if (pExceptRec
->ExceptionFlags
& EXCEPTION_EXIT_UNWIND
)
292 DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND
);
296 Context
.ContextFlags
=
297 (CONTEXT_i386
| CONTEXT_CONTROL
| CONTEXT_INTEGER
| CONTEXT_SEGMENTS
);
299 RtlpCaptureContext(&Context
);
301 DPRINT("Context.Eip = 0x%.08x\n", Context
.Eip
);
302 DPRINT("Context.Ebp = 0x%.08x\n", Context
.Ebp
);
303 DPRINT("Context.Esp = 0x%.08x\n", Context
.Esp
);
306 Context
.Eax
= EaxValue
;
308 // Begin traversing the list of EXCEPTION_REGISTRATION
309 while ((ULONG_PTR
)ERHead
!= -1 && ERHead
!= RegistrationFrame
)
311 EXCEPTION_RECORD er2
;
313 DPRINT("ERHead 0x%X\n", ERHead
);
315 // If there's an exception frame, but it's lower on the stack
316 // than the head of the exception list, something's wrong!
317 if (RegistrationFrame
&& (RegistrationFrame
<= ERHead
))
319 DPRINT("The exception frame is bad\n");
321 // Generate an exception to bail out
322 er2
.ExceptionRecord
= pExceptRec
;
323 er2
.NumberParameters
= 0;
324 er2
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
325 er2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
327 RtlRaiseException(&er2
);
331 Stack
= ERHead
+ sizeof(EXCEPTION_REGISTRATION
);
332 if ( (Teb
->Tib
.StackBase
<= (PVOID
)ERHead
) // Make sure that ERHead
333 && (Teb
->Tib
.->StackLimit
>= (PVOID
)Stack
) // is in range, and a multiple
334 && (0 == ((ULONG_PTR
)ERHead
& 3)) ) // of 4 (i.e., sane)
339 PEXCEPTION_REGISTRATION NewERHead
;
340 PEXCEPTION_REGISTRATION pCurrExceptReg
;
341 EXCEPTION_DISPOSITION ReturnValue
;
343 DPRINT("Executing handler at 0x%X for unwind\n", ERHead
->handler
);
345 ReturnValue
= RtlpExecuteHandlerForUnwind(
352 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead
->handler
, ReturnValue
);
354 if (ReturnValue
!= ExceptionContinueSearch
)
356 if (ReturnValue
!= ExceptionCollidedUnwind
)
358 DPRINT("Bad return value\n");
360 er2
.ExceptionRecord
= pExceptRec
;
361 er2
.NumberParameters
= 0;
362 er2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
363 er2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
365 RtlRaiseException(&er2
);
373 pCurrExceptReg
= ERHead
;
374 ERHead
= ERHead
->prev
;
376 DPRINT("New ERHead is 0x%X\n", ERHead
);
378 DPRINT("Setting exception registration at 0x%X as current\n",
379 /*RegistrationFrame->prev*/ pCurrExceptReg
->prev
);
381 // Unlink the exception handler
382 SehpSetExceptionList(pCurrExceptReg
->prev
);
384 else // The stack looks goofy! Raise an exception to bail out
386 DPRINT("Bad stack\n");
388 er2
.ExceptionRecord
= pExceptRec
;
389 er2
.NumberParameters
= 0;
390 er2
.ExceptionCode
= STATUS_BAD_STACK
;
391 er2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
393 RtlRaiseException(&er2
);