📄 seh.s
字号:
/* $Id: seh.s 23790 2006-08-29 19:14:18Z greatlrd $
*
* 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
.globl __EH_prolog
// 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
test %ebx, %ebx
je .lu2_done
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:
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
// Copied from Wine.
__EH_prolog:
pushl $-1
pushl %eax
pushl %fs:0
movl %esp, %fs:0
movl 12(%esp), %eax
movl %ebp, 12(%esp)
leal 12(%esp), %ebp
pushl %eax
ret
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -