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 ***************************************************************/
23 MsvcrtDebug(ULONG Value)
25 DbgPrint("KernelDebug 0x%.08x\n", Value);
33 _abnormal_termination(void)
35 DbgPrint("Abnormal Termination\n");
46 struct _EXCEPTION_RECORD *ExceptionRecord,
47 void *RegistrationFrame,
48 struct _CONTEXT *ContextRecord,
49 void *DispatcherContext)
51 DbgPrint("_except_handler2()\n");
52 return (EXCEPTION_DISPOSITION)0;
59 _global_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame)
61 RtlUnwind(RegistrationFrame, &&__ret_label, NULL, 0);
63 // return is important
68 /* Implemented in except.s */
71 RtlpCaptureContext(PCONTEXT pContext);
73 /* Macros that will help streamline the SEH implementations for
74 kernel mode and user mode */
76 #define SehpGetStackLimits(StackBase, StackLimit) \
78 (*(StackBase)) = KeGetCurrentKPCR()->StackBase; \
79 (*(StackLimit)) = KeGetCurrentKPCR()->StackLimit; \
82 #define SehpGetExceptionList() \
83 (PEXCEPTION_REGISTRATION)(KeGetCurrentThread()->TrapFrame ->ExceptionList)
85 #define SehpSetExceptionList(NewExceptionList) \
86 KeGetCurrentThread()->TrapFrame->ExceptionList = (PVOID)(NewExceptionList)
88 #define SehpCaptureContext(Context) \
90 KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \
93 #define SehpContinue(Context, TestAlert) \
94 ZwContinue(Context, TestAlert)
96 /*** Code below this line is shared with lib/ntdll/rtl/i386/exception.c - please keep in sync ***/
101 DbgPrint("Value 0x%.08x\n", Value);
105 /* Declare a few prototypes for the functions in except.s */
107 EXCEPTION_DISPOSITION
108 RtlpExecuteHandlerForException(
109 PEXCEPTION_RECORD ExceptionRecord,
110 PEXCEPTION_REGISTRATION RegistrationFrame,
112 PVOID DispatcherContext,
113 PEXCEPTION_HANDLER ExceptionHandler);
115 EXCEPTION_DISPOSITION
116 RtlpExecuteHandlerForUnwind(
117 PEXCEPTION_RECORD ExceptionRecord,
118 PEXCEPTION_REGISTRATION RegistrationFrame,
120 PVOID DispatcherContext,
121 PEXCEPTION_HANDLER ExceptionHandler);
126 VOID RtlpDumpExceptionRegistrations(VOID)
128 PEXCEPTION_REGISTRATION Current;
130 DbgPrint("Dumping exception registrations:\n");
132 Current = SehpGetExceptionList();
134 if ((ULONG_PTR)Current != -1)
136 while ((ULONG_PTR)Current != -1)
138 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler);
139 Current = Current->prev;
141 DbgPrint(" End-Of-List\n");
143 DbgPrint(" No exception registrations exists.\n");
150 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
153 PEXCEPTION_REGISTRATION RegistrationFrame;
154 DWORD DispatcherContext;
157 DPRINT("RtlpDispatchException()\n");
160 RtlpDumpExceptionRegistrations();
163 RegistrationFrame = SehpGetExceptionList();
165 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
167 /* Check if there are any exception handlers at all. */
168 if ((ULONG_PTR)RegistrationFrame == (ULONG_PTR)-1)
170 ExceptionRecord->ExceptionFlags |= EXCEPTION_NONCONTINUABLE;
171 return ExceptionContinueExecution;
174 while ((ULONG_PTR)RegistrationFrame != (ULONG_PTR)-1)
176 EXCEPTION_RECORD ExceptionRecord2;
178 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
180 // Make sure the registration frame is located within the stack
182 DPRINT("Error checking\n");
184 if (Teb->Tib.StackBase > RegistrationFrameEnd)
186 DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
187 Teb->Tib.StackBase, RegistrationFrameEnd);
188 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
189 return ExceptionContinueExecution;
191 // FIXME: Stack top, correct?
192 if (Teb->Tib.StackLimit < RegistrationFrameEnd)
194 DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
195 Teb->Tib.StackLimit, RegistrationFrameEnd);
196 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
197 return ExceptionContinueExecution;
200 // Make sure stack is DWORD aligned
201 if ((ULONG_PTR)RegistrationFrame & 3)
203 DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
204 RegistrationFrameEnd);
205 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
206 return ExceptionContinueExecution;
213 RtlpLogLastExceptionDisposition( hLog, retValue );
216 DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler);
217 DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord);
218 DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame);
219 DPRINT("Context 0x%X\n", Context);
220 DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext);
222 ReturnValue = RtlpExecuteHandlerForException(
227 RegistrationFrame->handler);
231 DPRINT("Exception handler said 0x%X\n", ReturnValue);
232 DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame);
234 PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08);
235 DPRINT("StandardESP == 0x%.08x\n", sp[0]);
236 DPRINT("Exception Pointers == 0x%.08x\n", sp[1]);
237 DPRINT("PrevFrame == 0x%.08x\n", sp[2]);
238 DPRINT("Handler == 0x%.08x\n", sp[3]);
239 DPRINT("ScopeTable == 0x%.08x\n", sp[4]);
240 DPRINT("TryLevel == 0x%.08x\n", sp[5]);
241 DPRINT("EBP == 0x%.08x\n", sp[6]);
246 if (RegistrationFrame == NULL)
248 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag
251 if (ReturnValue == ExceptionContinueExecution)
253 DPRINT("ReturnValue == ExceptionContinueExecution\n");
254 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
256 DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
258 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
259 ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
260 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
261 ExceptionRecord2.NumberParameters = 0;
262 RtlRaiseException(&ExceptionRecord2);
266 /* Copy the (possibly changed) context back to the trap frame and return */
267 SehpContinue(Context, FALSE);
268 return ExceptionContinueExecution;
271 else if (ReturnValue == ExceptionContinueSearch)
273 DPRINT("ReturnValue == ExceptionContinueSearch\n");
275 /* Nothing to do here */
277 else if (ReturnValue == ExceptionNestedException)
279 DPRINT("ReturnValue == ExceptionNestedException\n");
281 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
282 if (DispatcherContext > Temp)
284 Temp = DispatcherContext;
287 else /* if (ReturnValue == ExceptionCollidedUnwind) */
289 DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
291 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
292 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
293 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
294 ExceptionRecord2.NumberParameters = 0;
295 RtlRaiseException(&ExceptionRecord2);
298 RegistrationFrame = RegistrationFrame->prev; // Go to previous frame
301 /* No exception handler will handle this exception */
303 DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
305 return ExceptionContinueExecution;
309 RtlRaiseStatus(NTSTATUS Status)
311 EXCEPTION_RECORD ExceptionRecord;
313 DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status);
315 ExceptionRecord.ExceptionCode = Status;
316 ExceptionRecord.ExceptionRecord = NULL;
317 ExceptionRecord.NumberParameters = 0;
318 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
319 RtlRaiseException (& ExceptionRecord);
326 RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame,
328 PEXCEPTION_RECORD ExceptionRecord,
331 PEXCEPTION_REGISTRATION ERHead;
332 PEXCEPTION_RECORD pExceptRec;
333 EXCEPTION_RECORD TempER;
336 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame);
339 RtlpDumpExceptionRegistrations();
342 ERHead = SehpGetExceptionList();
344 DPRINT("ERHead is 0x%X\n", ERHead);
346 pExceptRec = &TempER;
348 if (ExceptionRecord == NULL) // The normal case
350 DPRINT("ExceptionRecord == NULL (normal)\n");
352 pExceptRec->ExceptionFlags = 0;
353 pExceptRec->ExceptionCode = STATUS_UNWIND;
354 pExceptRec->ExceptionRecord = NULL;
355 pExceptRec->ExceptionAddress = ReturnAddress;
356 pExceptRec->ExceptionInformation[0] = 0;
359 if (RegistrationFrame)
360 pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING;
362 pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND);
365 DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags);
366 if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING)
368 DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING);
370 if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND)
372 DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND);
376 Context.ContextFlags =
377 (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS);
379 SehpCaptureContext(&Context);
381 DPRINT("Context.Eip = 0x%.08x\n", Context.Eip);
382 DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp);
383 DPRINT("Context.Esp = 0x%.08x\n", Context.Esp);
386 Context.Eax = EaxValue;
388 // Begin traversing the list of EXCEPTION_REGISTRATION
389 while ((ULONG_PTR)ERHead != (ULONG_PTR)-1)
391 EXCEPTION_RECORD er2;
393 DPRINT("ERHead 0x%X\n", ERHead);
395 if (ERHead == RegistrationFrame)
397 DPRINT("Continueing execution\n");
398 SehpContinue(&Context, FALSE);
403 // If there's an exception frame, but it's lower on the stack
404 // than the head of the exception list, something's wrong!
405 if (RegistrationFrame && (RegistrationFrame <= ERHead))
407 DPRINT("The exception frame is bad\n");
409 // Generate an exception to bail out
410 er2.ExceptionRecord = pExceptRec;
411 er2.NumberParameters = 0;
412 er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
413 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
415 RtlRaiseException(&er2);
420 Stack = ERHead + sizeof(EXCEPTION_REGISTRATION);
421 if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead
422 && (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple
423 && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane)
428 PEXCEPTION_REGISTRATION NewERHead;
429 PEXCEPTION_REGISTRATION pCurrExceptReg;
430 EXCEPTION_DISPOSITION ReturnValue;
432 DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler);
434 ReturnValue = RtlpExecuteHandlerForUnwind(
441 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue);
443 if (ReturnValue != ExceptionContinueSearch)
445 if (ReturnValue != ExceptionCollidedUnwind)
447 DPRINT("Bad return value\n");
449 er2.ExceptionRecord = pExceptRec;
450 er2.NumberParameters = 0;
451 er2.ExceptionCode = STATUS_INVALID_DISPOSITION;
452 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
454 RtlRaiseException(&er2);
462 pCurrExceptReg = ERHead;
463 ERHead = ERHead->prev;
465 DPRINT("New ERHead is 0x%X\n", ERHead);
467 DPRINT("Setting exception registration at 0x%X as current\n",
468 RegistrationFrame->prev);
470 // Unlink the exception handler
471 SehpSetExceptionList(RegistrationFrame->prev);
473 else // The stack looks goofy! Raise an exception to bail out
475 DPRINT("Bad stack\n");
477 er2.ExceptionRecord = pExceptRec;
478 er2.NumberParameters = 0;
479 er2.ExceptionCode = STATUS_BAD_STACK;
480 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
482 RtlRaiseException(&er2);
486 // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
487 // This shouldn't happen normally.
489 DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
492 if ((ULONG_PTR)RegistrationFrame == (ULONG_PTR)-1)
493 SehpContinue(&Context, FALSE);
495 NtRaiseException(pExceptRec, &Context, 0);