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 /* Macros that will help streamline the SEH implementations for
27 kernel mode and user mode */
29 #define SehpGetStackLimits(StackBase, StackLimit) \
31 (*(StackBase)) = NtCurrentTeb()->Tib->StackBase; \
32 (*(StackLimit)) = NtCurrentTeb()->Tib->StackLimit; \
35 #define SehpGetExceptionList() \
36 (PEXCEPTION_REGISTRATION)(NtCurrentTeb()->Tib.ExceptionList)
38 #define SehpSetExceptionList(NewExceptionList) \
39 NtCurrentTeb()->Tib.ExceptionList = (PVOID)(NewExceptionList)
41 #define SehpCaptureContext(Context) \
43 RtlpCaptureContext(Context); \
46 #define SehpContinue(Context, TestAlert) \
47 NtContinue(Context, TestAlert)
49 /*** Code below this line is shared with ntoskrnl/rtl/i386/exception.c - please keep in sync ***/
54 DbgPrint("Value 0x%.08x\n", Value
);
58 /* Declare a few prototypes for the functions in except.s */
61 RtlpExecuteHandlerForException(
62 PEXCEPTION_RECORD ExceptionRecord
,
63 PEXCEPTION_REGISTRATION RegistrationFrame
,
65 PVOID DispatcherContext
,
66 PEXCEPTION_HANDLER ExceptionHandler
);
69 RtlpExecuteHandlerForUnwind(
70 PEXCEPTION_RECORD ExceptionRecord
,
71 PEXCEPTION_REGISTRATION RegistrationFrame
,
73 PVOID DispatcherContext
,
74 PEXCEPTION_HANDLER ExceptionHandler
);
79 VOID
RtlpDumpExceptionRegistrations(VOID
)
81 PEXCEPTION_REGISTRATION Current
;
83 DbgPrint("Dumping exception registrations:\n");
85 Current
= SehpGetExceptionList();
87 if ((ULONG_PTR
)Current
!= -1)
89 while ((ULONG_PTR
)Current
!= -1)
91 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current
, Current
->handler
);
92 Current
= Current
->prev
;
94 DbgPrint(" End-Of-List\n");
96 DbgPrint(" No exception registrations exists.\n");
103 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
106 PEXCEPTION_REGISTRATION RegistrationFrame
;
107 DWORD DispatcherContext
;
110 DPRINT("RtlpDispatchException()\n");
113 RtlpDumpExceptionRegistrations();
116 RegistrationFrame
= SehpGetExceptionList();
118 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame
);
120 while ((ULONG_PTR
)RegistrationFrame
!= -1)
122 EXCEPTION_RECORD ExceptionRecord2
;
124 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
126 // Make sure the registration frame is located within the stack
128 DPRINT("Error checking\n");
130 if (Teb
->Tib
.StackBase
> RegistrationFrameEnd
)
132 DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
133 Teb
->Tib
.StackBase
, RegistrationFrameEnd
);
134 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
135 return ExceptionContinueExecution
;
137 // FIXME: Stack top, correct?
138 if (Teb
->Tib
.StackLimit
< RegistrationFrameEnd
)
140 DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
141 Teb
->Tib
.StackLimit
, RegistrationFrameEnd
);
142 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
143 return ExceptionContinueExecution
;
146 // Make sure stack is DWORD aligned
147 if ((ULONG_PTR
)RegistrationFrame
& 3)
149 DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
150 RegistrationFrameEnd
);
151 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_STACK_INVALID
;
152 return ExceptionContinueExecution
;
159 RtlpLogLastExceptionDisposition( hLog
, retValue
);
162 DPRINT("Calling handler at 0x%X\n", RegistrationFrame
->handler
);
163 DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord
);
164 DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame
);
165 DPRINT("Context 0x%X\n", Context
);
166 DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext
);
168 ReturnValue
= RtlpExecuteHandlerForException(
173 RegistrationFrame
->handler
);
175 DPRINT("Exception handler said 0x%X\n", ReturnValue
);
176 DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame
);
178 PULONG sp
= (PULONG
)((PVOID
)RegistrationFrame
- 0x08);
179 DPRINT("StandardESP == 0x%.08x\n", sp
[0]);
180 DPRINT("Exception Pointers == 0x%.08x\n", sp
[1]);
181 DPRINT("PrevFrame == 0x%.08x\n", sp
[2]);
182 DPRINT("Handler == 0x%.08x\n", sp
[3]);
183 DPRINT("ScopeTable == 0x%.08x\n", sp
[4]);
184 DPRINT("TryLevel == 0x%.08x\n", sp
[5]);
185 DPRINT("EBP == 0x%.08x\n", sp
[6]);
188 if (RegistrationFrame
== NULL
)
190 ExceptionRecord
->ExceptionFlags
&= ~EXCEPTION_NESTED_CALL
; // Turn off flag
193 if (ReturnValue
== ExceptionContinueExecution
)
195 DPRINT("ReturnValue == ExceptionContinueExecution\n");
196 if (ExceptionRecord
->ExceptionFlags
& EXCEPTION_NONCONTINUABLE
)
198 DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
200 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
201 ExceptionRecord2
.ExceptionCode
= STATUS_NONCONTINUABLE_EXCEPTION
;
202 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
203 ExceptionRecord2
.NumberParameters
= 0;
204 RtlRaiseException(&ExceptionRecord2
);
208 /* Copy the (possibly changed) context back to the trap frame and return */
209 SehpContinue(Context
, FALSE
);
210 return ExceptionContinueExecution
;
213 else if (ReturnValue
== ExceptionContinueSearch
)
215 DPRINT("ReturnValue == ExceptionContinueSearch\n");
217 /* Nothing to do here */
219 else if (ReturnValue
== ExceptionNestedException
)
221 DPRINT("ReturnValue == ExceptionNestedException\n");
223 ExceptionRecord
->ExceptionFlags
|= EXCEPTION_EXIT_UNWIND
;
224 if (DispatcherContext
> Temp
)
226 Temp
= DispatcherContext
;
229 else /* if (ReturnValue == ExceptionCollidedUnwind) */
231 DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
233 ExceptionRecord2
.ExceptionRecord
= ExceptionRecord
;
234 ExceptionRecord2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
235 ExceptionRecord2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
236 ExceptionRecord2
.NumberParameters
= 0;
237 RtlRaiseException(&ExceptionRecord2
);
240 RegistrationFrame
= RegistrationFrame
->prev
; // Go to previous frame
243 /* No exception handler will handle this exception */
245 DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
247 return ExceptionContinueExecution
;
254 RtlRaiseStatus(NTSTATUS Status
)
256 EXCEPTION_RECORD ExceptionRecord
;
258 DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status
);
260 ExceptionRecord
.ExceptionCode
= Status
;
261 ExceptionRecord
.ExceptionRecord
= NULL
;
262 ExceptionRecord
.NumberParameters
= 0;
263 ExceptionRecord
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
264 RtlRaiseException (& ExceptionRecord
);
271 RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame
,
273 PEXCEPTION_RECORD ExceptionRecord
,
276 PEXCEPTION_REGISTRATION ERHead
;
277 PEXCEPTION_RECORD pExceptRec
;
278 EXCEPTION_RECORD TempER
;
281 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame
);
284 RtlpDumpExceptionRegistrations();
287 ERHead
= SehpGetExceptionList();
289 DPRINT("ERHead is 0x%X\n", ERHead
);
291 if (ExceptionRecord
== NULL
) // The normal case
293 DPRINT("ExceptionRecord == NULL (normal)\n");
295 pExceptRec
= &TempER
;
296 pExceptRec
->ExceptionFlags
= 0;
297 pExceptRec
->ExceptionCode
= STATUS_UNWIND
;
298 pExceptRec
->ExceptionRecord
= NULL
;
299 pExceptRec
->ExceptionAddress
= ReturnAddress
;
300 pExceptRec
->ExceptionInformation
[0] = 0;
304 pExceptRec
= ExceptionRecord
;
307 if (RegistrationFrame
)
308 pExceptRec
->ExceptionFlags
|= EXCEPTION_UNWINDING
;
310 pExceptRec
->ExceptionFlags
|= (EXCEPTION_UNWINDING
|EXCEPTION_EXIT_UNWIND
);
313 DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec
->ExceptionFlags
);
314 if (pExceptRec
->ExceptionFlags
& EXCEPTION_UNWINDING
)
316 DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING
);
318 if (pExceptRec
->ExceptionFlags
& EXCEPTION_EXIT_UNWIND
)
320 DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND
);
324 Context
.ContextFlags
=
325 (CONTEXT_i386
| CONTEXT_CONTROL
| CONTEXT_INTEGER
| CONTEXT_SEGMENTS
);
327 SehpCaptureContext(&Context
);
329 DPRINT("Context.Eip = 0x%.08x\n", Context
.Eip
);
330 DPRINT("Context.Ebp = 0x%.08x\n", Context
.Ebp
);
331 DPRINT("Context.Esp = 0x%.08x\n", Context
.Esp
);
334 Context
.Eax
= EaxValue
;
336 // Begin traversing the list of EXCEPTION_REGISTRATION
337 while ((ULONG_PTR
)ERHead
!= -1)
339 EXCEPTION_RECORD er2
;
341 DPRINT("ERHead 0x%X\n", ERHead
);
343 if (ERHead
== RegistrationFrame
)
345 DPRINT("Continueing execution\n");
346 SehpContinue(&Context
, FALSE
);
351 // If there's an exception frame, but it's lower on the stack
352 // than the head of the exception list, something's wrong!
353 if (RegistrationFrame
&& (RegistrationFrame
<= ERHead
))
355 DPRINT("The exception frame is bad\n");
357 // Generate an exception to bail out
358 er2
.ExceptionRecord
= pExceptRec
;
359 er2
.NumberParameters
= 0;
360 er2
.ExceptionCode
= STATUS_INVALID_UNWIND_TARGET
;
361 er2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
363 RtlRaiseException(&er2
);
368 Stack
= ERHead
+ sizeof(EXCEPTION_REGISTRATION
);
369 if ( (Teb
->Tib
.StackBase
<= (PVOID
)ERHead
) // Make sure that ERHead
370 && (Teb
->Tib
.->StackLimit
>= (PVOID
)Stack
) // is in range, and a multiple
371 && (0 == ((ULONG_PTR
)ERHead
& 3)) ) // of 4 (i.e., sane)
376 PEXCEPTION_REGISTRATION NewERHead
;
377 PEXCEPTION_REGISTRATION pCurrExceptReg
;
378 EXCEPTION_DISPOSITION ReturnValue
;
380 DPRINT("Executing handler at 0x%X for unwind\n", ERHead
->handler
);
382 ReturnValue
= RtlpExecuteHandlerForUnwind(
389 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead
->handler
, ReturnValue
);
391 if (ReturnValue
!= ExceptionContinueSearch
)
393 if (ReturnValue
!= ExceptionCollidedUnwind
)
395 DPRINT("Bad return value\n");
397 er2
.ExceptionRecord
= pExceptRec
;
398 er2
.NumberParameters
= 0;
399 er2
.ExceptionCode
= STATUS_INVALID_DISPOSITION
;
400 er2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
402 RtlRaiseException(&er2
);
410 pCurrExceptReg
= ERHead
;
411 ERHead
= ERHead
->prev
;
413 DPRINT("New ERHead is 0x%X\n", ERHead
);
415 DPRINT("Setting exception registration at 0x%X as current\n",
416 RegistrationFrame
->prev
);
418 // Unlink the exception handler
419 SehpSetExceptionList(RegistrationFrame
->prev
);
421 else // The stack looks goofy! Raise an exception to bail out
423 DPRINT("Bad stack\n");
425 er2
.ExceptionRecord
= pExceptRec
;
426 er2
.NumberParameters
= 0;
427 er2
.ExceptionCode
= STATUS_BAD_STACK
;
428 er2
.ExceptionFlags
= EXCEPTION_NONCONTINUABLE
;
430 RtlRaiseException(&er2
);
434 // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
435 // This shouldn't happen normally.
437 DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
440 if ((ULONG_PTR
)RegistrationFrame
== -1)
441 SehpContinue(&Context
, FALSE
);
443 NtRaiseException(pExceptRec
, &Context
, 0);