From 7fa558788216d79fd9f5148f1f7af5fd0f47e7b2 Mon Sep 17 00:00:00 2001 From: "KJK::Hyperion" Date: Fri, 25 Jun 2004 01:41:20 +0000 Subject: [PATCH] Committed in the hope CVS will shut the hell up and let me branch. Still part of the SEH work svn path=/trunk/; revision=9865 --- reactos/lib/rtl/i386/except.s | 291 +++++++++++++++++++++ reactos/lib/rtl/i386/exception.c | 417 +++++++++++++++++++++++++++++++ 2 files changed, 708 insertions(+) create mode 100644 reactos/lib/rtl/i386/except.s create mode 100644 reactos/lib/rtl/i386/exception.c diff --git a/reactos/lib/rtl/i386/except.s b/reactos/lib/rtl/i386/except.s new file mode 100644 index 00000000000..bd0a78f235a --- /dev/null +++ b/reactos/lib/rtl/i386/except.s @@ -0,0 +1,291 @@ +/* $Id: except.s,v 1.1 2004/06/25 01:41:19 hyperion Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: User-mode exception support for IA-32 + * FILE: lib/ntdll/rtl/i386/except.s + * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * NOTES: This file is shared with ntoskrnl/rtl/i386/except.s. + * Please keep them in sync. + */ + +#define EXCEPTION_UNWINDING 0x02 + +#define EREC_FLAGS 0x04 + +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +.globl _RtlpExecuteHandlerForException +.globl _RtlpExecuteHandlerForUnwind + +#define CONTEXT_FLAGS 0x00 +#define CONTEXT_SEGGS 0x8C +#define CONTEXT_SEGFS 0x90 +#define CONTEXT_SEGES 0x94 +#define CONTEXT_SEGDS 0x98 +#define CONTEXT_EDI 0x9C +#define CONTEXT_ESI 0xA0 +#define CONTEXT_EBX 0xA4 +#define CONTEXT_EDX 0xA8 +#define CONTEXT_ECX 0xAC +#define CONTEXT_EAX 0xB0 +#define CONTEXT_EBP 0xB4 +#define CONTEXT_EIP 0xB8 +#define CONTEXT_SEGCS 0xBC +#define CONTEXT_EFLAGS 0xC0 +#define CONTEXT_ESP 0xC4 +#define CONTEXT_SEGSS 0xC8 + + +#define RCC_CONTEXT 0x08 + +// EAX = value to print +_do_debug: + pushal + pushl %eax + call _AsmDebug@4 + popal + ret + +#ifndef __NTOSKRNL__ + +// +// VOID +// RtlpCaptureContext(PCONTEXT pContext); +// +// Parameters: +// [ESP+08h] - PCONTEXT_X86 pContext +// Registers: +// None +// Returns: +// Nothing +// Notes: +// Grabs the current CPU context. +.globl _RtlpCaptureContext +_RtlpCaptureContext: + pushl %ebp + movl %esp, %ebp + movl RCC_CONTEXT(%ebp), %edx // EDX = Address of context structure + + cld + pushf + pop %eax + movl %eax, CONTEXT_EFLAGS(%edx) + xorl %eax, %eax + movl %eax, CONTEXT_EAX(%edx) + movl %eax, CONTEXT_EBX(%edx) + movl %eax, CONTEXT_ECX(%edx) + movl %eax, CONTEXT_EDX(%edx) + movl %eax, CONTEXT_ESI(%edx) + movl %eax, CONTEXT_EDI(%edx) + movl %cs, %eax + movl %eax, CONTEXT_SEGCS(%edx) + movl %ds, %eax + movl %eax, CONTEXT_SEGDS(%edx) + movl %es, %eax + movl %eax, CONTEXT_SEGES(%edx) + movl %fs, %eax + movl %eax, CONTEXT_SEGFS(%edx) + movl %gs, %eax + movl %eax, CONTEXT_SEGGS(%edx) + movl %ss, %eax + movl %eax, CONTEXT_SEGSS(%edx) + + // + // STACK LAYOUT: - (ESP to put in context structure) + // - RETURN ADDRESS OF CALLER OF CALLER + // - EBP OF CALLER OF CALLER + // ... + // - RETURN ADDRESS OF CALLER + // - EBP OF CALLER + // ... + // + + // Get return address of the caller of the caller of this function + movl %ebp, %ebx + //movl 4(%ebx), %eax // EAX = return address of caller + movl (%ebx), %ebx // EBX = EBP of caller + + movl 4(%ebx), %eax // EAX = return address of caller of caller + movl (%ebx), %ebx // EBX = EBP of caller of caller + + movl %eax, CONTEXT_EIP(%edx) // EIP = return address of caller of caller + movl %ebx, CONTEXT_EBP(%edx) // EBP = EBP of caller of caller + addl $8, %ebx + movl %ebx, CONTEXT_ESP(%edx) // ESP = EBP of caller of caller + 8 + + movl %ebp, %esp + popl %ebp + ret + +#endif /* !__NTOSKRNL__ */ + +#define REH_ERECORD 0x08 +#define REH_RFRAME 0x0C +#define REH_CONTEXT 0x10 +#define REH_DCONTEXT 0x14 +#define REH_EROUTINE 0x18 + +// Parameters: +// None +// Registers: +// [EBP+08h] - PEXCEPTION_RECORD ExceptionRecord +// [EBP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame +// [EBP+10h] - PVOID Context +// [EBP+14h] - PVOID DispatcherContext +// [EBP+18h] - PEXCEPTION_HANDLER ExceptionRoutine +// EDX - Address of protecting exception handler +// Returns: +// EXCEPTION_DISPOSITION +// Notes: +// Setup the protecting exception handler and call the exception +// handler in the right context. +_RtlpExecuteHandler: + pushl %ebp + movl %esp, %ebp + pushl REH_RFRAME(%ebp) + + pushl %edx + pushl %fs:0x0 + movl %esp, %fs:0x0 + + // Prepare to call the exception handler + pushl REH_DCONTEXT(%ebp) + pushl REH_CONTEXT(%ebp) + pushl REH_RFRAME(%ebp) + pushl REH_ERECORD(%ebp) + + // Now call the exception handler + movl REH_EROUTINE(%ebp), %eax + call *%eax + + cmpl $-1, %fs:0x0 + jne .reh_stack_looks_ok + + // This should not happen + pushl 0 + pushl 0 + pushl 0 + pushl 0 + call _RtlAssert@16 + +.reh_loop: + jmp .reh_loop + +.reh_stack_looks_ok: + movl %fs:0x0, %esp + + // Return to the 'front-end' for this function + popl %fs:0x0 + movl %ebp, %esp + popl %ebp + ret + + +#define REP_ERECORD 0x04 +#define REP_RFRAME 0x08 +#define REP_CONTEXT 0x0C +#define REP_DCONTEXT 0x10 + +// Parameters: +// [ESP+04h] - PEXCEPTION_RECORD ExceptionRecord +// [ESP+08h] - PEXCEPTION_REGISTRATION RegistrationFrame +// [ESP+0Ch] - PCONTEXT Context +// [ESP+10h] - PVOID DispatcherContext +// Registers: +// None +// Returns: +// EXCEPTION_DISPOSITION +// Notes: +// This exception handler protects the exception handling +// mechanism by detecting nested exceptions. +_RtlpExceptionProtector: + movl $ExceptionContinueSearch, %eax + movl REP_ERECORD(%esp), %ecx + testl $EXCEPTION_UNWINDING, EREC_FLAGS(%ecx) + jnz .rep_end + + // Unwinding is not taking place, so return ExceptionNestedException + + // Set DispatcherContext field to the exception registration for the + // exception handler that executed when a nested exception occurred + movl REP_DCONTEXT(%esp), %ecx + movl REP_RFRAME(%esp), %eax + movl %eax, (%ecx) + movl $ExceptionNestedException, %eax + +.rep_end: + ret + + +// Parameters: +// [ESP+04h] - PEXCEPTION_RECORD ExceptionRecord +// [ESP+08h] - PEXCEPTION_REGISTRATION RegistrationFrame +// [ESP+0Ch] - PCONTEXT Context +// [ESP+10h] - PVOID DispatcherContext +// [ESP+14h] - PEXCEPTION_HANDLER ExceptionHandler +// Registers: +// None +// Returns: +// EXCEPTION_DISPOSITION +// Notes: +// Front-end +_RtlpExecuteHandlerForException: + movl $_RtlpExceptionProtector, %edx + jmp _RtlpExecuteHandler + + +#define RUP_ERECORD 0x04 +#define RUP_RFRAME 0x08 +#define RUP_CONTEXT 0x0C +#define RUP_DCONTEXT 0x10 + +// Parameters: +// [ESP+04h] - PEXCEPTION_RECORD ExceptionRecord +// [ESP+08h] - PEXCEPTION_REGISTRATION RegistrationFrame +// [ESP+0Ch] - PCONTEXT Context +// [ESP+10h] - PVOID DispatcherContext +// Registers: +// None +// Returns: +// EXCEPTION_DISPOSITION +// Notes: +// This exception handler protects the exception handling +// mechanism by detecting collided unwinds. +_RtlpUnwindProtector: + movl $ExceptionContinueSearch, %eax + movl %ecx, RUP_ERECORD(%esp) + testl $EXCEPTION_UNWINDING, EREC_FLAGS(%ecx) + jz .rup_end + + // Unwinding is taking place, so return ExceptionCollidedUnwind + + movl RUP_RFRAME(%esp), %ecx + movl RUP_DCONTEXT(%esp), %edx + + // Set DispatcherContext field to the exception registration for the + // exception handler that executed when a collision occurred + movl RUP_RFRAME(%ecx), %eax + movl %eax, (%edx) + movl $ExceptionCollidedUnwind, %eax + +.rup_end: + ret + + +// Parameters: +// [ESP+04h] - PEXCEPTION_RECORD ExceptionRecord +// [ESP+08h] - PEXCEPTION_REGISTRATION RegistrationFrame +// [ESP+0Ch] - PCONTEXT Context +// [ESP+10h] - PVOID DispatcherContext +// [ESP+14h] - PEXCEPTION_HANDLER ExceptionHandler +// Registers: +// None +// Returns: +// EXCEPTION_DISPOSITION +_RtlpExecuteHandlerForUnwind: + movl $_RtlpUnwindProtector, %edx + jmp _RtlpExecuteHandler diff --git a/reactos/lib/rtl/i386/exception.c b/reactos/lib/rtl/i386/exception.c new file mode 100644 index 00000000000..ea80bc90a4a --- /dev/null +++ b/reactos/lib/rtl/i386/exception.c @@ -0,0 +1,417 @@ +/* $Id: exception.c,v 1.1 2004/06/25 01:41:20 hyperion Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: User-mode exception support for IA-32 + * FILE: lib/ntdll/rtl/i386/exception.c + * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + */ + +/* INCLUDES *****************************************************************/ + +#include +#include +#include + +//#define NDEBUG +#include + +/* FUNCTIONS ***************************************************************/ + +/* Implemented in except.s */ + +VOID +RtlpCaptureContext(PCONTEXT pContext); + +#define SehpGetStackLimits(StackBase, StackLimit) \ +{ \ + (*(StackBase)) = NtCurrentTeb()->Tib->StackBase; \ + (*(StackLimit)) = NtCurrentTeb()->Tib->StackLimit; \ +} + +#define SehpGetExceptionList() \ + (PEXCEPTION_REGISTRATION)(NtCurrentTeb()->Tib.ExceptionList) + +#define SehpSetExceptionList(NewExceptionList) \ + NtCurrentTeb()->Tib.ExceptionList = (PVOID)(NewExceptionList) + +VOID STDCALL +AsmDebug(ULONG Value) +{ + DbgPrint("Value 0x%.08x\n", Value); +} + + +/* Declare a few prototypes for the functions in except.s */ + +EXCEPTION_DISPOSITION +RtlpExecuteHandlerForException( + PEXCEPTION_RECORD ExceptionRecord, + PEXCEPTION_REGISTRATION RegistrationFrame, + PCONTEXT Context, + PVOID DispatcherContext, + PEXCEPTION_HANDLER ExceptionHandler); + +EXCEPTION_DISPOSITION +RtlpExecuteHandlerForUnwind( + PEXCEPTION_RECORD ExceptionRecord, + PEXCEPTION_REGISTRATION RegistrationFrame, + PCONTEXT Context, + PVOID DispatcherContext, + PEXCEPTION_HANDLER ExceptionHandler); + + +#ifndef NDEBUG + +VOID RtlpDumpExceptionRegistrations(VOID) +{ + PEXCEPTION_REGISTRATION Current; + + DbgPrint("Dumping exception registrations:\n"); + + Current = SehpGetExceptionList(); + + if ((ULONG_PTR)Current != -1) + { + while ((ULONG_PTR)Current != -1) + { + DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler); + Current = Current->prev; + } + DbgPrint(" End-Of-List\n"); + } else { + DbgPrint(" No exception registrations exists.\n"); + } +} + +#endif /* NDEBUG */ + +ULONG +RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + PEXCEPTION_REGISTRATION RegistrationFrame; + DWORD DispatcherContext; + DWORD ReturnValue; + + DPRINT("RtlpDispatchException()\n"); + +#ifndef NDEBUG + RtlpDumpExceptionRegistrations(); +#endif /* NDEBUG */ + + RegistrationFrame = SehpGetExceptionList(); + + DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame); + + while ((ULONG_PTR)RegistrationFrame != -1) + { + EXCEPTION_RECORD ExceptionRecord2; + DWORD Temp = 0; + //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8; + + // Make sure the registration frame is located within the stack + + DPRINT("Error checking\n"); +#if 0 + if (Teb->Tib.StackBase > RegistrationFrameEnd) + { + DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n", + Teb->Tib.StackBase, RegistrationFrameEnd); + ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; + return ExceptionContinueExecution; + } + // FIXME: Stack top, correct? + if (Teb->Tib.StackLimit < RegistrationFrameEnd) + { + DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n", + Teb->Tib.StackLimit, RegistrationFrameEnd); + ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; + return ExceptionContinueExecution; + } + + // Make sure stack is DWORD aligned + if ((ULONG_PTR)RegistrationFrame & 3) + { + DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n", + RegistrationFrameEnd); + ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; + return ExceptionContinueExecution; + } +#endif + +#if 0 + /* FIXME: */ + if (someFlag) + RtlpLogLastExceptionDisposition( hLog, retValue ); +#endif + + DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler); + DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord); + DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame); + DPRINT("Context 0x%X\n", Context); + DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext); + + ReturnValue = RtlpExecuteHandlerForException( + ExceptionRecord, + RegistrationFrame, + Context, + &DispatcherContext, + RegistrationFrame->handler); +#ifdef DEBUG + DPRINT("Exception handler said 0x%X\n", ReturnValue); + DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame); + { + PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08); + DPRINT("StandardESP == 0x%.08x\n", sp[0]); + DPRINT("Exception Pointers == 0x%.08x\n", sp[1]); + DPRINT("PrevFrame == 0x%.08x\n", sp[2]); + DPRINT("Handler == 0x%.08x\n", sp[3]); + DPRINT("ScopeTable == 0x%.08x\n", sp[4]); + DPRINT("TryLevel == 0x%.08x\n", sp[5]); + DPRINT("EBP == 0x%.08x\n", sp[6]); + } +#endif + if (RegistrationFrame == NULL) + { + ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag + } + + if (ReturnValue == ExceptionContinueExecution) + { + DPRINT("ReturnValue == ExceptionContinueExecution\n"); + if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) + { + DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n"); + + ExceptionRecord2.ExceptionRecord = ExceptionRecord; + ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; + ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord2.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord2); + } + else + { + /* Copy the (possibly changed) context back to the trap frame and return */ + ZwContinue(Context, FALSE); + return ExceptionContinueExecution; + } + } + else if (ReturnValue == ExceptionContinueSearch) + { + DPRINT("ReturnValue == ExceptionContinueSearch\n"); + + /* Nothing to do here */ + } + else if (ReturnValue == ExceptionNestedException) + { + DPRINT("ReturnValue == ExceptionNestedException\n"); + + ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND; + if (DispatcherContext > Temp) + { + Temp = DispatcherContext; + } + } + else /* if (ReturnValue == ExceptionCollidedUnwind) */ + { + DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n"); + + ExceptionRecord2.ExceptionRecord = ExceptionRecord; + ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION; + ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + ExceptionRecord2.NumberParameters = 0; + RtlRaiseException(&ExceptionRecord2); + } + + RegistrationFrame = RegistrationFrame->prev; // Go to previous frame + } + + /* No exception handler will handle this exception */ + + DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n"); + + return ExceptionContinueExecution; +} + + +/* + * @implemented + */ +VOID STDCALL +RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame, + PVOID ReturnAddress, + PEXCEPTION_RECORD ExceptionRecord, + DWORD EaxValue) +{ + PEXCEPTION_REGISTRATION ERHead; + PEXCEPTION_RECORD pExceptRec; + EXCEPTION_RECORD TempER; + CONTEXT Context; + + DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame); + +#ifndef NDEBUG + RtlpDumpExceptionRegistrations(); +#endif /* NDEBUG */ + + ERHead = SehpGetExceptionList(); + + DPRINT("ERHead is 0x%X\n", ERHead); + + if (ExceptionRecord == NULL) // The normal case + { + DPRINT("ExceptionRecord == NULL (normal)\n"); + + pExceptRec = &TempER; + pExceptRec->ExceptionFlags = 0; + pExceptRec->ExceptionCode = STATUS_UNWIND; + pExceptRec->ExceptionRecord = NULL; + pExceptRec->ExceptionAddress = ReturnAddress; + pExceptRec->ExceptionInformation[0] = 0; + } + else + { + pExceptRec = ExceptionRecord; + } + + if (RegistrationFrame) + pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING; + else + pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND); + +#ifndef NDEBUG + DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags); + if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING) + { + DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING); + } + if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND) + { + DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND); + } +#endif /* NDEBUG */ + + Context.ContextFlags = + (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS); + + RtlpCaptureContext(&Context); + + DPRINT("Context.Eip = 0x%.08x\n", Context.Eip); + DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp); + DPRINT("Context.Esp = 0x%.08x\n", Context.Esp); + + Context.Esp += 0x10; + Context.Eax = EaxValue; + + // Begin traversing the list of EXCEPTION_REGISTRATION + while ((ULONG_PTR)ERHead != -1) + { + EXCEPTION_RECORD er2; + + DPRINT("ERHead 0x%X\n", ERHead); + + if (ERHead == RegistrationFrame) + { + DPRINT("Continueing execution\n"); + ZwContinue(&Context, FALSE); + return; + } + else + { + // If there's an exception frame, but it's lower on the stack + // than the head of the exception list, something's wrong! + if (RegistrationFrame && (RegistrationFrame <= ERHead)) + { + DPRINT("The exception frame is bad\n"); + + // Generate an exception to bail out + er2.ExceptionRecord = pExceptRec; + er2.NumberParameters = 0; + er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; + er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + + RtlRaiseException(&er2); + } + } + +#if 0 + Stack = ERHead + sizeof(EXCEPTION_REGISTRATION); + if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead + && (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple + && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane) +#else + if (1) +#endif + { + PEXCEPTION_REGISTRATION NewERHead; + PEXCEPTION_REGISTRATION pCurrExceptReg; + EXCEPTION_DISPOSITION ReturnValue; + + DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler); + + ReturnValue = RtlpExecuteHandlerForUnwind( + pExceptRec, + ERHead, + &Context, + &NewERHead, + ERHead->handler); + + DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue); + + if (ReturnValue != ExceptionContinueSearch) + { + if (ReturnValue != ExceptionCollidedUnwind) + { + DPRINT("Bad return value\n"); + + er2.ExceptionRecord = pExceptRec; + er2.NumberParameters = 0; + er2.ExceptionCode = STATUS_INVALID_DISPOSITION; + er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + + RtlRaiseException(&er2); + } + else + { + ERHead = NewERHead; + } + } + + pCurrExceptReg = ERHead; + ERHead = ERHead->prev; + + DPRINT("New ERHead is 0x%X\n", ERHead); + + DPRINT("Setting exception registration at 0x%X as current\n", + RegistrationFrame->prev); + + // Unlink the exception handler + SehpSetExceptionList(RegistrationFrame->prev); + } + else // The stack looks goofy! Raise an exception to bail out + { + DPRINT("Bad stack\n"); + + er2.ExceptionRecord = pExceptRec; + er2.NumberParameters = 0; + er2.ExceptionCode = STATUS_BAD_STACK; + er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + + RtlRaiseException(&er2); + } + } + + // If we get here, we reached the end of the EXCEPTION_REGISTRATION list. + // This shouldn't happen normally. + + DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n", + RegistrationFrame); + + if ((ULONG_PTR)RegistrationFrame == -1) + ZwContinue(&Context, FALSE); + else + NtRaiseException(pExceptRec, &Context, 0); +} + +/* EOF */