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);
30 _abnormal_termination(void)
32 DbgPrint("Abnormal Termination\n");
40 struct _EXCEPTION_RECORD *ExceptionRecord,
41 void *RegistrationFrame,
42 struct _CONTEXT *ContextRecord,
43 void *DispatcherContext)
45 DbgPrint("_except_handler2()\n");
46 return (EXCEPTION_DISPOSITION)0;
50 _global_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame)
52 RtlUnwind(RegistrationFrame, &&__ret_label, NULL, 0);
54 // return is important
59 /* Implemented in except.s */
62 RtlpCaptureContext(PCONTEXT pContext);
64 /* Macros that will help streamline the SEH implementations for
65 kernel mode and user mode */
67 #define SehpGetStackLimits(StackBase, StackLimit) \
69 (*(StackBase)) = KeGetCurrentKPCR()->StackBase; \
70 (*(StackLimit)) = KeGetCurrentKPCR()->StackLimit; \
73 #define SehpGetExceptionList() \
74 (PEXCEPTION_REGISTRATION)(KeGetCurrentThread()->TrapFrame ->ExceptionList)
76 #define SehpSetExceptionList(NewExceptionList) \
77 KeGetCurrentThread()->TrapFrame->ExceptionList = (PVOID)(NewExceptionList)
79 #define SehpCaptureContext(Context) \
81 KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \
84 /*** Code below this line is shared with lib/ntdll/arch/ia32/exception.c - please keep in sync ***/
89 DbgPrint("Value 0x%.08x\n", Value);
93 /* Declare a few prototypes for the functions in except.s */
96 RtlpExecuteHandlerForException(
97 PEXCEPTION_RECORD ExceptionRecord,
98 PEXCEPTION_REGISTRATION RegistrationFrame,
100 PVOID DispatcherContext,
101 PEXCEPTION_HANDLER ExceptionHandler);
103 EXCEPTION_DISPOSITION
104 RtlpExecuteHandlerForUnwind(
105 PEXCEPTION_RECORD ExceptionRecord,
106 PEXCEPTION_REGISTRATION RegistrationFrame,
108 PVOID DispatcherContext,
109 PEXCEPTION_HANDLER ExceptionHandler);
114 VOID RtlpDumpExceptionRegistrations(VOID)
116 PEXCEPTION_REGISTRATION Current;
118 DbgPrint("Dumping exception registrations:\n");
120 Current = SehpGetExceptionList();
122 if ((ULONG_PTR)Current != -1)
124 while ((ULONG_PTR)Current != -1)
126 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler);
127 Current = Current->prev;
129 DbgPrint(" End-Of-List\n");
131 DbgPrint(" No exception registrations exists.\n");
138 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
141 PEXCEPTION_REGISTRATION RegistrationFrame;
142 DWORD DispatcherContext;
145 DPRINT("RtlpDispatchException()\n");
148 RtlpDumpExceptionRegistrations();
151 RegistrationFrame = SehpGetExceptionList();
153 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
155 while ((ULONG_PTR)RegistrationFrame != (ULONG_PTR)-1)
157 EXCEPTION_RECORD ExceptionRecord2;
159 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
161 // Make sure the registration frame is located within the stack
163 DPRINT("Error checking\n");
165 if (Teb->Tib.StackBase > RegistrationFrameEnd)
167 DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
168 Teb->Tib.StackBase, RegistrationFrameEnd);
169 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
170 return ExceptionContinueExecution;
172 // FIXME: Stack top, correct?
173 if (Teb->Tib.StackLimit < RegistrationFrameEnd)
175 DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
176 Teb->Tib.StackLimit, RegistrationFrameEnd);
177 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
178 return ExceptionContinueExecution;
181 // Make sure stack is DWORD aligned
182 if ((ULONG_PTR)RegistrationFrame & 3)
184 DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
185 RegistrationFrameEnd);
186 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
187 return ExceptionContinueExecution;
194 RtlpLogLastExceptionDisposition( hLog, retValue );
197 DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler);
198 DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord);
199 DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame);
200 DPRINT("Context 0x%X\n", Context);
201 DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext);
203 ReturnValue = RtlpExecuteHandlerForException(
208 RegistrationFrame->handler);
212 DPRINT("Exception handler said 0x%X\n", ReturnValue);
213 DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame);
215 PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08);
216 DPRINT("StandardESP == 0x%.08x\n", sp[0]);
217 DPRINT("Exception Pointers == 0x%.08x\n", sp[1]);
218 DPRINT("PrevFrame == 0x%.08x\n", sp[2]);
219 DPRINT("Handler == 0x%.08x\n", sp[3]);
220 DPRINT("ScopeTable == 0x%.08x\n", sp[4]);
221 DPRINT("TryLevel == 0x%.08x\n", sp[5]);
222 DPRINT("EBP == 0x%.08x\n", sp[6]);
227 if (RegistrationFrame == NULL)
229 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag
232 if (ReturnValue == ExceptionContinueExecution)
234 DPRINT("ReturnValue == ExceptionContinueExecution\n");
235 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
237 DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
239 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
240 ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
241 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
242 ExceptionRecord2.NumberParameters = 0;
243 RtlRaiseException(&ExceptionRecord2);
247 /* Copy the (possibly changed) context back to the trap frame and return */
248 NtContinue(Context, FALSE);
249 return ExceptionContinueExecution;
252 else if (ReturnValue == ExceptionContinueSearch)
254 DPRINT("ReturnValue == ExceptionContinueSearch\n");
256 /* Nothing to do here */
258 else if (ReturnValue == ExceptionNestedException)
260 DPRINT("ReturnValue == ExceptionNestedException\n");
262 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
263 if (DispatcherContext > Temp)
265 Temp = DispatcherContext;
268 else /* if (ReturnValue == ExceptionCollidedUnwind) */
270 DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
272 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
273 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
274 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
275 ExceptionRecord2.NumberParameters = 0;
276 RtlRaiseException(&ExceptionRecord2);
279 RegistrationFrame = RegistrationFrame->prev; // Go to previous frame
282 /* No exception handler will handle this exception */
284 DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
286 return ExceptionContinueExecution;
290 RtlRaiseStatus(NTSTATUS Status)
292 EXCEPTION_RECORD ExceptionRecord;
294 DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status);
296 ExceptionRecord.ExceptionCode = Status;
297 ExceptionRecord.ExceptionRecord = NULL;
298 ExceptionRecord.NumberParameters = 0;
299 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
300 RtlRaiseException (& ExceptionRecord);
304 RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame,
306 PEXCEPTION_RECORD ExceptionRecord,
309 PEXCEPTION_REGISTRATION ERHead;
310 PEXCEPTION_RECORD pExceptRec;
311 EXCEPTION_RECORD TempER;
314 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame);
317 RtlpDumpExceptionRegistrations();
320 ERHead = SehpGetExceptionList();
322 DPRINT("ERHead is 0x%X\n", ERHead);
324 if (ExceptionRecord == NULL) // The normal case
326 DPRINT("ExceptionRecord == NULL (normal)\n");
328 pExceptRec = &TempER;
329 pExceptRec->ExceptionFlags = 0;
330 pExceptRec->ExceptionCode = STATUS_UNWIND;
331 pExceptRec->ExceptionRecord = NULL;
332 pExceptRec->ExceptionAddress = ReturnAddress;
333 pExceptRec->ExceptionInformation[0] = 0;
336 if (RegistrationFrame)
337 pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING;
339 pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND);
342 DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags);
343 if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING)
345 DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING);
347 if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND)
349 DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND);
353 Context.ContextFlags =
354 (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS);
356 SehpCaptureContext(&Context);
358 DPRINT("Context.Eip = 0x%.08x\n", Context.Eip);
359 DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp);
360 DPRINT("Context.Esp = 0x%.08x\n", Context.Esp);
363 Context.Eax = EaxValue;
365 // Begin traversing the list of EXCEPTION_REGISTRATION
366 while ((ULONG_PTR)ERHead != (ULONG_PTR)-1)
368 EXCEPTION_RECORD er2;
370 DPRINT("ERHead 0x%X\n", ERHead);
372 if (ERHead == RegistrationFrame)
374 DPRINT("Continueing execution\n");
375 NtContinue(&Context, FALSE);
380 // If there's an exception frame, but it's lower on the stack
381 // than the head of the exception list, something's wrong!
382 if (RegistrationFrame && (RegistrationFrame <= ERHead))
384 DPRINT("The exception frame is bad\n");
386 // Generate an exception to bail out
387 er2.ExceptionRecord = pExceptRec;
388 er2.NumberParameters = 0;
389 er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
390 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
392 RtlRaiseException(&er2);
397 Stack = ERHead + sizeof(EXCEPTION_REGISTRATION);
398 if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead
399 && (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple
400 && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane)
405 PEXCEPTION_REGISTRATION NewERHead;
406 PEXCEPTION_REGISTRATION pCurrExceptReg;
407 EXCEPTION_DISPOSITION ReturnValue;
409 DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler);
411 ReturnValue = RtlpExecuteHandlerForUnwind(
418 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue);
420 if (ReturnValue != ExceptionContinueSearch)
422 if (ReturnValue != ExceptionCollidedUnwind)
424 DPRINT("Bad return value\n");
426 er2.ExceptionRecord = pExceptRec;
427 er2.NumberParameters = 0;
428 er2.ExceptionCode = STATUS_INVALID_DISPOSITION;
429 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
431 RtlRaiseException(&er2);
439 pCurrExceptReg = ERHead;
440 ERHead = ERHead->prev;
442 DPRINT("New ERHead is 0x%X\n", ERHead);
444 DPRINT("Setting exception registration at 0x%X as current\n",
445 RegistrationFrame->prev);
447 // Unlink the exception handler
448 SehpSetExceptionList(RegistrationFrame->prev);
450 else // The stack looks goofy! Raise an exception to bail out
452 DPRINT("Bad stack\n");
454 er2.ExceptionRecord = pExceptRec;
455 er2.NumberParameters = 0;
456 er2.ExceptionCode = STATUS_BAD_STACK;
457 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
459 RtlRaiseException(&er2);
463 // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
464 // This shouldn't happen normally.
466 DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
469 if ((ULONG_PTR)RegistrationFrame == (ULONG_PTR)-1)
470 NtContinue(&Context, FALSE);
472 NtRaiseException(pExceptRec, &Context, 0);