dos2unix'd some more files.

svn path=/trunk/; revision=3660
This commit is contained in:
David Welch 2002-10-26 09:53:16 +00:00
parent 9bbe34eb81
commit 31c69eaf8a
5 changed files with 1172 additions and 1172 deletions

View file

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

View file

@ -1,433 +1,433 @@
/* $Id: exception.c,v 1.2 2002/10/26 07:32:08 chorns Exp $ /* $Id: exception.c,v 1.3 2002/10/26 09:53:15 dwelch Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* PURPOSE: User-mode exception support for IA-32 * PURPOSE: User-mode exception support for IA-32
* FILE: lib/ntdll/rtl/i386/exception.c * FILE: lib/ntdll/rtl/i386/exception.c
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
#include <ddk/ntddk.h> #include <ddk/ntddk.h>
#include <windows.h> #include <windows.h>
#include <string.h> #include <string.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
/* FUNCTIONS ***************************************************************/ /* FUNCTIONS ***************************************************************/
/* Implemented in except.s */ /* Implemented in except.s */
VOID VOID
RtlpCaptureContext(PCONTEXT pContext); RtlpCaptureContext(PCONTEXT pContext);
/* Macros that will help streamline the SEH implementations for /* Macros that will help streamline the SEH implementations for
kernel mode and user mode */ kernel mode and user mode */
#define SehpGetStackLimits(StackBase, StackLimit) \ #define SehpGetStackLimits(StackBase, StackLimit) \
{ \ { \
(*(StackBase)) = NtCurrentTeb()->Tib->StackBase; \ (*(StackBase)) = NtCurrentTeb()->Tib->StackBase; \
(*(StackLimit)) = NtCurrentTeb()->Tib->StackLimit; \ (*(StackLimit)) = NtCurrentTeb()->Tib->StackLimit; \
} }
#define SehpGetExceptionList() \ #define SehpGetExceptionList() \
(PEXCEPTION_REGISTRATION)(NtCurrentTeb()->Tib.ExceptionList) (PEXCEPTION_REGISTRATION)(NtCurrentTeb()->Tib.ExceptionList)
#define SehpSetExceptionList(NewExceptionList) \ #define SehpSetExceptionList(NewExceptionList) \
NtCurrentTeb()->Tib.ExceptionList = (PVOID)(NewExceptionList) NtCurrentTeb()->Tib.ExceptionList = (PVOID)(NewExceptionList)
#define SehpCaptureContext(Context) \ #define SehpCaptureContext(Context) \
{ \ { \
RtlpCaptureContext(Context); \ RtlpCaptureContext(Context); \
} }
/*** Code below this line is shared with ntoskrnl/rtl/i386/exception.c - please keep in sync ***/ /*** Code below this line is shared with ntoskrnl/rtl/i386/exception.c - please keep in sync ***/
VOID STDCALL VOID STDCALL
AsmDebug(ULONG Value) AsmDebug(ULONG Value)
{ {
DbgPrint("Value 0x%.08x\n", Value); DbgPrint("Value 0x%.08x\n", Value);
} }
/* Declare a few prototypes for the functions in except.s */ /* Declare a few prototypes for the functions in except.s */
EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
RtlpExecuteHandlerForException( RtlpExecuteHandlerForException(
PEXCEPTION_RECORD ExceptionRecord, PEXCEPTION_RECORD ExceptionRecord,
PEXCEPTION_REGISTRATION RegistrationFrame, PEXCEPTION_REGISTRATION RegistrationFrame,
PCONTEXT Context, PCONTEXT Context,
PVOID DispatcherContext, PVOID DispatcherContext,
PEXCEPTION_HANDLER ExceptionHandler); PEXCEPTION_HANDLER ExceptionHandler);
EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
RtlpExecuteHandlerForUnwind( RtlpExecuteHandlerForUnwind(
PEXCEPTION_RECORD ExceptionRecord, PEXCEPTION_RECORD ExceptionRecord,
PEXCEPTION_REGISTRATION RegistrationFrame, PEXCEPTION_REGISTRATION RegistrationFrame,
PCONTEXT Context, PCONTEXT Context,
PVOID DispatcherContext, PVOID DispatcherContext,
PEXCEPTION_HANDLER ExceptionHandler); PEXCEPTION_HANDLER ExceptionHandler);
#ifndef NDEBUG #ifndef NDEBUG
VOID RtlpDumpExceptionRegistrations(VOID) VOID RtlpDumpExceptionRegistrations(VOID)
{ {
PEXCEPTION_REGISTRATION Current; PEXCEPTION_REGISTRATION Current;
DbgPrint("Dumping exception registrations:\n"); DbgPrint("Dumping exception registrations:\n");
Current = SehpGetExceptionList(); Current = SehpGetExceptionList();
if ((ULONG_PTR)Current != -1) if ((ULONG_PTR)Current != -1)
{ {
while ((ULONG_PTR)Current != -1) while ((ULONG_PTR)Current != -1)
{ {
DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler); DbgPrint(" (0x%08X) HANDLER (0x%08X)\n", Current, Current->handler);
Current = Current->prev; Current = Current->prev;
} }
DbgPrint(" End-Of-List\n"); DbgPrint(" End-Of-List\n");
} else { } else {
DbgPrint(" No exception registrations exists.\n"); DbgPrint(" No exception registrations exists.\n");
} }
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
ULONG ULONG
RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
IN PCONTEXT Context) IN PCONTEXT Context)
{ {
PEXCEPTION_REGISTRATION RegistrationFrame; PEXCEPTION_REGISTRATION RegistrationFrame;
DWORD DispatcherContext; DWORD DispatcherContext;
DWORD ReturnValue; DWORD ReturnValue;
DPRINT("RtlpDispatchException()\n"); DPRINT("RtlpDispatchException()\n");
#ifndef NDEBUG #ifndef NDEBUG
RtlpDumpExceptionRegistrations(); RtlpDumpExceptionRegistrations();
#endif /* NDEBUG */ #endif /* NDEBUG */
RegistrationFrame = SehpGetExceptionList(); RegistrationFrame = SehpGetExceptionList();
DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame); DPRINT("RegistrationFrame is 0x%X\n", RegistrationFrame);
while ((ULONG_PTR)RegistrationFrame != -1) while ((ULONG_PTR)RegistrationFrame != -1)
{ {
EXCEPTION_RECORD ExceptionRecord2; EXCEPTION_RECORD ExceptionRecord2;
DWORD Temp = 0; DWORD Temp = 0;
//PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8; //PVOID RegistrationFrameEnd = (PVOID)RegistrationFrame + 8;
// Make sure the registration frame is located within the stack // Make sure the registration frame is located within the stack
DPRINT("Error checking\n"); DPRINT("Error checking\n");
#if 0 #if 0
if (Teb->Tib.StackBase > RegistrationFrameEnd) if (Teb->Tib.StackBase > RegistrationFrameEnd)
{ {
DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n", DPRINT("Teb->Tib.StackBase (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
Teb->Tib.StackBase, RegistrationFrameEnd); Teb->Tib.StackBase, RegistrationFrameEnd);
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
return ExceptionContinueExecution; return ExceptionContinueExecution;
} }
// FIXME: Stack top, correct? // FIXME: Stack top, correct?
if (Teb->Tib.StackLimit < RegistrationFrameEnd) if (Teb->Tib.StackLimit < RegistrationFrameEnd)
{ {
DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n", DPRINT("Teb->Tib.StackLimit (0x%.08x) > RegistrationFrameEnd (0x%.08x)\n",
Teb->Tib.StackLimit, RegistrationFrameEnd); Teb->Tib.StackLimit, RegistrationFrameEnd);
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
return ExceptionContinueExecution; return ExceptionContinueExecution;
} }
// Make sure stack is DWORD aligned // Make sure stack is DWORD aligned
if ((ULONG_PTR)RegistrationFrame & 3) if ((ULONG_PTR)RegistrationFrame & 3)
{ {
DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n", DPRINT("RegistrationFrameEnd (0x%.08x) is not DWORD aligned.\n",
RegistrationFrameEnd); RegistrationFrameEnd);
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID; ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
return ExceptionContinueExecution; return ExceptionContinueExecution;
} }
#endif #endif
#if 0 #if 0
/* FIXME: */ /* FIXME: */
if (someFlag) if (someFlag)
RtlpLogLastExceptionDisposition( hLog, retValue ); RtlpLogLastExceptionDisposition( hLog, retValue );
#endif #endif
DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler); DPRINT("Calling handler at 0x%X\n", RegistrationFrame->handler);
DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord); DPRINT("ExceptionRecord 0x%X\n", ExceptionRecord);
DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame); DPRINT("RegistrationFrame 0x%X\n", RegistrationFrame);
DPRINT("Context 0x%X\n", Context); DPRINT("Context 0x%X\n", Context);
DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext); DPRINT("&DispatcherContext 0x%X\n", &DispatcherContext);
ReturnValue = RtlpExecuteHandlerForException( ReturnValue = RtlpExecuteHandlerForException(
ExceptionRecord, ExceptionRecord,
RegistrationFrame, RegistrationFrame,
Context, Context,
&DispatcherContext, &DispatcherContext,
RegistrationFrame->handler); RegistrationFrame->handler);
DPRINT("Exception handler said 0x%X\n", ReturnValue); DPRINT("Exception handler said 0x%X\n", ReturnValue);
DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame); DPRINT("RegistrationFrame == 0x%.08x\n", RegistrationFrame);
{ {
PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08); PULONG sp = (PULONG)((PVOID)RegistrationFrame - 0x08);
DPRINT("StandardESP == 0x%.08x\n", sp[0]); DPRINT("StandardESP == 0x%.08x\n", sp[0]);
DPRINT("Exception Pointers == 0x%.08x\n", sp[1]); DPRINT("Exception Pointers == 0x%.08x\n", sp[1]);
DPRINT("PrevFrame == 0x%.08x\n", sp[2]); DPRINT("PrevFrame == 0x%.08x\n", sp[2]);
DPRINT("Handler == 0x%.08x\n", sp[3]); DPRINT("Handler == 0x%.08x\n", sp[3]);
DPRINT("ScopeTable == 0x%.08x\n", sp[4]); DPRINT("ScopeTable == 0x%.08x\n", sp[4]);
DPRINT("TryLevel == 0x%.08x\n", sp[5]); DPRINT("TryLevel == 0x%.08x\n", sp[5]);
DPRINT("EBP == 0x%.08x\n", sp[6]); DPRINT("EBP == 0x%.08x\n", sp[6]);
} }
if (RegistrationFrame == NULL) if (RegistrationFrame == NULL)
{ {
ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag ExceptionRecord->ExceptionFlags &= ~EXCEPTION_NESTED_CALL; // Turn off flag
} }
if (ReturnValue == ExceptionContinueExecution) if (ReturnValue == ExceptionContinueExecution)
{ {
DPRINT("ReturnValue == ExceptionContinueExecution\n"); DPRINT("ReturnValue == ExceptionContinueExecution\n");
if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
{ {
DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n"); DPRINT("(ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == TRUE\n");
ExceptionRecord2.ExceptionRecord = ExceptionRecord; ExceptionRecord2.ExceptionRecord = ExceptionRecord;
ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; ExceptionRecord2.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;
ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
ExceptionRecord2.NumberParameters = 0; ExceptionRecord2.NumberParameters = 0;
RtlRaiseException(&ExceptionRecord2); RtlRaiseException(&ExceptionRecord2);
} }
else else
{ {
/* Copy the (possibly changed) context back to the trap frame and return */ /* Copy the (possibly changed) context back to the trap frame and return */
NtContinue(Context, FALSE); NtContinue(Context, FALSE);
return ExceptionContinueExecution; return ExceptionContinueExecution;
} }
} }
else if (ReturnValue == ExceptionContinueSearch) else if (ReturnValue == ExceptionContinueSearch)
{ {
DPRINT("ReturnValue == ExceptionContinueSearch\n"); DPRINT("ReturnValue == ExceptionContinueSearch\n");
/* Nothing to do here */ /* Nothing to do here */
} }
else if (ReturnValue == ExceptionNestedException) else if (ReturnValue == ExceptionNestedException)
{ {
DPRINT("ReturnValue == ExceptionNestedException\n"); DPRINT("ReturnValue == ExceptionNestedException\n");
ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND; ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
if (DispatcherContext > Temp) if (DispatcherContext > Temp)
{ {
Temp = DispatcherContext; Temp = DispatcherContext;
} }
} }
else /* if (ReturnValue == ExceptionCollidedUnwind) */ else /* if (ReturnValue == ExceptionCollidedUnwind) */
{ {
DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n"); DPRINT("ReturnValue == ExceptionCollidedUnwind or unknown\n");
ExceptionRecord2.ExceptionRecord = ExceptionRecord; ExceptionRecord2.ExceptionRecord = ExceptionRecord;
ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION; ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
ExceptionRecord2.NumberParameters = 0; ExceptionRecord2.NumberParameters = 0;
RtlRaiseException(&ExceptionRecord2); RtlRaiseException(&ExceptionRecord2);
} }
RegistrationFrame = RegistrationFrame->prev; // Go to previous frame RegistrationFrame = RegistrationFrame->prev; // Go to previous frame
} }
/* No exception handler will handle this exception */ /* No exception handler will handle this exception */
DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n"); DPRINT("RtlpDispatchException(): Return ExceptionContinueExecution\n");
return ExceptionContinueExecution; return ExceptionContinueExecution;
} }
VOID STDCALL VOID STDCALL
RtlRaiseStatus(NTSTATUS Status) RtlRaiseStatus(NTSTATUS Status)
{ {
EXCEPTION_RECORD ExceptionRecord; EXCEPTION_RECORD ExceptionRecord;
DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status); DPRINT("RtlRaiseStatus(Status 0x%.08x)\n", Status);
ExceptionRecord.ExceptionCode = Status; ExceptionRecord.ExceptionCode = Status;
ExceptionRecord.ExceptionRecord = NULL; ExceptionRecord.ExceptionRecord = NULL;
ExceptionRecord.NumberParameters = 0; ExceptionRecord.NumberParameters = 0;
ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
RtlRaiseException (& ExceptionRecord); RtlRaiseException (& ExceptionRecord);
} }
VOID STDCALL VOID STDCALL
RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame, RtlUnwind(PEXCEPTION_REGISTRATION RegistrationFrame,
PVOID ReturnAddress, PVOID ReturnAddress,
PEXCEPTION_RECORD ExceptionRecord, PEXCEPTION_RECORD ExceptionRecord,
DWORD EaxValue) DWORD EaxValue)
{ {
PEXCEPTION_REGISTRATION ERHead; PEXCEPTION_REGISTRATION ERHead;
PEXCEPTION_RECORD pExceptRec; PEXCEPTION_RECORD pExceptRec;
EXCEPTION_RECORD TempER; EXCEPTION_RECORD TempER;
CONTEXT Context; CONTEXT Context;
DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame); DPRINT("RtlUnwind(). RegistrationFrame 0x%X\n", RegistrationFrame);
#ifndef NDEBUG #ifndef NDEBUG
RtlpDumpExceptionRegistrations(); RtlpDumpExceptionRegistrations();
#endif /* NDEBUG */ #endif /* NDEBUG */
ERHead = SehpGetExceptionList(); ERHead = SehpGetExceptionList();
DPRINT("ERHead is 0x%X\n", ERHead); DPRINT("ERHead is 0x%X\n", ERHead);
if (ExceptionRecord == NULL) // The normal case if (ExceptionRecord == NULL) // The normal case
{ {
DPRINT("ExceptionRecord == NULL (normal)\n"); DPRINT("ExceptionRecord == NULL (normal)\n");
pExceptRec = &TempER; pExceptRec = &TempER;
pExceptRec->ExceptionFlags = 0; pExceptRec->ExceptionFlags = 0;
pExceptRec->ExceptionCode = STATUS_UNWIND; pExceptRec->ExceptionCode = STATUS_UNWIND;
pExceptRec->ExceptionRecord = NULL; pExceptRec->ExceptionRecord = NULL;
pExceptRec->ExceptionAddress = ReturnAddress; pExceptRec->ExceptionAddress = ReturnAddress;
pExceptRec->ExceptionInformation[0] = 0; pExceptRec->ExceptionInformation[0] = 0;
} }
if (RegistrationFrame) if (RegistrationFrame)
pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING; pExceptRec->ExceptionFlags |= EXCEPTION_UNWINDING;
else else
pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND); pExceptRec->ExceptionFlags |= (EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND);
#ifndef NDEBUG #ifndef NDEBUG
DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags); DPRINT("ExceptionFlags == 0x%x:\n", pExceptRec->ExceptionFlags);
if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING) if (pExceptRec->ExceptionFlags & EXCEPTION_UNWINDING)
{ {
DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING); DPRINT(" * EXCEPTION_UNWINDING (0x%x)\n", EXCEPTION_UNWINDING);
} }
if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND) if (pExceptRec->ExceptionFlags & EXCEPTION_EXIT_UNWIND)
{ {
DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND); DPRINT(" * EXCEPTION_EXIT_UNWIND (0x%x)\n", EXCEPTION_EXIT_UNWIND);
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
Context.ContextFlags = Context.ContextFlags =
(CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS); (CONTEXT_i386 | CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS);
SehpCaptureContext(&Context); SehpCaptureContext(&Context);
DPRINT("Context.Eip = 0x%.08x\n", Context.Eip); DPRINT("Context.Eip = 0x%.08x\n", Context.Eip);
DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp); DPRINT("Context.Ebp = 0x%.08x\n", Context.Ebp);
DPRINT("Context.Esp = 0x%.08x\n", Context.Esp); DPRINT("Context.Esp = 0x%.08x\n", Context.Esp);
Context.Esp += 0x10; Context.Esp += 0x10;
Context.Eax = EaxValue; Context.Eax = EaxValue;
// Begin traversing the list of EXCEPTION_REGISTRATION // Begin traversing the list of EXCEPTION_REGISTRATION
while ((ULONG_PTR)ERHead != -1) while ((ULONG_PTR)ERHead != -1)
{ {
EXCEPTION_RECORD er2; EXCEPTION_RECORD er2;
DPRINT("ERHead 0x%X\n", ERHead); DPRINT("ERHead 0x%X\n", ERHead);
if (ERHead == RegistrationFrame) if (ERHead == RegistrationFrame)
{ {
DPRINT("Continueing execution\n"); DPRINT("Continueing execution\n");
NtContinue(&Context, FALSE); NtContinue(&Context, FALSE);
return; return;
} }
else else
{ {
// If there's an exception frame, but it's lower on the stack // If there's an exception frame, but it's lower on the stack
// than the head of the exception list, something's wrong! // than the head of the exception list, something's wrong!
if (RegistrationFrame && (RegistrationFrame <= ERHead)) if (RegistrationFrame && (RegistrationFrame <= ERHead))
{ {
DPRINT("The exception frame is bad\n"); DPRINT("The exception frame is bad\n");
// Generate an exception to bail out // Generate an exception to bail out
er2.ExceptionRecord = pExceptRec; er2.ExceptionRecord = pExceptRec;
er2.NumberParameters = 0; er2.NumberParameters = 0;
er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET; er2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
RtlRaiseException(&er2); RtlRaiseException(&er2);
} }
} }
#if 0 #if 0
Stack = ERHead + sizeof(EXCEPTION_REGISTRATION); Stack = ERHead + sizeof(EXCEPTION_REGISTRATION);
if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead if ( (Teb->Tib.StackBase <= (PVOID)ERHead ) // Make sure that ERHead
&& (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple && (Teb->Tib.->StackLimit >= (PVOID)Stack ) // is in range, and a multiple
&& (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane) && (0 == ((ULONG_PTR)ERHead & 3)) ) // of 4 (i.e., sane)
{ {
#else #else
if (1) { if (1) {
#endif #endif
PEXCEPTION_REGISTRATION NewERHead; PEXCEPTION_REGISTRATION NewERHead;
PEXCEPTION_REGISTRATION pCurrExceptReg; PEXCEPTION_REGISTRATION pCurrExceptReg;
EXCEPTION_DISPOSITION ReturnValue; EXCEPTION_DISPOSITION ReturnValue;
DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler); DPRINT("Executing handler at 0x%X for unwind\n", ERHead->handler);
ReturnValue = RtlpExecuteHandlerForUnwind( ReturnValue = RtlpExecuteHandlerForUnwind(
pExceptRec, pExceptRec,
ERHead, ERHead,
&Context, &Context,
&NewERHead, &NewERHead,
ERHead->handler); ERHead->handler);
DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue); DPRINT("Handler at 0x%X returned 0x%X\n", ERHead->handler, ReturnValue);
if (ReturnValue != ExceptionContinueSearch) if (ReturnValue != ExceptionContinueSearch)
{ {
if (ReturnValue != ExceptionCollidedUnwind) if (ReturnValue != ExceptionCollidedUnwind)
{ {
DPRINT("Bad return value\n"); DPRINT("Bad return value\n");
er2.ExceptionRecord = pExceptRec; er2.ExceptionRecord = pExceptRec;
er2.NumberParameters = 0; er2.NumberParameters = 0;
er2.ExceptionCode = STATUS_INVALID_DISPOSITION; er2.ExceptionCode = STATUS_INVALID_DISPOSITION;
er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
RtlRaiseException(&er2); RtlRaiseException(&er2);
} }
else else
{ {
ERHead = NewERHead; ERHead = NewERHead;
} }
} }
pCurrExceptReg = ERHead; pCurrExceptReg = ERHead;
ERHead = ERHead->prev; ERHead = ERHead->prev;
DPRINT("New ERHead is 0x%X\n", ERHead); DPRINT("New ERHead is 0x%X\n", ERHead);
DPRINT("Setting exception registration at 0x%X as current\n", DPRINT("Setting exception registration at 0x%X as current\n",
RegistrationFrame->prev); RegistrationFrame->prev);
// Unlink the exception handler // Unlink the exception handler
SehpSetExceptionList(RegistrationFrame->prev); SehpSetExceptionList(RegistrationFrame->prev);
} }
else // The stack looks goofy! Raise an exception to bail out else // The stack looks goofy! Raise an exception to bail out
{ {
DPRINT("Bad stack\n"); DPRINT("Bad stack\n");
er2.ExceptionRecord = pExceptRec; er2.ExceptionRecord = pExceptRec;
er2.NumberParameters = 0; er2.NumberParameters = 0;
er2.ExceptionCode = STATUS_BAD_STACK; er2.ExceptionCode = STATUS_BAD_STACK;
er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE; er2.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
RtlRaiseException(&er2); RtlRaiseException(&er2);
} }
} }
// If we get here, we reached the end of the EXCEPTION_REGISTRATION list. // If we get here, we reached the end of the EXCEPTION_REGISTRATION list.
// This shouldn't happen normally. // This shouldn't happen normally.
DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n", DPRINT("Ran out of exception registrations. RegistrationFrame is (0x%X)\n",
RegistrationFrame); RegistrationFrame);
if ((ULONG_PTR)RegistrationFrame == -1) if ((ULONG_PTR)RegistrationFrame == -1)
NtContinue(&Context, FALSE); NtContinue(&Context, FALSE);
else else
NtRaiseException(pExceptRec, &Context, 0); NtRaiseException(pExceptRec, &Context, 0);
} }
/* EOF */ /* EOF */

View file

@ -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 = ../.. PATH_TO_TOP = ../..
@ -10,7 +10,7 @@ TARGET_BASE = 0x77e70000
TARGET_SDKLIBS = ntdll.a kernel32.a gdi32.a 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 TARGET_OBJECTS = $(TARGET_NAME).o

View file

@ -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 * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
@ -76,10 +76,10 @@ RtlpCaptureContext(PCONTEXT pContext);
#define SehpSetExceptionList(NewExceptionList) \ #define SehpSetExceptionList(NewExceptionList) \
KeGetCurrentThread()->TrapFrame->ExceptionList = (PVOID)(NewExceptionList) KeGetCurrentThread()->TrapFrame->ExceptionList = (PVOID)(NewExceptionList)
#define SehpCaptureContext(Context) \ #define SehpCaptureContext(Context) \
{ \ { \
KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \ KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, (Context)); \
} }
/*** Code below this line is shared with lib/ntdll/arch/ia32/exception.c - please keep in sync ***/ /*** Code below this line is shared with lib/ntdll/arch/ia32/exception.c - please keep in sync ***/

View file

@ -1,366 +1,366 @@
/* $Id: seh.s,v 1.2 2002/10/26 07:32:08 chorns Exp $ /* $Id: seh.s,v 1.3 2002/10/26 09:53:16 dwelch Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* PURPOSE: Runtime library exception support for IA-32 * PURPOSE: Runtime library exception support for IA-32
* FILE: ntoskrnl/rtl/i386/seh.s * FILE: ntoskrnl/rtl/i386/seh.s
* PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* NOTES: This file is shared with lib/msvcrt/except/seh.s. * NOTES: This file is shared with lib/msvcrt/except/seh.s.
* Please keep them in sync. * Please keep them in sync.
*/ */
#define ExceptionContinueExecution 0 #define ExceptionContinueExecution 0
#define ExceptionContinueSearch 1 #define ExceptionContinueSearch 1
#define ExceptionNestedException 2 #define ExceptionNestedException 2
#define ExceptionCollidedUnwind 3 #define ExceptionCollidedUnwind 3
#define EXCEPTION_NONCONTINUABLE 0x01 #define EXCEPTION_NONCONTINUABLE 0x01
#define EXCEPTION_UNWINDING 0x02 #define EXCEPTION_UNWINDING 0x02
#define EXCEPTION_EXIT_UNWIND 0x04 #define EXCEPTION_EXIT_UNWIND 0x04
#define EXCEPTION_STACK_INVALID 0x08 #define EXCEPTION_STACK_INVALID 0x08
#define EXCEPTION_NESTED_CALL 0x10 #define EXCEPTION_NESTED_CALL 0x10
#define EXCEPTION_TARGET_UNWIND 0x20 #define EXCEPTION_TARGET_UNWIND 0x20
#define EXCEPTION_COLLIDED_UNWIND 0x40 #define EXCEPTION_COLLIDED_UNWIND 0x40
#define EXCEPTION_UNWIND_MODE \ #define EXCEPTION_UNWIND_MODE \
( EXCEPTION_UNWINDING \ ( EXCEPTION_UNWINDING \
| EXCEPTION_EXIT_UNWIND \ | EXCEPTION_EXIT_UNWIND \
| EXCEPTION_TARGET_UNWIND \ | EXCEPTION_TARGET_UNWIND \
| EXCEPTION_COLLIDED_UNWIND) | EXCEPTION_COLLIDED_UNWIND)
#define EREC_CODE 0x00 #define EREC_CODE 0x00
#define EREC_FLAGS 0x04 #define EREC_FLAGS 0x04
#define EREC_RECORD 0x08 #define EREC_RECORD 0x08
#define EREC_ADDRESS 0x0C #define EREC_ADDRESS 0x0C
#define EREC_NUMPARAMS 0x10 #define EREC_NUMPARAMS 0x10
#define EREC_INFO 0x14 #define EREC_INFO 0x14
#define TRYLEVEL_NONE -1 #define TRYLEVEL_NONE -1
#define TRYLEVEL_INVALID -2 #define TRYLEVEL_INVALID -2
#define ER_STANDARDESP -0x08 #define ER_STANDARDESP -0x08
#define ER_EPOINTERS -0x04 #define ER_EPOINTERS -0x04
#define ER_PREVFRAME 0x00 #define ER_PREVFRAME 0x00
#define ER_HANDLER 0x04 #define ER_HANDLER 0x04
#define ER_SCOPETABLE 0x08 #define ER_SCOPETABLE 0x08
#define ER_TRYLEVEL 0x0C #define ER_TRYLEVEL 0x0C
#define ER_EBP 0x10 #define ER_EBP 0x10
#define ST_TRYLEVEL 0x00 #define ST_TRYLEVEL 0x00
#define ST_FILTER 0x04 #define ST_FILTER 0x04
#define ST_HANDLER 0x08 #define ST_HANDLER 0x08
#define CONTEXT_EDI 0x9C #define CONTEXT_EDI 0x9C
#define CONTEXT_EBX 0xA4 #define CONTEXT_EBX 0xA4
#define CONTEXT_EIP 0xB8 #define CONTEXT_EIP 0xB8
.globl __local_unwind2 .globl __local_unwind2
.globl __except_handler3 .globl __except_handler3
// EAX = value to print // EAX = value to print
_do_debug: _do_debug:
pushal pushal
pushl %eax pushl %eax
call _MsvcrtDebug@4 call _MsvcrtDebug@4
popal popal
ret ret
#define LU2_TRYLEVEL 0x08 #define LU2_TRYLEVEL 0x08
#define LU2_REGFRAME 0x04 #define LU2_REGFRAME 0x04
// //
// void // void
// _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame, // _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame,
// LONG TryLevel) // LONG TryLevel)
// //
// Parameters: // Parameters:
// [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame // [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame
// [EDX+04h] - LONG TryLevel // [EDX+04h] - LONG TryLevel
// Registers: // Registers:
// EBP - EBP of call frame we are unwinding // EBP - EBP of call frame we are unwinding
// Returns: // Returns:
// Nothing // Nothing
// Notes: // Notes:
// Run all termination handlers for a call frame from the current // Run all termination handlers for a call frame from the current
// try-level up to (but not including) the given stop try-level. // try-level up to (but not including) the given stop try-level.
__local_unwind2: __local_unwind2:
// Setup our call frame so we can access parameters using EDX // Setup our call frame so we can access parameters using EDX
//pushl %ebp //pushl %ebp
movl %esp, %edx movl %esp, %edx
// FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the
// unwinding in case something goes wrong // unwinding in case something goes wrong
.lu2_next_scope: .lu2_next_scope:
// Keep a pointer to the exception registration in EBX // Keep a pointer to the exception registration in EBX
movl LU2_REGFRAME(%edx), %ebx movl LU2_REGFRAME(%edx), %ebx
// If we have reached the end of the chain or we're asked to stop here // If we have reached the end of the chain or we're asked to stop here
// by the caller then exit // by the caller then exit
movl ER_TRYLEVEL(%ebx), %eax movl ER_TRYLEVEL(%ebx), %eax
cmpl $-1, %eax cmpl $-1, %eax
je .lu2_done je .lu2_done
cmpl LU2_TRYLEVEL(%edx), %eax cmpl LU2_TRYLEVEL(%edx), %eax
je .lu2_done je .lu2_done
// Keep a pointer to the scopetable in ESI // Keep a pointer to the scopetable in ESI
movl ER_SCOPETABLE(%ebx), %esi movl ER_SCOPETABLE(%ebx), %esi
// Compute the offset of the entry in the scopetable that describes // Compute the offset of the entry in the scopetable that describes
// the scope that is to be unwound. Put the offset in EDI. // the scope that is to be unwound. Put the offset in EDI.
movl ST_TRYLEVEL(%esi), %edi movl ST_TRYLEVEL(%esi), %edi
lea (%edi, %edi, 2), %edi lea (%edi, %edi, 2), %edi
shll $2, %edi shll $2, %edi
addl %esi, %edi addl %esi, %edi
// If this is not a termination handler then skip it // If this is not a termination handler then skip it
cmpl $0, ST_FILTER(%edi) cmpl $0, ST_FILTER(%edi)
jne .lu2_next_scope jne .lu2_next_scope
// Save the previous try-level in the exception registration structure // Save the previous try-level in the exception registration structure
movl ST_TRYLEVEL(%edi), %eax movl ST_TRYLEVEL(%edi), %eax
movl %eax, ER_TRYLEVEL(%ebx) movl %eax, ER_TRYLEVEL(%ebx)
// Fetch the address of the termination handler // Fetch the address of the termination handler
movl ST_HANDLER(%edi), %eax movl ST_HANDLER(%edi), %eax
// Termination handlers may trash all registers so save the // Termination handlers may trash all registers so save the
// important ones and then call the handler // important ones and then call the handler
pushl %edx pushl %edx
call *%eax call *%eax
// Get our base pointer back // Get our base pointer back
popl %edx popl %edx
jmp .lu2_next_scope jmp .lu2_next_scope
.lu2_done: .lu2_done:
// FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect
// the unwinding // the unwinding
//movl %esi, %esp //movl %esi, %esp
//popl %ebp //popl %ebp
ret ret
#define EH3_DISPCONTEXT 0x14 #define EH3_DISPCONTEXT 0x14
#define EH3_CONTEXT 0x10 #define EH3_CONTEXT 0x10
#define EH3_REGFRAME 0x0C #define EH3_REGFRAME 0x0C
#define EH3_ERECORD 0x08 #define EH3_ERECORD 0x08
// Parameters: // Parameters:
// [ESP+14h] - PVOID DispatcherContext // [ESP+14h] - PVOID DispatcherContext
// [ESP+10h] - PCONTEXT Context // [ESP+10h] - PCONTEXT Context
// [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame // [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame
// [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord // [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord
// Registers: // Registers:
// Unknown // Unknown
// Returns: // Returns:
// EXCEPTION_DISPOSITION - How this handler handled the exception // EXCEPTION_DISPOSITION - How this handler handled the exception
// Notes: // Notes:
// Try to find an exception handler that will handle the exception. // Try to find an exception handler that will handle the exception.
// Traverse the entries in the scopetable that is associated with the // Traverse the entries in the scopetable that is associated with the
// exception registration passed as a parameter to this function. // exception registration passed as a parameter to this function.
// If an exception handler that will handle the exception is found, it // If an exception handler that will handle the exception is found, it
// is called and this function never returns // is called and this function never returns
__except_handler3: __except_handler3:
// Setup our call frame so we can access parameters using EBP // Setup our call frame so we can access parameters using EBP
pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION) pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION)
movl %esp, %ebp movl %esp, %ebp
// Don't trust the direction flag to be cleared // Don't trust the direction flag to be cleared
cld cld
// Either we're called to handle an exception or we're called to unwind // Either we're called to handle an exception or we're called to unwind
movl EH3_ERECORD(%ebp), %eax movl EH3_ERECORD(%ebp), %eax
testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax) testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax)
jnz .eh3_unwind jnz .eh3_unwind
// Keep a pointer to the exception registration in EBX // Keep a pointer to the exception registration in EBX
movl EH3_REGFRAME(%ebp), %ebx movl EH3_REGFRAME(%ebp), %ebx
// Build an EXCEPTION_POINTERS structure on the stack and store it's // Build an EXCEPTION_POINTERS structure on the stack and store it's
// address in the EXCEPTION_REGISTRATION structure // address in the EXCEPTION_REGISTRATION structure
movl EH3_CONTEXT(%esp), %eax movl EH3_CONTEXT(%esp), %eax
pushl %ebx // Registration frame pushl %ebx // Registration frame
pushl %eax // Context pushl %eax // Context
movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack
// Keep current try-level in EDI // Keep current try-level in EDI
movl ER_TRYLEVEL(%ebx), %edi movl ER_TRYLEVEL(%ebx), %edi
// Keep a pointer to the scopetable in ESI // Keep a pointer to the scopetable in ESI
movl ER_SCOPETABLE(%ebx), %esi movl ER_SCOPETABLE(%ebx), %esi
.eh3_next_scope: .eh3_next_scope:
// If we have reached the end of the chain then exit // If we have reached the end of the chain then exit
cmpl $-1, %edi cmpl $-1, %edi
je .eh3_search je .eh3_search
// Compute the offset of the entry in the scopetable and store // Compute the offset of the entry in the scopetable and store
// the absolute address in EAX // the absolute address in EAX
lea (%edi, %edi, 2), %eax lea (%edi, %edi, 2), %eax
shll $2, %eax shll $2, %eax
addl %esi, %eax addl %esi, %eax
// Fetch the address of the filter routine // Fetch the address of the filter routine
movl ST_FILTER(%eax), %eax movl ST_FILTER(%eax), %eax
// If this is a termination handler then skip it // If this is a termination handler then skip it
cmpl $0, %eax cmpl $0, %eax
je .eh3_continue je .eh3_continue
// Filter routines may trash all registers so save the important // Filter routines may trash all registers so save the important
// ones before restoring the call frame ebp and calling the handler // ones before restoring the call frame ebp and calling the handler
pushl %ebp pushl %ebp
pushl %edi // Stop try-level pushl %edi // Stop try-level
lea ER_EBP(%ebx), %ebp lea ER_EBP(%ebx), %ebp
call *%eax call *%eax
popl %edi // Stop try-level popl %edi // Stop try-level
popl %ebp popl %ebp
// Reload EBX with registration frame address // Reload EBX with registration frame address
movl EH3_REGFRAME(%ebp), %ebx movl EH3_REGFRAME(%ebp), %ebx
// Be more flexible here by checking if the return value is less than // 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 // zero, equal to zero, or larger than zero instead of the defined
// values: // values:
// -1 (EXCEPTION_CONTINUE_EXECUTION) // -1 (EXCEPTION_CONTINUE_EXECUTION)
// 0 (EXCEPTION_CONTINUE_SEARCH) // 0 (EXCEPTION_CONTINUE_SEARCH)
// +1 (EXCEPTION_EXECUTE_HANDLER) // +1 (EXCEPTION_EXECUTE_HANDLER)
orl %eax, %eax orl %eax, %eax
jz .eh3_continue jz .eh3_continue
js .eh3_dismiss js .eh3_dismiss
// Filter returned: EXCEPTION_EXECUTE_HANDLER // Filter returned: EXCEPTION_EXECUTE_HANDLER
// Ask the OS to perform global unwinding. // Ask the OS to perform global unwinding.
pushl %edi // Save stop try-level pushl %edi // Save stop try-level
pushl %ebx // Save registration frame address pushl %ebx // Save registration frame address
pushl %ebx // Registration frame address pushl %ebx // Registration frame address
call __global_unwind2 call __global_unwind2
popl %eax // Remove parameter to __global_unwind2 popl %eax // Remove parameter to __global_unwind2
popl %ebx // Restore registration frame address popl %ebx // Restore registration frame address
popl %edi // Restore stop try-level popl %edi // Restore stop try-level
// Change the context structure so _except_finish is called in the // Change the context structure so _except_finish is called in the
// correct context since we return ExceptionContinueExecution. // correct context since we return ExceptionContinueExecution.
movl EH3_CONTEXT(%ebp), %eax movl EH3_CONTEXT(%ebp), %eax
movl %edi, CONTEXT_EDI(%eax) // Stop try-level movl %edi, CONTEXT_EDI(%eax) // Stop try-level
movl %ebx, CONTEXT_EBX(%eax) // Registration frame address movl %ebx, CONTEXT_EBX(%eax) // Registration frame address
movl $_except_finish, CONTEXT_EIP(%eax) movl $_except_finish, CONTEXT_EIP(%eax)
movl $ExceptionContinueExecution, %eax movl $ExceptionContinueExecution, %eax
jmp .eh3_return jmp .eh3_return
// Filter returned: EXCEPTION_CONTINUE_SEARCH // Filter returned: EXCEPTION_CONTINUE_SEARCH
.eh3_continue: .eh3_continue:
// Reload ESI because the filter routine may have trashed it // Reload ESI because the filter routine may have trashed it
movl ER_SCOPETABLE(%ebx), %esi movl ER_SCOPETABLE(%ebx), %esi
// Go one try-level closer to the top // Go one try-level closer to the top
lea (%edi, %edi, 2), %edi lea (%edi, %edi, 2), %edi
shll $2, %edi shll $2, %edi
addl %esi, %edi addl %esi, %edi
movl ST_TRYLEVEL(%edi), %edi movl ST_TRYLEVEL(%edi), %edi
jmp .eh3_next_scope jmp .eh3_next_scope
// Filter returned: EXCEPTION_CONTINUE_EXECUTION // Filter returned: EXCEPTION_CONTINUE_EXECUTION
// Continue execution like nothing happened // Continue execution like nothing happened
.eh3_dismiss: .eh3_dismiss:
movl $ExceptionContinueExecution, %eax movl $ExceptionContinueExecution, %eax
jmp .eh3_return jmp .eh3_return
// Tell the OS to search for another handler that will handle the exception // Tell the OS to search for another handler that will handle the exception
.eh3_search: .eh3_search:
movl $ExceptionContinueSearch, %eax movl $ExceptionContinueSearch, %eax
jmp .eh3_return jmp .eh3_return
// Perform local unwinding // Perform local unwinding
.eh3_unwind: .eh3_unwind:
movl $ExceptionContinueSearch, %eax movl $ExceptionContinueSearch, %eax
testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax) testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax)
jnz .eh3_return jnz .eh3_return
// Save some important registers // Save some important registers
pushl %ebp pushl %ebp
lea ER_EBP(%ebx), %ebp lea ER_EBP(%ebx), %ebp
pushl $-1 pushl $-1
pushl %ebx pushl %ebx
call __local_unwind2 call __local_unwind2
addl $8, %esp addl $8, %esp
// Restore some important registers // Restore some important registers
popl %ebp popl %ebp
movl $ExceptionContinueSearch, %eax movl $ExceptionContinueSearch, %eax
// Get me out of here // Get me out of here
.eh3_return: .eh3_return:
movl %ebp, %esp movl %ebp, %esp
popl %ebp popl %ebp
ret ret
// Parameters: // Parameters:
// None // None
// Registers: // Registers:
// EBX - Pointer to exception registration structure // EBX - Pointer to exception registration structure
// EDI - Stop try-level // EDI - Stop try-level
// Returns: // Returns:
// - // -
// Notes: // Notes:
// - // -
_except_finish: _except_finish:
// Setup EBP for the exception handler. By doing this the exception // Setup EBP for the exception handler. By doing this the exception
// handler can access local variables as normal // handler can access local variables as normal
lea ER_EBP(%ebx), %ebp lea ER_EBP(%ebx), %ebp
// Save some important registers // Save some important registers
pushl %ebp pushl %ebp
pushl %ebx pushl %ebx
pushl %edi pushl %edi
// Stop try-level // Stop try-level
pushl %edi pushl %edi
// Pointer to exception registration structure // Pointer to exception registration structure
pushl %ebx pushl %ebx
call __local_unwind2 call __local_unwind2
addl $8, %esp addl $8, %esp
// Restore some important registers // Restore some important registers
popl %edi popl %edi
popl %ebx popl %ebx
popl %ebp popl %ebp
// Keep a pointer to the scopetable in ESI // Keep a pointer to the scopetable in ESI
movl ER_SCOPETABLE(%ebx), %esi movl ER_SCOPETABLE(%ebx), %esi
// Compute the offset of the entry in the scopetable and store // Compute the offset of the entry in the scopetable and store
// the absolute address in EDI // the absolute address in EDI
lea (%edi, %edi, 2), %edi lea (%edi, %edi, 2), %edi
shll $2, %edi shll $2, %edi
addl %esi, %edi addl %esi, %edi
// Set the current try-level to the previous try-level and call // Set the current try-level to the previous try-level and call
// the exception handler // the exception handler
movl ST_TRYLEVEL(%edi), %eax movl ST_TRYLEVEL(%edi), %eax
movl %eax, ER_TRYLEVEL(%ebx) movl %eax, ER_TRYLEVEL(%ebx)
movl ST_HANDLER(%edi), %eax movl ST_HANDLER(%edi), %eax
call *%eax call *%eax
// We should never get here // We should never get here
ret ret