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 /*** Code below this line is shared with ntoskrnl/rtl/i386/exception.c - please keep in sync ***/
51 DbgPrint("Value 0x%.08x\n", Value);
55 /* Declare a few prototypes for the functions in except.s */
58 RtlpExecuteHandlerForException(
59 PEXCEPTION_RECORD ExceptionRecord,
60 PEXCEPTION_REGISTRATION RegistrationFrame,
62 PVOID DispatcherContext,
63 PEXCEPTION_HANDLER ExceptionHandler);
66 RtlpExecuteHandlerForUnwind(
67 PEXCEPTION_RECORD ExceptionRecord,
68 PEXCEPTION_REGISTRATION RegistrationFrame,
70 PVOID DispatcherContext,
71 PEXCEPTION_HANDLER ExceptionHandler);
76 VOID RtlpDumpExceptionRegistrations(VOID)
78 PEXCEPTION_REGISTRATION Current;
80 DbgPrint("Dumping exception registrations:\n");
82 Current = SehpGetExceptionList();
84 if ((ULONG_PTR)Current != -1)
86 while ((ULONG_PTR)Current != -1)
88 DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler);
89 Current = Current->prev;
91 DbgPrint(" End-Of-List\n");
93 DbgPrint(" No exception registrations exists.\n");
100 RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
103 PEXCEPTION_REGISTRATION RegistrationFrame;
104 DWORD DispatcherContext;
107 DPRINT("RtlpDispatchException()\n");
110 RtlpDumpExceptionRegistrations();
113 RegistrationFrame = SehpGetExceptionList();
115 DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
117 while ((ULONG_PTR)RegistrationFrame != -1)
119 EXCEPTION_RECORD ExceptionRecord2;
121 //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
123 // Make sure the registration frame is located within the stack
125 DPRINT("Error checking\n");
127 if (Teb->Tib.StackBase > RegistrationFrameEnd)
129 DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
130 Teb->Tib.StackBase, RegistrationFrameEnd);
131 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
132 return ExceptionContinueExecution;
134 // FIXME: Stack top, correct?
135 if (Teb->Tib.StackLimit < RegistrationFrameEnd)
137 DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
138 Teb->Tib.StackLimit, RegistrationFrameEnd);
139 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
140 return ExceptionContinueExecution;
143 // Make sure stack is DWORD aligned
144 if ((ULONG_PTR)RegistrationFrame & 3)
146 DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
147 RegistrationFrameEnd);
148 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
149 return ExceptionContinueExecution;
156 RtlpLogLastExceptionDisposition( hLog, retValue );
159 DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler);
160 DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord);
161 DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame);
162 DPRINT("Context 0x%X\n", Context);
163 DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext);
165 ReturnValue = RtlpExecuteHandlerForException(
170 RegistrationFrame->handler);
172 DPRINT("Exception handler said 0x%X\n", ReturnValue);
173 DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame);
175 PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08);
176 DPRINT("StandardESP == 0x%.08x\n", sp[0]);
177 DPRINT("Exception Pointers == 0x%.08x\n", sp[1]);
178 DPRINT("PrevFrame == 0x%.08x\n", sp[2]);
179 DPRINT("Handler == 0x%.08x\n", sp[3]);
180 DPRINT("ScopeTable == 0x%.08x\n", sp[4]);
181 DPRINT("TryLevel == 0x%.08x\n", sp[5]);
182 DPRINT("EBP == 0x%.08x\n", sp[6]);
185 if (RegistrationFrame == NULL)
187 ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag
190 if (ReturnValue == ExceptionContinueExecution)
192 DPRINT("ReturnValue == ExceptionContinueExecution\n");
193 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
195 DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
197 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
198 ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
199 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
200 ExceptionRecord2.NumberParameters = 0;
201 RtlRaiseException(&ExceptionRecord2);
205 /* Copy the (possibly changed) context back to the trap frame and return */
206 NtContinue(Context, FALSE);
207 return ExceptionContinueExecution;
210 else if (ReturnValue == ExceptionContinueSearch)
212 DPRINT("ReturnValue == ExceptionContinueSearch\n");
214 /* Nothing to do here */
216 else if (ReturnValue == ExceptionNestedException)
218 DPRINT("ReturnValue == ExceptionNestedException\n");
220 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
221 if (DispatcherContext > Temp)
223 Temp = DispatcherContext;
226 else /* if (ReturnValue == ExceptionCollidedUnwind) */
228 DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
230 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
231 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
232 ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
233 ExceptionRecord2.NumberParameters = 0;
234 RtlRaiseException(&ExceptionRecord2);
237 RegistrationFrame = RegistrationFrame->prev; // Go to previous frame
240 /* No exception handler will handle this exception */
242 DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
244 return ExceptionContinueExecution;
248 RtlRaiseStatus(NTSTATUS Status)
250 EXCEPTION_RECORD ExceptionRecord;
252 DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status);
254 ExceptionRecord.ExceptionCode = Status;
255 ExceptionRecord.ExceptionRecord = NULL;
256 ExceptionRecord.NumberParameters = 0;
257 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
258 RtlRaiseException (& ExceptionRecord);
262 RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame,
264 PEXCEPTION_RECORD ExceptionRecord,
267 PEXCEPTION_REGISTRATION ERHead;
268 PEXCEPTION_RECORD pExceptRec;
269 EXCEPTION_RECORD TempER;
272 DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame);
275 RtlpDumpExceptionRegistrations();
278 ERHead = SehpGetExceptionList();
280 DPRINT("ERHead is 0x%X\n", ERHead);
282 if (ExceptionRecord == NULL) // The normal case
284 DPRINT("ExceptionRecord == NULL (normal)\n");
286 pExceptRec = &TempER;
287 pExceptRec->ExceptionFlags = 0;
288 pExceptRec->ExceptionCode = STATUS_UNWIND;
289 pExceptRec->ExceptionRecord = NULL;
290 pExceptRec->ExceptionAddress = ReturnAddress;
291 pExceptRec->ExceptionInformation[0] = 0;
294 if (RegistrationFrame)
295 pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING;
297 pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND);
300 DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags);
301 if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING)
303 DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING);
305 if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND)
307 DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND);
311 Context.ContextFlags =
312 (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS);
314 SehpCaptureContext(&Context);
316 DPRINT("Context.Eip = 0x%.08x\n", Context.Eip);
317 DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp);
318 DPRINT("Context.Esp = 0x%.08x\n", Context.Esp);
321 Context.Eax = EaxValue;
323 // Begin traversing the list of EXCEPTION_REGISTRATION
324 while ((ULONG_PTR)ERHead != -1)
326 EXCEPTION_RECORD er2;
328 DPRINT("ERHead 0x%X\n", ERHead);
330 if (ERHead == RegistrationFrame)
332 DPRINT("Continueing execution\n");
333 NtContinue(&Context, FALSE);
338 // If there's an exception frame, but it's lower on the stack
339 // than the head of the exception list, something's wrong!
340 if (RegistrationFrame && (RegistrationFrame <= ERHead))
342 DPRINT("The exception frame is bad\n");
344 // Generate an exception to bail out
345 er2.ExceptionRecord = pExceptRec;
346 er2.NumberParameters = 0;
347 er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
348 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
350 RtlRaiseException(&er2);
355 Stack = ERHead + sizeof(EXCEPTION_REGISTRATION);
356 if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead
357 && (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple
358 && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane)
363 PEXCEPTION_REGISTRATION NewERHead;
364 PEXCEPTION_REGISTRATION pCurrExceptReg;
365 EXCEPTION_DISPOSITION ReturnValue;
367 DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler);
369 ReturnValue = RtlpExecuteHandlerForUnwind(
376 DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue);
378 if (ReturnValue != ExceptionContinueSearch)
380 if (ReturnValue != ExceptionCollidedUnwind)
382 DPRINT("Bad return value\n");
384 er2.ExceptionRecord = pExceptRec;
385 er2.NumberParameters = 0;
386 er2.ExceptionCode = STATUS_INVALID_DISPOSITION;
387 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
389 RtlRaiseException(&er2);
397 pCurrExceptReg = ERHead;
398 ERHead = ERHead->prev;
400 DPRINT("New ERHead is 0x%X\n", ERHead);
402 DPRINT("Setting exception registration at 0x%X as current\n",
403 RegistrationFrame->prev);
405 // Unlink the exception handler
406 SehpSetExceptionList(RegistrationFrame->prev);
408 else // The stack looks goofy! Raise an exception to bail out
410 DPRINT("Bad stack\n");
412 er2.ExceptionRecord = pExceptRec;
413 er2.NumberParameters = 0;
414 er2.ExceptionCode = STATUS_BAD_STACK;
415 er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
417 RtlRaiseException(&er2);
421 // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
422 // This shouldn't happen normally.
424 DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
427 if ((ULONG_PTR)RegistrationFrame == -1)
428 NtContinue(&Context, FALSE);
430 NtRaiseException(pExceptRec, &Context, 0);