3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Kernel-mode exception support for IA-32
6 * FILE: ntoskrnl/rtl/i386/exception.c
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
10 /* INCLUDES *****************************************************************/
13 #include <internal/ke.h>
14 #include <internal/ps.h>
19 /* FUNCTIONS ***************************************************************/
25 MsvcrtDebug(ULONG Value)
27 DbgPrint("KernelDebug 0x%.08x\n", Value);
32 _abnormal_termination(void)
34 DbgPrint("Abnormal Termination\n");
42 struct _EXCEPTION_RECORD *ExceptionRecord,
43 void *RegistrationFrame,
44 struct _CONTEXT *ContextRecord,
45 void *DispatcherContext)
47 DbgPrint("_except_handler2()\n");
48 return (EXCEPTION_DISPOSITION)0;
51 #endif /* LIBCAPTIVE */
56 #endif /* LIBCAPTIVE */
57 _global_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame)
59 RtlUnwind(RegistrationFrame, &&__ret_label, NULL, 0);
61 // return is important
67 /* Implemented in except.s */
70 RtlpCaptureContext(PCONTEXT pContext);
72 /* Macros that will help streamline the SEH implementations for
73 kernel mode and user mode */
75 #define SehpGetStackLimits(StackBase, StackLimit) \
77 (*(StackBase)) = KeGetCurrentKPCR()->StackBase; \
78 (*(StackLimit)) = KeGetCurrentKPCR()->StackLimit; \
81 #endif /* LIBCAPTIVE */
85 #define SehpGetExceptionList() \
86 (PEXCEPTION_REGISTRATION)(KeGetCurrentThread()->TrapFrame ->ExceptionList)
88 #define SehpSetExceptionList(NewExceptionList) \
89 KeGetCurrentThread()->TrapFrame->ExceptionList = (PVOID)(NewExceptionList)
91 #else /* !LIBCAPTIVE */
93 extern guint32 fs_KPCR_ExceptionList;
95 #define SehpGetExceptionList() \
96 (PEXCEPTION_REGISTRATION)(fs_KPCR_ExceptionList)
98 #define SehpSetExceptionList(NewExceptionList) \
99 fs_KPCR_ExceptionList = (guint32)(PVOID)(NewExceptionList)
101 #endif /* LIBCAPTIVE */
105 #define SehpCaptureContext(Context) \
107 KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \
110 /*** Code below this line is shared with lib/ntdll/arch/ia32/exception.c - please keep in sync ***/
113 AsmDebug(ULONG Value)
115 DbgPrint("Value 0x%.08x\n", Value);
119 /* Declare a few prototypes for the functions in except.s */
121 #endif /* LIBCAPTIVE */
123 EXCEPTION_DISPOSITION
124 RtlpExecuteHandlerForException(
125 PEXCEPTION_RECORD ExceptionRecord,
126 PEXCEPTION_REGISTRATION RegistrationFrame,
128 PVOID DispatcherContext,
129 PEXCEPTION_HANDLER ExceptionHandler);
131 EXCEPTION_DISPOSITION
132 RtlpExecuteHandlerForUnwind(
133 PEXCEPTION_RECORD ExceptionRecord,
134 PEXCEPTION_REGISTRATION RegistrationFrame,
136 PVOID DispatcherContext,
137 PEXCEPTION_HANDLER ExceptionHandler);
143 VOID RtlpDumpExceptionRegistrations(VOID)
145 PEXCEPTION_REGISTRATION Current;
147 DbgPrint("Dumping exception registrations:\n");
149 Current = SehpGetExceptionList();
151 if ((ULONG_PTR)Current != -1)
153 while ((ULONG_PTR)Current != -1)
155 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler);
156 Current = Current->prev;
158 DbgPrint(" End-Of-List\n");
160 DbgPrint(" No exception registrations exists.\n");
166 #endif /* LIBCAPTIVE */
169 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
172 PEXCEPTION_REGISTRATION RegistrationFrame;
173 DWORD DispatcherContext;
176 DPRINT("RtlpDispatchException()\n");
179 RtlpDumpExceptionRegistrations();
182 RegistrationFrame = SehpGetExceptionList();
184 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
186 while ((ULONG_PTR)RegistrationFrame != (ULONG_PTR)-1)
188 EXCEPTION_RECORD ExceptionRecord2;
190 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
192 // Make sure the registration frame is located within the stack
194 DPRINT("Error checking\n");
196 if (Teb->Tib.StackBase > RegistrationFrameEnd)
198 DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
199 Teb->Tib.StackBase, RegistrationFrameEnd);
200 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
201 return ExceptionContinueExecution;
203 // FIXME: Stack top, correct?
204 if (Teb->Tib.StackLimit < RegistrationFrameEnd)
206 DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
207 Teb->Tib.StackLimit, RegistrationFrameEnd);
208 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
209 return ExceptionContinueExecution;
212 // Make sure stack is DWORD aligned
213 if ((ULONG_PTR)RegistrationFrame & 3)
215 DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
216 RegistrationFrameEnd);
217 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
218 return ExceptionContinueExecution;
225 RtlpLogLastExceptionDisposition( hLog, retValue );
228 DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler);
229 DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord);
230 DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame);
231 DPRINT("Context 0x%X\n", Context);
232 DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext);
234 ReturnValue = RtlpExecuteHandlerForException(
239 RegistrationFrame->handler);
243 DPRINT("Exception handler said 0x%X\n", ReturnValue);
244 DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame);
246 PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08);
247 DPRINT("StandardESP == 0x%.08x\n", sp[0]);
248 DPRINT("Exception Pointers == 0x%.08x\n", sp[1]);
249 DPRINT("PrevFrame == 0x%.08x\n", sp[2]);
250 DPRINT("Handler == 0x%.08x\n", sp[3]);
251 DPRINT("ScopeTable == 0x%.08x\n", sp[4]);
252 DPRINT("TryLevel == 0x%.08x\n", sp[5]);
253 DPRINT("EBP == 0x%.08x\n", sp[6]);
258 if (RegistrationFrame == NULL)
260 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag
263 if (ReturnValue == ExceptionContinueExecution)
265 DPRINT("ReturnValue == ExceptionContinueExecution\n");
266 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
268 DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
270 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
271 ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
272 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
273 ExceptionRecord2.NumberParameters = 0;
274 RtlRaiseException(&ExceptionRecord2);
278 /* Copy the (possibly changed) context back to the trap frame and return */
280 NtContinue(Context, FALSE);
281 #else /* !LIBCAPTIVE */
283 #endif /* LIBCAPTIVE */
284 return ExceptionContinueExecution;
287 else if (ReturnValue == ExceptionContinueSearch)
289 DPRINT("ReturnValue == ExceptionContinueSearch\n");
291 /* Nothing to do here */
293 else if (ReturnValue == ExceptionNestedException)
295 DPRINT("ReturnValue == ExceptionNestedException\n");
297 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
298 if (DispatcherContext > Temp)
300 Temp = DispatcherContext;
303 else /* if (ReturnValue == ExceptionCollidedUnwind) */
305 DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
307 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
308 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
309 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
310 ExceptionRecord2.NumberParameters = 0;
311 RtlRaiseException(&ExceptionRecord2);
314 RegistrationFrame = RegistrationFrame->prev; // Go to previous frame
317 /* No exception handler will handle this exception */
319 DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
321 return ExceptionContinueExecution;
327 RtlRaiseStatus(NTSTATUS Status)
329 EXCEPTION_RECORD ExceptionRecord;
331 DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status);
333 ExceptionRecord.ExceptionCode = Status;
334 ExceptionRecord.ExceptionRecord = NULL;
335 ExceptionRecord.NumberParameters = 0;
336 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
337 RtlRaiseException (& ExceptionRecord);
340 #endif /* LIBCAPTIVE */
343 RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame,
345 PEXCEPTION_RECORD ExceptionRecord,
348 PEXCEPTION_REGISTRATION ERHead;
349 PEXCEPTION_RECORD pExceptRec;
350 EXCEPTION_RECORD TempER;
353 #endif /* LIBCAPTIVE */
355 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame);
358 RtlpDumpExceptionRegistrations();
361 ERHead = SehpGetExceptionList();
363 DPRINT("ERHead is 0x%X\n", ERHead);
365 if (ExceptionRecord == NULL) // The normal case
367 DPRINT("ExceptionRecord == NULL (normal)\n");
369 pExceptRec = &TempER;
370 pExceptRec->ExceptionFlags = 0;
371 pExceptRec->ExceptionCode = STATUS_UNWIND;
372 pExceptRec->ExceptionRecord = NULL;
373 pExceptRec->ExceptionAddress = ReturnAddress;
374 pExceptRec->ExceptionInformation[0] = 0;
377 if (RegistrationFrame)
378 pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING;
380 pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND);
383 DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags);
384 if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING)
386 DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING);
388 if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND)
390 DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND);
395 Context.ContextFlags =
396 (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS);
398 SehpCaptureContext(&Context);
400 DPRINT("Context.Eip = 0x%.08x\n", Context.Eip);
401 DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp);
402 DPRINT("Context.Esp = 0x%.08x\n", Context.Esp);
405 Context.Eax = EaxValue;
406 #endif /* LIBCAPTIVE */
408 // Begin traversing the list of EXCEPTION_REGISTRATION
409 while ((ULONG_PTR)ERHead != (ULONG_PTR)-1)
411 EXCEPTION_RECORD er2;
413 DPRINT("ERHead 0x%X\n", ERHead);
415 if (ERHead == RegistrationFrame)
417 DPRINT("Continueing execution\n");
419 NtContinue(&Context, FALSE);
420 #else /* !LIBCAPTIVE */
421 /* FIXME: What to do there? */
422 #endif /* LIBCAPTIVE */
427 // If there's an exception frame, but it's lower on the stack
428 // than the head of the exception list, something's wrong!
429 if (RegistrationFrame && (RegistrationFrame <= ERHead))
431 DPRINT("The exception frame is bad\n");
433 // Generate an exception to bail out
434 er2.ExceptionRecord = pExceptRec;
435 er2.NumberParameters = 0;
436 er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
437 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
439 RtlRaiseException(&er2);
444 Stack = ERHead + sizeof(EXCEPTION_REGISTRATION);
445 if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead
446 && (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple
447 && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane)
452 PEXCEPTION_REGISTRATION NewERHead;
453 PEXCEPTION_REGISTRATION pCurrExceptReg;
454 EXCEPTION_DISPOSITION ReturnValue;
456 DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler);
458 ReturnValue = RtlpExecuteHandlerForUnwind(
463 #else /* !LIBCAPTIVE */
465 #endif /* LIBCAPTIVE */
469 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue);
471 if (ReturnValue != ExceptionContinueSearch)
473 if (ReturnValue != ExceptionCollidedUnwind)
475 DPRINT("Bad return value\n");
477 er2.ExceptionRecord = pExceptRec;
478 er2.NumberParameters = 0;
479 er2.ExceptionCode = STATUS_INVALID_DISPOSITION;
480 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
482 RtlRaiseException(&er2);
490 pCurrExceptReg = ERHead;
491 ERHead = ERHead->prev;
493 DPRINT("New ERHead is 0x%X\n", ERHead);
495 DPRINT("Setting exception registration at 0x%X as current\n",
496 RegistrationFrame->prev);
498 // Unlink the exception handler
499 SehpSetExceptionList(RegistrationFrame->prev);
501 else // The stack looks goofy! Raise an exception to bail out
503 DPRINT("Bad stack\n");
505 er2.ExceptionRecord = pExceptRec;
506 er2.NumberParameters = 0;
507 er2.ExceptionCode = STATUS_BAD_STACK;
508 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
510 RtlRaiseException(&er2);
514 // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
515 // This shouldn't happen normally.
517 DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
521 if ((ULONG_PTR)RegistrationFrame == (ULONG_PTR)-1)
522 NtContinue(&Context, FALSE);
524 NtRaiseException(pExceptRec, &Context, 0);
525 #else /* !LIBCAPTIVE */
527 #endif /* LIBCAPTIVE */