diff --git a/reactos/lib/msvcrt/except/seh.s b/reactos/lib/msvcrt/except/seh.s index b0b5762f886..7a2813fe80d 100755 --- a/reactos/lib/msvcrt/except/seh.s +++ b/reactos/lib/msvcrt/except/seh.s @@ -1,366 +1,366 @@ -/* $Id: seh.s,v 1.2 2002/10/26 07:32:08 chorns Exp $ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS MSVCRT Runtime Library - * PURPOSE: Runtime library exception support for IA-32 - * FILE: lib/msvcrt/except/seh.s - * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - * NOTES: This file is shared with ntoskrnl/rtl/i386/seh.s. - * Please keep them in sync. - */ - -#define ExceptionContinueExecution 0 -#define ExceptionContinueSearch 1 -#define ExceptionNestedException 2 -#define ExceptionCollidedUnwind 3 - -#define EXCEPTION_NONCONTINUABLE 0x01 -#define EXCEPTION_UNWINDING 0x02 -#define EXCEPTION_EXIT_UNWIND 0x04 -#define EXCEPTION_STACK_INVALID 0x08 -#define EXCEPTION_NESTED_CALL 0x10 -#define EXCEPTION_TARGET_UNWIND 0x20 -#define EXCEPTION_COLLIDED_UNWIND 0x40 - -#define EXCEPTION_UNWIND_MODE \ -( EXCEPTION_UNWINDING \ - | EXCEPTION_EXIT_UNWIND \ - | EXCEPTION_TARGET_UNWIND \ - | EXCEPTION_COLLIDED_UNWIND) - -#define EREC_CODE 0x00 -#define EREC_FLAGS 0x04 -#define EREC_RECORD 0x08 -#define EREC_ADDRESS 0x0C -#define EREC_NUMPARAMS 0x10 -#define EREC_INFO 0x14 - -#define TRYLEVEL_NONE -1 -#define TRYLEVEL_INVALID -2 - -#define ER_STANDARDESP -0x08 -#define ER_EPOINTERS -0x04 -#define ER_PREVFRAME 0x00 -#define ER_HANDLER 0x04 -#define ER_SCOPETABLE 0x08 -#define ER_TRYLEVEL 0x0C -#define ER_EBP 0x10 - -#define ST_TRYLEVEL 0x00 -#define ST_FILTER 0x04 -#define ST_HANDLER 0x08 - -#define CONTEXT_EDI 0x9C -#define CONTEXT_EBX 0xA4 -#define CONTEXT_EIP 0xB8 - -.globl __local_unwind2 -.globl __except_handler3 - -// EAX = value to print -_do_debug: - pushal - pushl %eax - call _MsvcrtDebug@4 - popal - ret - -#define LU2_TRYLEVEL 0x08 -#define LU2_REGFRAME 0x04 - -// -// void -// _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame, -// LONG TryLevel) -// -// Parameters: -// [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame -// [EDX+04h] - LONG TryLevel -// Registers: -// EBP - EBP of call frame we are unwinding -// Returns: -// Nothing -// Notes: -// Run all termination handlers for a call frame from the current -// try-level up to (but not including) the given stop try-level. -__local_unwind2: - // Setup our call frame so we can access parameters using EDX - //pushl %ebp - movl %esp, %edx - - // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the - // unwinding in case something goes wrong - -.lu2_next_scope: - - // Keep a pointer to the exception registration in EBX - movl LU2_REGFRAME(%edx), %ebx - - // If we have reached the end of the chain or we're asked to stop here - // by the caller then exit - movl ER_TRYLEVEL(%ebx), %eax - - cmpl $-1, %eax - je .lu2_done - - cmpl LU2_TRYLEVEL(%edx), %eax - je .lu2_done - - // Keep a pointer to the scopetable in ESI - movl ER_SCOPETABLE(%ebx), %esi - - // Compute the offset of the entry in the scopetable that describes - // the scope that is to be unwound. Put the offset in EDI. - movl ST_TRYLEVEL(%esi), %edi - lea (%edi, %edi, 2), %edi - shll $2, %edi - addl %esi, %edi - - // If this is not a termination handler then skip it - cmpl $0, ST_FILTER(%edi) - jne .lu2_next_scope - - // Save the previous try-level in the exception registration structure - movl ST_TRYLEVEL(%edi), %eax - movl %eax, ER_TRYLEVEL(%ebx) - - // Fetch the address of the termination handler - movl ST_HANDLER(%edi), %eax - - // Termination handlers may trash all registers so save the - // important ones and then call the handler - pushl %edx - call *%eax - - // Get our base pointer back - popl %edx - - jmp .lu2_next_scope - -.lu2_done: - - // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect - // the unwinding - - //movl %esi, %esp - //popl %ebp - ret - -#define EH3_DISPCONTEXT 0x14 -#define EH3_CONTEXT 0x10 -#define EH3_REGFRAME 0x0C -#define EH3_ERECORD 0x08 - -// Parameters: -// [ESP+14h] - PVOID DispatcherContext -// [ESP+10h] - PCONTEXT Context -// [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame -// [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord -// Registers: -// Unknown -// Returns: -// EXCEPTION_DISPOSITION - How this handler handled the exception -// Notes: -// Try to find an exception handler that will handle the exception. -// Traverse the entries in the scopetable that is associated with the -// exception registration passed as a parameter to this function. -// If an exception handler that will handle the exception is found, it -// is called and this function never returns -__except_handler3: - // Setup our call frame so we can access parameters using EBP - pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION) - movl %esp, %ebp - - // Don't trust the direction flag to be cleared - cld - - // Either we're called to handle an exception or we're called to unwind - movl EH3_ERECORD(%ebp), %eax - testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax) - jnz .eh3_unwind - - // Keep a pointer to the exception registration in EBX - movl EH3_REGFRAME(%ebp), %ebx - - // Build an EXCEPTION_POINTERS structure on the stack and store it's - // address in the EXCEPTION_REGISTRATION structure - movl EH3_CONTEXT(%esp), %eax - pushl %ebx // Registration frame - pushl %eax // Context - movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack - - // Keep current try-level in EDI - movl ER_TRYLEVEL(%ebx), %edi - - // Keep a pointer to the scopetable in ESI - movl ER_SCOPETABLE(%ebx), %esi - -.eh3_next_scope: - - // If we have reached the end of the chain then exit - cmpl $-1, %edi - je .eh3_search - - // Compute the offset of the entry in the scopetable and store - // the absolute address in EAX - lea (%edi, %edi, 2), %eax - shll $2, %eax - addl %esi, %eax - - // Fetch the address of the filter routine - movl ST_FILTER(%eax), %eax - - // If this is a termination handler then skip it - cmpl $0, %eax - je .eh3_continue - - // Filter routines may trash all registers so save the important - // ones before restoring the call frame ebp and calling the handler - pushl %ebp - pushl %edi // Stop try-level - lea ER_EBP(%ebx), %ebp - call *%eax - popl %edi // Stop try-level - popl %ebp - - // Reload EBX with registration frame address - movl EH3_REGFRAME(%ebp), %ebx - - // Be more flexible here by checking if the return value is less than - // zero, equal to zero, or larger than zero instead of the defined - // values: - // -1 (EXCEPTION_CONTINUE_EXECUTION) - // 0 (EXCEPTION_CONTINUE_SEARCH) - // +1 (EXCEPTION_EXECUTE_HANDLER) - orl %eax, %eax - jz .eh3_continue - js .eh3_dismiss - - // Filter returned: EXCEPTION_EXECUTE_HANDLER - - // Ask the OS to perform global unwinding. - pushl %edi // Save stop try-level - pushl %ebx // Save registration frame address - pushl %ebx // Registration frame address - call __global_unwind2 - popl %eax // Remove parameter to __global_unwind2 - popl %ebx // Restore registration frame address - popl %edi // Restore stop try-level - - // Change the context structure so _except_finish is called in the - // correct context since we return ExceptionContinueExecution. - movl EH3_CONTEXT(%ebp), %eax - - movl %edi, CONTEXT_EDI(%eax) // Stop try-level - movl %ebx, CONTEXT_EBX(%eax) // Registration frame address - movl $_except_finish, CONTEXT_EIP(%eax) - - movl $ExceptionContinueExecution, %eax - jmp .eh3_return - - // Filter returned: EXCEPTION_CONTINUE_SEARCH -.eh3_continue: - - // Reload ESI because the filter routine may have trashed it - movl ER_SCOPETABLE(%ebx), %esi - - // Go one try-level closer to the top - lea (%edi, %edi, 2), %edi - shll $2, %edi - addl %esi, %edi - movl ST_TRYLEVEL(%edi), %edi - - jmp .eh3_next_scope - - // Filter returned: EXCEPTION_CONTINUE_EXECUTION - // Continue execution like nothing happened -.eh3_dismiss: - movl $ExceptionContinueExecution, %eax - jmp .eh3_return - - // Tell the OS to search for another handler that will handle the exception -.eh3_search: - - movl $ExceptionContinueSearch, %eax - jmp .eh3_return - - // Perform local unwinding -.eh3_unwind: - - movl $ExceptionContinueSearch, %eax - testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax) - jnz .eh3_return - - // Save some important registers - pushl %ebp - - lea ER_EBP(%ebx), %ebp - pushl $-1 - pushl %ebx - call __local_unwind2 - addl $8, %esp - - // Restore some important registers - popl %ebp - - movl $ExceptionContinueSearch, %eax - - // Get me out of here -.eh3_return: - - movl %ebp, %esp - popl %ebp - ret - -// Parameters: -// None -// Registers: -// EBX - Pointer to exception registration structure -// EDI - Stop try-level -// Returns: -// - -// Notes: -// - -_except_finish: - - // Setup EBP for the exception handler. By doing this the exception - // handler can access local variables as normal - lea ER_EBP(%ebx), %ebp - - // Save some important registers - pushl %ebp - pushl %ebx - pushl %edi - - // Stop try-level - pushl %edi - - // Pointer to exception registration structure - pushl %ebx - call __local_unwind2 - addl $8, %esp - - // Restore some important registers - popl %edi - popl %ebx - popl %ebp - - // Keep a pointer to the scopetable in ESI - movl ER_SCOPETABLE(%ebx), %esi - - // Compute the offset of the entry in the scopetable and store - // the absolute address in EDI - lea (%edi, %edi, 2), %edi - shll $2, %edi - addl %esi, %edi - - // Set the current try-level to the previous try-level and call - // the exception handler - movl ST_TRYLEVEL(%edi), %eax - movl %eax, ER_TRYLEVEL(%ebx) - movl ST_HANDLER(%edi), %eax - - call *%eax - - // We should never get here - ret +/* $Id: seh.s,v 1.3 2002/10/26 09:53:15 dwelch Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS MSVCRT Runtime Library + * PURPOSE: Runtime library exception support for IA-32 + * FILE: lib/msvcrt/except/seh.s + * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * NOTES: This file is shared with ntoskrnl/rtl/i386/seh.s. + * Please keep them in sync. + */ + +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +#define EXCEPTION_NONCONTINUABLE 0x01 +#define EXCEPTION_UNWINDING 0x02 +#define EXCEPTION_EXIT_UNWIND 0x04 +#define EXCEPTION_STACK_INVALID 0x08 +#define EXCEPTION_NESTED_CALL 0x10 +#define EXCEPTION_TARGET_UNWIND 0x20 +#define EXCEPTION_COLLIDED_UNWIND 0x40 + +#define EXCEPTION_UNWIND_MODE \ +( EXCEPTION_UNWINDING \ + | EXCEPTION_EXIT_UNWIND \ + | EXCEPTION_TARGET_UNWIND \ + | EXCEPTION_COLLIDED_UNWIND) + +#define EREC_CODE 0x00 +#define EREC_FLAGS 0x04 +#define EREC_RECORD 0x08 +#define EREC_ADDRESS 0x0C +#define EREC_NUMPARAMS 0x10 +#define EREC_INFO 0x14 + +#define TRYLEVEL_NONE -1 +#define TRYLEVEL_INVALID -2 + +#define ER_STANDARDESP -0x08 +#define ER_EPOINTERS -0x04 +#define ER_PREVFRAME 0x00 +#define ER_HANDLER 0x04 +#define ER_SCOPETABLE 0x08 +#define ER_TRYLEVEL 0x0C +#define ER_EBP 0x10 + +#define ST_TRYLEVEL 0x00 +#define ST_FILTER 0x04 +#define ST_HANDLER 0x08 + +#define CONTEXT_EDI 0x9C +#define CONTEXT_EBX 0xA4 +#define CONTEXT_EIP 0xB8 + +.globl __local_unwind2 +.globl __except_handler3 + +// EAX = value to print +_do_debug: + pushal + pushl %eax + call _MsvcrtDebug@4 + popal + ret + +#define LU2_TRYLEVEL 0x08 +#define LU2_REGFRAME 0x04 + +// +// void +// _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame, +// LONG TryLevel) +// +// Parameters: +// [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame +// [EDX+04h] - LONG TryLevel +// Registers: +// EBP - EBP of call frame we are unwinding +// Returns: +// Nothing +// Notes: +// Run all termination handlers for a call frame from the current +// try-level up to (but not including) the given stop try-level. +__local_unwind2: + // Setup our call frame so we can access parameters using EDX + //pushl %ebp + movl %esp, %edx + + // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the + // unwinding in case something goes wrong + +.lu2_next_scope: + + // Keep a pointer to the exception registration in EBX + movl LU2_REGFRAME(%edx), %ebx + + // If we have reached the end of the chain or we're asked to stop here + // by the caller then exit + movl ER_TRYLEVEL(%ebx), %eax + + cmpl $-1, %eax + je .lu2_done + + cmpl LU2_TRYLEVEL(%edx), %eax + je .lu2_done + + // Keep a pointer to the scopetable in ESI + movl ER_SCOPETABLE(%ebx), %esi + + // Compute the offset of the entry in the scopetable that describes + // the scope that is to be unwound. Put the offset in EDI. + movl ST_TRYLEVEL(%esi), %edi + lea (%edi, %edi, 2), %edi + shll $2, %edi + addl %esi, %edi + + // If this is not a termination handler then skip it + cmpl $0, ST_FILTER(%edi) + jne .lu2_next_scope + + // Save the previous try-level in the exception registration structure + movl ST_TRYLEVEL(%edi), %eax + movl %eax, ER_TRYLEVEL(%ebx) + + // Fetch the address of the termination handler + movl ST_HANDLER(%edi), %eax + + // Termination handlers may trash all registers so save the + // important ones and then call the handler + pushl %edx + call *%eax + + // Get our base pointer back + popl %edx + + jmp .lu2_next_scope + +.lu2_done: + + // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect + // the unwinding + + //movl %esi, %esp + //popl %ebp + ret + +#define EH3_DISPCONTEXT 0x14 +#define EH3_CONTEXT 0x10 +#define EH3_REGFRAME 0x0C +#define EH3_ERECORD 0x08 + +// Parameters: +// [ESP+14h] - PVOID DispatcherContext +// [ESP+10h] - PCONTEXT Context +// [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame +// [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord +// Registers: +// Unknown +// Returns: +// EXCEPTION_DISPOSITION - How this handler handled the exception +// Notes: +// Try to find an exception handler that will handle the exception. +// Traverse the entries in the scopetable that is associated with the +// exception registration passed as a parameter to this function. +// If an exception handler that will handle the exception is found, it +// is called and this function never returns +__except_handler3: + // Setup our call frame so we can access parameters using EBP + pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION) + movl %esp, %ebp + + // Don't trust the direction flag to be cleared + cld + + // Either we're called to handle an exception or we're called to unwind + movl EH3_ERECORD(%ebp), %eax + testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax) + jnz .eh3_unwind + + // Keep a pointer to the exception registration in EBX + movl EH3_REGFRAME(%ebp), %ebx + + // Build an EXCEPTION_POINTERS structure on the stack and store it's + // address in the EXCEPTION_REGISTRATION structure + movl EH3_CONTEXT(%esp), %eax + pushl %ebx // Registration frame + pushl %eax // Context + movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack + + // Keep current try-level in EDI + movl ER_TRYLEVEL(%ebx), %edi + + // Keep a pointer to the scopetable in ESI + movl ER_SCOPETABLE(%ebx), %esi + +.eh3_next_scope: + + // If we have reached the end of the chain then exit + cmpl $-1, %edi + je .eh3_search + + // Compute the offset of the entry in the scopetable and store + // the absolute address in EAX + lea (%edi, %edi, 2), %eax + shll $2, %eax + addl %esi, %eax + + // Fetch the address of the filter routine + movl ST_FILTER(%eax), %eax + + // If this is a termination handler then skip it + cmpl $0, %eax + je .eh3_continue + + // Filter routines may trash all registers so save the important + // ones before restoring the call frame ebp and calling the handler + pushl %ebp + pushl %edi // Stop try-level + lea ER_EBP(%ebx), %ebp + call *%eax + popl %edi // Stop try-level + popl %ebp + + // Reload EBX with registration frame address + movl EH3_REGFRAME(%ebp), %ebx + + // Be more flexible here by checking if the return value is less than + // zero, equal to zero, or larger than zero instead of the defined + // values: + // -1 (EXCEPTION_CONTINUE_EXECUTION) + // 0 (EXCEPTION_CONTINUE_SEARCH) + // +1 (EXCEPTION_EXECUTE_HANDLER) + orl %eax, %eax + jz .eh3_continue + js .eh3_dismiss + + // Filter returned: EXCEPTION_EXECUTE_HANDLER + + // Ask the OS to perform global unwinding. + pushl %edi // Save stop try-level + pushl %ebx // Save registration frame address + pushl %ebx // Registration frame address + call __global_unwind2 + popl %eax // Remove parameter to __global_unwind2 + popl %ebx // Restore registration frame address + popl %edi // Restore stop try-level + + // Change the context structure so _except_finish is called in the + // correct context since we return ExceptionContinueExecution. + movl EH3_CONTEXT(%ebp), %eax + + movl %edi, CONTEXT_EDI(%eax) // Stop try-level + movl %ebx, CONTEXT_EBX(%eax) // Registration frame address + movl $_except_finish, CONTEXT_EIP(%eax) + + movl $ExceptionContinueExecution, %eax + jmp .eh3_return + + // Filter returned: EXCEPTION_CONTINUE_SEARCH +.eh3_continue: + + // Reload ESI because the filter routine may have trashed it + movl ER_SCOPETABLE(%ebx), %esi + + // Go one try-level closer to the top + lea (%edi, %edi, 2), %edi + shll $2, %edi + addl %esi, %edi + movl ST_TRYLEVEL(%edi), %edi + + jmp .eh3_next_scope + + // Filter returned: EXCEPTION_CONTINUE_EXECUTION + // Continue execution like nothing happened +.eh3_dismiss: + movl $ExceptionContinueExecution, %eax + jmp .eh3_return + + // Tell the OS to search for another handler that will handle the exception +.eh3_search: + + movl $ExceptionContinueSearch, %eax + jmp .eh3_return + + // Perform local unwinding +.eh3_unwind: + + movl $ExceptionContinueSearch, %eax + testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax) + jnz .eh3_return + + // Save some important registers + pushl %ebp + + lea ER_EBP(%ebx), %ebp + pushl $-1 + pushl %ebx + call __local_unwind2 + addl $8, %esp + + // Restore some important registers + popl %ebp + + movl $ExceptionContinueSearch, %eax + + // Get me out of here +.eh3_return: + + movl %ebp, %esp + popl %ebp + ret + +// Parameters: +// None +// Registers: +// EBX - Pointer to exception registration structure +// EDI - Stop try-level +// Returns: +// - +// Notes: +// - +_except_finish: + + // Setup EBP for the exception handler. By doing this the exception + // handler can access local variables as normal + lea ER_EBP(%ebx), %ebp + + // Save some important registers + pushl %ebp + pushl %ebx + pushl %edi + + // Stop try-level + pushl %edi + + // Pointer to exception registration structure + pushl %ebx + call __local_unwind2 + addl $8, %esp + + // Restore some important registers + popl %edi + popl %ebx + popl %ebp + + // Keep a pointer to the scopetable in ESI + movl ER_SCOPETABLE(%ebx), %esi + + // Compute the offset of the entry in the scopetable and store + // the absolute address in EDI + lea (%edi, %edi, 2), %edi + shll $2, %edi + addl %esi, %edi + + // Set the current try-level to the previous try-level and call + // the exception handler + movl ST_TRYLEVEL(%edi), %eax + movl %eax, ER_TRYLEVEL(%ebx) + movl ST_HANDLER(%edi), %eax + + call *%eax + + // We should never get here + ret diff --git a/reactos/lib/ntdll/rtl/i386/exception.c b/reactos/lib/ntdll/rtl/i386/exception.c index 4886d4aa527..f31ab66f288 100755 --- a/reactos/lib/ntdll/rtl/i386/exception.c +++ b/reactos/lib/ntdll/rtl/i386/exception.c @@ -1,433 +1,433 @@ -/* $Id: exception.c,v 1.2 2002/10/26 07:32:08 chorns 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); - -/* Macros that will help streamline the SEH implementations for - kernel mode and user mode */ - -#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) - -#define SehpCaptureContext(Context) \ -{ \ - RtlpCaptureContext(Context); \ -} - -/*** Code below this line is shared with ntoskrnl/rtl/i386/exception.c - please keep in sync ***/ - -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); - - 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]); - } - - 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 */ - NtContinue(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; -} - -VOID STDCALL -RtlRaiseStatus(NTSTATUS Status) -{ - EXCEPTION_RECORD ExceptionRecord; - - DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status); - - ExceptionRecord.ExceptionCode = Status; - ExceptionRecord.ExceptionRecord = NULL; - ExceptionRecord.NumberParameters = 0; - ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; - RtlRaiseException (& ExceptionRecord); -} - -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; - } - - 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); - - SehpCaptureContext(&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"); - NtContinue(&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) - NtContinue(&Context, FALSE); - else - NtRaiseException(pExceptRec, &Context, 0); -} - -/* EOF */ +/* $Id: exception.c,v 1.3 2002/10/26 09:53:15 dwelch 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); + +/* Macros that will help streamline the SEH implementations for + kernel mode and user mode */ + +#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) + +#define SehpCaptureContext(Context) \ +{ \ + RtlpCaptureContext(Context); \ +} + +/*** Code below this line is shared with ntoskrnl/rtl/i386/exception.c - please keep in sync ***/ + +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); + + 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]); + } + + 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 */ + NtContinue(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; +} + +VOID STDCALL +RtlRaiseStatus(NTSTATUS Status) +{ + EXCEPTION_RECORD ExceptionRecord; + + DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status); + + ExceptionRecord.ExceptionCode = Status; + ExceptionRecord.ExceptionRecord = NULL; + ExceptionRecord.NumberParameters = 0; + ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + RtlRaiseException (& ExceptionRecord); +} + +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; + } + + 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); + + SehpCaptureContext(&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"); + NtContinue(&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) + NtContinue(&Context, FALSE); + else + NtRaiseException(pExceptRec, &Context, 0); +} + +/* EOF */ diff --git a/reactos/lib/user32/Makefile b/reactos/lib/user32/Makefile index 3e36a08f2c8..bc38b33130a 100644 --- a/reactos/lib/user32/Makefile +++ b/reactos/lib/user32/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.7 2002/10/20 14:53:02 ekohl Exp $ +# $Id: Makefile,v 1.8 2002/10/26 09:53:15 dwelch Exp $ PATH_TO_TOP = ../.. @@ -10,7 +10,7 @@ TARGET_BASE = 0x77e70000 TARGET_SDKLIBS = ntdll.a kernel32.a gdi32.a -TARGET_CFLAGS = -I./include -DUNICODE -DDBG -Wall -Werror +TARGET_CFLAGS = -I./include -DUNICODE -Wall -Werror TARGET_OBJECTS = $(TARGET_NAME).o diff --git a/reactos/ntoskrnl/rtl/i386/exception.c b/reactos/ntoskrnl/rtl/i386/exception.c index 3983ae4a52a..04acc7a4209 100755 --- a/reactos/ntoskrnl/rtl/i386/exception.c +++ b/reactos/ntoskrnl/rtl/i386/exception.c @@ -1,4 +1,4 @@ -/* $Id: exception.c,v 1.1 2002/10/26 00:36:54 chorns Exp $ +/* $Id: exception.c,v 1.2 2002/10/26 09:53:16 dwelch Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -76,10 +76,10 @@ RtlpCaptureContext(PCONTEXT pContext); #define SehpSetExceptionList(NewExceptionList) \ KeGetCurrentThread()->TrapFrame->ExceptionList = (PVOID)(NewExceptionList) -#define SehpCaptureContext(Context) \ -{ \ - KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \ -} +#define SehpCaptureContext(Context) \ +{ \ + KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \ +} /*** Code below this line is shared with lib/ntdll/arch/ia32/exception.c - please keep in sync ***/ diff --git a/reactos/ntoskrnl/rtl/i386/seh.s b/reactos/ntoskrnl/rtl/i386/seh.s index 9b0e2b2ec02..fe6caf2c38c 100755 --- a/reactos/ntoskrnl/rtl/i386/seh.s +++ b/reactos/ntoskrnl/rtl/i386/seh.s @@ -1,366 +1,366 @@ -/* $Id: seh.s,v 1.2 2002/10/26 07:32:08 chorns Exp $ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * PURPOSE: Runtime library exception support for IA-32 - * FILE: ntoskrnl/rtl/i386/seh.s - * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) - * NOTES: This file is shared with lib/msvcrt/except/seh.s. - * Please keep them in sync. - */ - -#define ExceptionContinueExecution 0 -#define ExceptionContinueSearch 1 -#define ExceptionNestedException 2 -#define ExceptionCollidedUnwind 3 - -#define EXCEPTION_NONCONTINUABLE 0x01 -#define EXCEPTION_UNWINDING 0x02 -#define EXCEPTION_EXIT_UNWIND 0x04 -#define EXCEPTION_STACK_INVALID 0x08 -#define EXCEPTION_NESTED_CALL 0x10 -#define EXCEPTION_TARGET_UNWIND 0x20 -#define EXCEPTION_COLLIDED_UNWIND 0x40 - -#define EXCEPTION_UNWIND_MODE \ -( EXCEPTION_UNWINDING \ - | EXCEPTION_EXIT_UNWIND \ - | EXCEPTION_TARGET_UNWIND \ - | EXCEPTION_COLLIDED_UNWIND) - -#define EREC_CODE 0x00 -#define EREC_FLAGS 0x04 -#define EREC_RECORD 0x08 -#define EREC_ADDRESS 0x0C -#define EREC_NUMPARAMS 0x10 -#define EREC_INFO 0x14 - -#define TRYLEVEL_NONE -1 -#define TRYLEVEL_INVALID -2 - -#define ER_STANDARDESP -0x08 -#define ER_EPOINTERS -0x04 -#define ER_PREVFRAME 0x00 -#define ER_HANDLER 0x04 -#define ER_SCOPETABLE 0x08 -#define ER_TRYLEVEL 0x0C -#define ER_EBP 0x10 - -#define ST_TRYLEVEL 0x00 -#define ST_FILTER 0x04 -#define ST_HANDLER 0x08 - -#define CONTEXT_EDI 0x9C -#define CONTEXT_EBX 0xA4 -#define CONTEXT_EIP 0xB8 - -.globl __local_unwind2 -.globl __except_handler3 - -// EAX = value to print -_do_debug: - pushal - pushl %eax - call _MsvcrtDebug@4 - popal - ret - -#define LU2_TRYLEVEL 0x08 -#define LU2_REGFRAME 0x04 - -// -// void -// _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame, -// LONG TryLevel) -// -// Parameters: -// [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame -// [EDX+04h] - LONG TryLevel -// Registers: -// EBP - EBP of call frame we are unwinding -// Returns: -// Nothing -// Notes: -// Run all termination handlers for a call frame from the current -// try-level up to (but not including) the given stop try-level. -__local_unwind2: - // Setup our call frame so we can access parameters using EDX - //pushl %ebp - movl %esp, %edx - - // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the - // unwinding in case something goes wrong - -.lu2_next_scope: - - // Keep a pointer to the exception registration in EBX - movl LU2_REGFRAME(%edx), %ebx - - // If we have reached the end of the chain or we're asked to stop here - // by the caller then exit - movl ER_TRYLEVEL(%ebx), %eax - - cmpl $-1, %eax - je .lu2_done - - cmpl LU2_TRYLEVEL(%edx), %eax - je .lu2_done - - // Keep a pointer to the scopetable in ESI - movl ER_SCOPETABLE(%ebx), %esi - - // Compute the offset of the entry in the scopetable that describes - // the scope that is to be unwound. Put the offset in EDI. - movl ST_TRYLEVEL(%esi), %edi - lea (%edi, %edi, 2), %edi - shll $2, %edi - addl %esi, %edi - - // If this is not a termination handler then skip it - cmpl $0, ST_FILTER(%edi) - jne .lu2_next_scope - - // Save the previous try-level in the exception registration structure - movl ST_TRYLEVEL(%edi), %eax - movl %eax, ER_TRYLEVEL(%ebx) - - // Fetch the address of the termination handler - movl ST_HANDLER(%edi), %eax - - // Termination handlers may trash all registers so save the - // important ones and then call the handler - pushl %edx - call *%eax - - // Get our base pointer back - popl %edx - - jmp .lu2_next_scope - -.lu2_done: - - // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect - // the unwinding - - //movl %esi, %esp - //popl %ebp - ret - -#define EH3_DISPCONTEXT 0x14 -#define EH3_CONTEXT 0x10 -#define EH3_REGFRAME 0x0C -#define EH3_ERECORD 0x08 - -// Parameters: -// [ESP+14h] - PVOID DispatcherContext -// [ESP+10h] - PCONTEXT Context -// [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame -// [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord -// Registers: -// Unknown -// Returns: -// EXCEPTION_DISPOSITION - How this handler handled the exception -// Notes: -// Try to find an exception handler that will handle the exception. -// Traverse the entries in the scopetable that is associated with the -// exception registration passed as a parameter to this function. -// If an exception handler that will handle the exception is found, it -// is called and this function never returns -__except_handler3: - // Setup our call frame so we can access parameters using EBP - pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION) - movl %esp, %ebp - - // Don't trust the direction flag to be cleared - cld - - // Either we're called to handle an exception or we're called to unwind - movl EH3_ERECORD(%ebp), %eax - testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax) - jnz .eh3_unwind - - // Keep a pointer to the exception registration in EBX - movl EH3_REGFRAME(%ebp), %ebx - - // Build an EXCEPTION_POINTERS structure on the stack and store it's - // address in the EXCEPTION_REGISTRATION structure - movl EH3_CONTEXT(%esp), %eax - pushl %ebx // Registration frame - pushl %eax // Context - movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack - - // Keep current try-level in EDI - movl ER_TRYLEVEL(%ebx), %edi - - // Keep a pointer to the scopetable in ESI - movl ER_SCOPETABLE(%ebx), %esi - -.eh3_next_scope: - - // If we have reached the end of the chain then exit - cmpl $-1, %edi - je .eh3_search - - // Compute the offset of the entry in the scopetable and store - // the absolute address in EAX - lea (%edi, %edi, 2), %eax - shll $2, %eax - addl %esi, %eax - - // Fetch the address of the filter routine - movl ST_FILTER(%eax), %eax - - // If this is a termination handler then skip it - cmpl $0, %eax - je .eh3_continue - - // Filter routines may trash all registers so save the important - // ones before restoring the call frame ebp and calling the handler - pushl %ebp - pushl %edi // Stop try-level - lea ER_EBP(%ebx), %ebp - call *%eax - popl %edi // Stop try-level - popl %ebp - - // Reload EBX with registration frame address - movl EH3_REGFRAME(%ebp), %ebx - - // Be more flexible here by checking if the return value is less than - // zero, equal to zero, or larger than zero instead of the defined - // values: - // -1 (EXCEPTION_CONTINUE_EXECUTION) - // 0 (EXCEPTION_CONTINUE_SEARCH) - // +1 (EXCEPTION_EXECUTE_HANDLER) - orl %eax, %eax - jz .eh3_continue - js .eh3_dismiss - - // Filter returned: EXCEPTION_EXECUTE_HANDLER - - // Ask the OS to perform global unwinding. - pushl %edi // Save stop try-level - pushl %ebx // Save registration frame address - pushl %ebx // Registration frame address - call __global_unwind2 - popl %eax // Remove parameter to __global_unwind2 - popl %ebx // Restore registration frame address - popl %edi // Restore stop try-level - - // Change the context structure so _except_finish is called in the - // correct context since we return ExceptionContinueExecution. - movl EH3_CONTEXT(%ebp), %eax - - movl %edi, CONTEXT_EDI(%eax) // Stop try-level - movl %ebx, CONTEXT_EBX(%eax) // Registration frame address - movl $_except_finish, CONTEXT_EIP(%eax) - - movl $ExceptionContinueExecution, %eax - jmp .eh3_return - - // Filter returned: EXCEPTION_CONTINUE_SEARCH -.eh3_continue: - - // Reload ESI because the filter routine may have trashed it - movl ER_SCOPETABLE(%ebx), %esi - - // Go one try-level closer to the top - lea (%edi, %edi, 2), %edi - shll $2, %edi - addl %esi, %edi - movl ST_TRYLEVEL(%edi), %edi - - jmp .eh3_next_scope - - // Filter returned: EXCEPTION_CONTINUE_EXECUTION - // Continue execution like nothing happened -.eh3_dismiss: - movl $ExceptionContinueExecution, %eax - jmp .eh3_return - - // Tell the OS to search for another handler that will handle the exception -.eh3_search: - - movl $ExceptionContinueSearch, %eax - jmp .eh3_return - - // Perform local unwinding -.eh3_unwind: - - movl $ExceptionContinueSearch, %eax - testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax) - jnz .eh3_return - - // Save some important registers - pushl %ebp - - lea ER_EBP(%ebx), %ebp - pushl $-1 - pushl %ebx - call __local_unwind2 - addl $8, %esp - - // Restore some important registers - popl %ebp - - movl $ExceptionContinueSearch, %eax - - // Get me out of here -.eh3_return: - - movl %ebp, %esp - popl %ebp - ret - -// Parameters: -// None -// Registers: -// EBX - Pointer to exception registration structure -// EDI - Stop try-level -// Returns: -// - -// Notes: -// - -_except_finish: - - // Setup EBP for the exception handler. By doing this the exception - // handler can access local variables as normal - lea ER_EBP(%ebx), %ebp - - // Save some important registers - pushl %ebp - pushl %ebx - pushl %edi - - // Stop try-level - pushl %edi - - // Pointer to exception registration structure - pushl %ebx - call __local_unwind2 - addl $8, %esp - - // Restore some important registers - popl %edi - popl %ebx - popl %ebp - - // Keep a pointer to the scopetable in ESI - movl ER_SCOPETABLE(%ebx), %esi - - // Compute the offset of the entry in the scopetable and store - // the absolute address in EDI - lea (%edi, %edi, 2), %edi - shll $2, %edi - addl %esi, %edi - - // Set the current try-level to the previous try-level and call - // the exception handler - movl ST_TRYLEVEL(%edi), %eax - movl %eax, ER_TRYLEVEL(%ebx) - movl ST_HANDLER(%edi), %eax - - call *%eax - - // We should never get here - ret +/* $Id: seh.s,v 1.3 2002/10/26 09:53:16 dwelch Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PURPOSE: Runtime library exception support for IA-32 + * FILE: ntoskrnl/rtl/i386/seh.s + * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) + * NOTES: This file is shared with lib/msvcrt/except/seh.s. + * Please keep them in sync. + */ + +#define ExceptionContinueExecution 0 +#define ExceptionContinueSearch 1 +#define ExceptionNestedException 2 +#define ExceptionCollidedUnwind 3 + +#define EXCEPTION_NONCONTINUABLE 0x01 +#define EXCEPTION_UNWINDING 0x02 +#define EXCEPTION_EXIT_UNWIND 0x04 +#define EXCEPTION_STACK_INVALID 0x08 +#define EXCEPTION_NESTED_CALL 0x10 +#define EXCEPTION_TARGET_UNWIND 0x20 +#define EXCEPTION_COLLIDED_UNWIND 0x40 + +#define EXCEPTION_UNWIND_MODE \ +( EXCEPTION_UNWINDING \ + | EXCEPTION_EXIT_UNWIND \ + | EXCEPTION_TARGET_UNWIND \ + | EXCEPTION_COLLIDED_UNWIND) + +#define EREC_CODE 0x00 +#define EREC_FLAGS 0x04 +#define EREC_RECORD 0x08 +#define EREC_ADDRESS 0x0C +#define EREC_NUMPARAMS 0x10 +#define EREC_INFO 0x14 + +#define TRYLEVEL_NONE -1 +#define TRYLEVEL_INVALID -2 + +#define ER_STANDARDESP -0x08 +#define ER_EPOINTERS -0x04 +#define ER_PREVFRAME 0x00 +#define ER_HANDLER 0x04 +#define ER_SCOPETABLE 0x08 +#define ER_TRYLEVEL 0x0C +#define ER_EBP 0x10 + +#define ST_TRYLEVEL 0x00 +#define ST_FILTER 0x04 +#define ST_HANDLER 0x08 + +#define CONTEXT_EDI 0x9C +#define CONTEXT_EBX 0xA4 +#define CONTEXT_EIP 0xB8 + +.globl __local_unwind2 +.globl __except_handler3 + +// EAX = value to print +_do_debug: + pushal + pushl %eax + call _MsvcrtDebug@4 + popal + ret + +#define LU2_TRYLEVEL 0x08 +#define LU2_REGFRAME 0x04 + +// +// void +// _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame, +// LONG TryLevel) +// +// Parameters: +// [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame +// [EDX+04h] - LONG TryLevel +// Registers: +// EBP - EBP of call frame we are unwinding +// Returns: +// Nothing +// Notes: +// Run all termination handlers for a call frame from the current +// try-level up to (but not including) the given stop try-level. +__local_unwind2: + // Setup our call frame so we can access parameters using EDX + //pushl %ebp + movl %esp, %edx + + // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the + // unwinding in case something goes wrong + +.lu2_next_scope: + + // Keep a pointer to the exception registration in EBX + movl LU2_REGFRAME(%edx), %ebx + + // If we have reached the end of the chain or we're asked to stop here + // by the caller then exit + movl ER_TRYLEVEL(%ebx), %eax + + cmpl $-1, %eax + je .lu2_done + + cmpl LU2_TRYLEVEL(%edx), %eax + je .lu2_done + + // Keep a pointer to the scopetable in ESI + movl ER_SCOPETABLE(%ebx), %esi + + // Compute the offset of the entry in the scopetable that describes + // the scope that is to be unwound. Put the offset in EDI. + movl ST_TRYLEVEL(%esi), %edi + lea (%edi, %edi, 2), %edi + shll $2, %edi + addl %esi, %edi + + // If this is not a termination handler then skip it + cmpl $0, ST_FILTER(%edi) + jne .lu2_next_scope + + // Save the previous try-level in the exception registration structure + movl ST_TRYLEVEL(%edi), %eax + movl %eax, ER_TRYLEVEL(%ebx) + + // Fetch the address of the termination handler + movl ST_HANDLER(%edi), %eax + + // Termination handlers may trash all registers so save the + // important ones and then call the handler + pushl %edx + call *%eax + + // Get our base pointer back + popl %edx + + jmp .lu2_next_scope + +.lu2_done: + + // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect + // the unwinding + + //movl %esi, %esp + //popl %ebp + ret + +#define EH3_DISPCONTEXT 0x14 +#define EH3_CONTEXT 0x10 +#define EH3_REGFRAME 0x0C +#define EH3_ERECORD 0x08 + +// Parameters: +// [ESP+14h] - PVOID DispatcherContext +// [ESP+10h] - PCONTEXT Context +// [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame +// [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord +// Registers: +// Unknown +// Returns: +// EXCEPTION_DISPOSITION - How this handler handled the exception +// Notes: +// Try to find an exception handler that will handle the exception. +// Traverse the entries in the scopetable that is associated with the +// exception registration passed as a parameter to this function. +// If an exception handler that will handle the exception is found, it +// is called and this function never returns +__except_handler3: + // Setup our call frame so we can access parameters using EBP + pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION) + movl %esp, %ebp + + // Don't trust the direction flag to be cleared + cld + + // Either we're called to handle an exception or we're called to unwind + movl EH3_ERECORD(%ebp), %eax + testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax) + jnz .eh3_unwind + + // Keep a pointer to the exception registration in EBX + movl EH3_REGFRAME(%ebp), %ebx + + // Build an EXCEPTION_POINTERS structure on the stack and store it's + // address in the EXCEPTION_REGISTRATION structure + movl EH3_CONTEXT(%esp), %eax + pushl %ebx // Registration frame + pushl %eax // Context + movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack + + // Keep current try-level in EDI + movl ER_TRYLEVEL(%ebx), %edi + + // Keep a pointer to the scopetable in ESI + movl ER_SCOPETABLE(%ebx), %esi + +.eh3_next_scope: + + // If we have reached the end of the chain then exit + cmpl $-1, %edi + je .eh3_search + + // Compute the offset of the entry in the scopetable and store + // the absolute address in EAX + lea (%edi, %edi, 2), %eax + shll $2, %eax + addl %esi, %eax + + // Fetch the address of the filter routine + movl ST_FILTER(%eax), %eax + + // If this is a termination handler then skip it + cmpl $0, %eax + je .eh3_continue + + // Filter routines may trash all registers so save the important + // ones before restoring the call frame ebp and calling the handler + pushl %ebp + pushl %edi // Stop try-level + lea ER_EBP(%ebx), %ebp + call *%eax + popl %edi // Stop try-level + popl %ebp + + // Reload EBX with registration frame address + movl EH3_REGFRAME(%ebp), %ebx + + // Be more flexible here by checking if the return value is less than + // zero, equal to zero, or larger than zero instead of the defined + // values: + // -1 (EXCEPTION_CONTINUE_EXECUTION) + // 0 (EXCEPTION_CONTINUE_SEARCH) + // +1 (EXCEPTION_EXECUTE_HANDLER) + orl %eax, %eax + jz .eh3_continue + js .eh3_dismiss + + // Filter returned: EXCEPTION_EXECUTE_HANDLER + + // Ask the OS to perform global unwinding. + pushl %edi // Save stop try-level + pushl %ebx // Save registration frame address + pushl %ebx // Registration frame address + call __global_unwind2 + popl %eax // Remove parameter to __global_unwind2 + popl %ebx // Restore registration frame address + popl %edi // Restore stop try-level + + // Change the context structure so _except_finish is called in the + // correct context since we return ExceptionContinueExecution. + movl EH3_CONTEXT(%ebp), %eax + + movl %edi, CONTEXT_EDI(%eax) // Stop try-level + movl %ebx, CONTEXT_EBX(%eax) // Registration frame address + movl $_except_finish, CONTEXT_EIP(%eax) + + movl $ExceptionContinueExecution, %eax + jmp .eh3_return + + // Filter returned: EXCEPTION_CONTINUE_SEARCH +.eh3_continue: + + // Reload ESI because the filter routine may have trashed it + movl ER_SCOPETABLE(%ebx), %esi + + // Go one try-level closer to the top + lea (%edi, %edi, 2), %edi + shll $2, %edi + addl %esi, %edi + movl ST_TRYLEVEL(%edi), %edi + + jmp .eh3_next_scope + + // Filter returned: EXCEPTION_CONTINUE_EXECUTION + // Continue execution like nothing happened +.eh3_dismiss: + movl $ExceptionContinueExecution, %eax + jmp .eh3_return + + // Tell the OS to search for another handler that will handle the exception +.eh3_search: + + movl $ExceptionContinueSearch, %eax + jmp .eh3_return + + // Perform local unwinding +.eh3_unwind: + + movl $ExceptionContinueSearch, %eax + testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax) + jnz .eh3_return + + // Save some important registers + pushl %ebp + + lea ER_EBP(%ebx), %ebp + pushl $-1 + pushl %ebx + call __local_unwind2 + addl $8, %esp + + // Restore some important registers + popl %ebp + + movl $ExceptionContinueSearch, %eax + + // Get me out of here +.eh3_return: + + movl %ebp, %esp + popl %ebp + ret + +// Parameters: +// None +// Registers: +// EBX - Pointer to exception registration structure +// EDI - Stop try-level +// Returns: +// - +// Notes: +// - +_except_finish: + + // Setup EBP for the exception handler. By doing this the exception + // handler can access local variables as normal + lea ER_EBP(%ebx), %ebp + + // Save some important registers + pushl %ebp + pushl %ebx + pushl %edi + + // Stop try-level + pushl %edi + + // Pointer to exception registration structure + pushl %ebx + call __local_unwind2 + addl $8, %esp + + // Restore some important registers + popl %edi + popl %ebx + popl %ebp + + // Keep a pointer to the scopetable in ESI + movl ER_SCOPETABLE(%ebx), %esi + + // Compute the offset of the entry in the scopetable and store + // the absolute address in EDI + lea (%edi, %edi, 2), %edi + shll $2, %edi + addl %esi, %edi + + // Set the current try-level to the previous try-level and call + // the exception handler + movl ST_TRYLEVEL(%edi), %eax + movl %eax, ER_TRYLEVEL(%ebx) + movl ST_HANDLER(%edi), %eax + + call *%eax + + // We should never get here + ret