reactos/sdk/lib/pseh/i386/seh.s

452 lines
9.2 KiB
ArmAsm

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS CRT
* FILE: lib/crt/misc/i386/seh.S
* PURPOSE: SEH Support for the CRT
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ks386.inc>
#define DISPOSITION_DISMISS 0
#define DISPOSITION_CONTINUE_SEARCH 1
#define DISPOSITION_COLLIDED_UNWIND 3
#define EXCEPTION_EXIT_UNWIND 4
#define EXCEPTION_UNWINDING 2
/* See seh_prolog.s */
SEH_FRAME_NewEsp = 0 /* 0x00 */
SEH_FRAME_unused = 4 /* 0x04 */
SEH_FRAME_PreviousRecord = 8 /* 0x08 */
SEH_FRAME_Handler = 12 /* 0x0c */
SEH_FRAME_SEHTable = 16 /* 0x10 */
SEH_FRAME_Disable = 20 /* 0x14 */
SEH_FRAME_OriginalEbp = 24 /* 0x18 */
SEH_FRAME_Size = 28 /* 0x1c */
EXTERN _RtlUnwind@16:PROC
/* GLOBALS *******************************************************************/
PUBLIC __global_unwind2
PUBLIC __local_unwind2
PUBLIC __abnormal_termination
PUBLIC __except_handler2
PUBLIC __except_handler3
/* FUNCTIONS *****************************************************************/
.code
_unwind_handler:
/* Check if we were unwinding and continue search if not */
mov ecx, [esp+4]
test dword ptr [ecx+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
mov eax, DISPOSITION_CONTINUE_SEARCH
jz unwind_handler_return
/* We have a collision, do a local unwind */
mov eax, [esp+20]
push ebp
mov ebp, [eax+16]
mov edx, [eax+40]
push edx
mov edx, [eax+36]
push edx
call __local_unwind2
add esp, 8
pop ebp
/* Set new try level */
mov eax, [esp+8]
mov edx, [esp+16]
mov [edx], eax
/* Return collided unwind */
mov eax, DISPOSITION_COLLIDED_UNWIND
unwind_handler_return:
ret
__global_unwind2:
/* Create stack and save all registers */
push ebp
mov ebp, esp
push ebx
push esi
push edi
push ebp
/* Call unwind */
push 0
push 0
push glu_return
push [ebp+8]
call _RtlUnwind@16
glu_return:
/* Restore registers and return */
pop ebp
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
__abnormal_termination:
/* Assume false */
xor eax, eax
/* Check if the handler is the unwind handler */
mov ecx, fs:0
cmp dword ptr [ecx+4], offset _unwind_handler
jne short ab_return
/* Get the try level */
mov edx, [ecx+12]
mov edx, [edx+12]
/* Compare it */
cmp [ecx+8], edx
jne ab_return
/* Return true */
mov eax, 1
/* Return */
ab_return:
ret
__local_unwind2:
/* Save volatiles */
push ebx
push esi
push edi
/* Get the exception registration */
mov eax, [esp+16]
/* Setup SEH to protect the unwind */
push ebp
push eax
push -2
push offset _unwind_handler
push fs:0
mov fs:0, esp
unwind_loop:
/* Get the exception registration and try level */
mov eax, [esp+36]
mov ebx, [eax+8]
mov esi, [eax+12]
/* Validate the unwind */
cmp esi, -1
je unwind_return
cmp dword ptr [esp+40], -1
je unwind_ok
cmp esi, [esp+40]
jbe unwind_return
unwind_ok:
/* Get the new enclosing level and save it */
lea esi, [esi+esi*2]
mov ecx, [ebx+esi*4]
mov [esp+8], ecx
mov [eax+12], ecx
/* Check the filter type */
cmp dword ptr [ebx+esi*4+4], 0
jnz __NLG_Return2
/* FIXME: NLG Notification */
/* Call the handler */
call dword ptr [ebx+esi*4+8]
__NLG_Return2:
/* Unwind again */
jmp unwind_loop
unwind_return:
/* Cleanup SEH */
pop fs:0
add esp, 16
pop edi
pop esi
pop ebx
ret
__except_handler2:
/* Setup stack and save volatiles */
push ebp
mov ebp, esp
sub esp, 8
push ebx
push esi
push edi
push ebp
/* Clear direction flag */
cld
/* Get exception registration and record */
mov ebx, [ebp+12]
mov eax, [ebp+8]
/* Check if this is an unwind */
test dword ptr [eax+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
jnz except_unwind2
/* Save exception pointers structure */
mov [ebp-8], eax
mov eax, [ebp+16]
mov [ebp-4], eax
lea eax, [ebp-8]
mov [ebx+20], eax
/* Get the try level and scope table */
mov esi, [ebx+12]
mov edi, [ebx+8]
except_loop2:
/* Validate try level */
cmp esi, -1
je except_search2
/* Check if this is the termination handler */
lea ecx, [esi+esi*2]
cmp dword ptr [edi+ecx*4+4], 0
jz except_continue2
/* Save registers and call filter, then restore them */
push esi
push ebp
mov ebp, [ebx+16]
call dword ptr [edi+ecx*4+4]
pop ebp
pop esi
/* Restore ebx and check the result */
mov ebx, [ebp+12]
or eax, eax
jz except_continue2
js except_dismiss2
/* So this is an accept, call the termination handlers */
mov edi, [ebx+8]
push ebx
call __global_unwind2
add esp, 4
/* Restore ebp */
mov ebp, [ebx+16]
/* Do local unwind */
push esi
push ebx
call __local_unwind2
add esp, 8
/* Set new try level */
lea ecx, [esi+esi*2]
mov eax, [edi+ecx*4]
mov [ebx+12], eax
/* Call except handler */
call dword ptr [edi+ecx*4+8]
except_continue2:
/* Reload try level and except again */
mov edi, [ebx+8]
lea ecx, [esi+esi*2]
mov esi, [edi+ecx*4]
jmp except_loop2
except_dismiss2:
/* Dismiss it */
mov eax, DISPOSITION_DISMISS
jmp except_return2
except_search2:
/* Continue searching */
mov eax, DISPOSITION_CONTINUE_SEARCH
jmp except_return2
/* Do local unwind */
except_unwind2:
push ebp
mov ebp, [ebx+16]
push -1
push ebx
call __local_unwind2
add esp, 8
/* Retore EBP and set return disposition */
pop ebp
mov eax, DISPOSITION_CONTINUE_SEARCH
except_return2:
/* Restore registers and stack */
pop ebp
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
__except_handler3:
PARAM_ExceptionRecord = 8
PARAM_RegistrationFrame = 12
PARAM_Context = 16
/* Setup stack and save volatiles */
push ebp
mov ebp, esp
sub esp, 8
push ebx
push esi
push edi
push ebp
/* Clear direction flag */
cld
/* Get exception registration and record */
mov ebx, [ebp+PARAM_RegistrationFrame]
mov eax, [ebp+PARAM_ExceptionRecord]
/* Check if this is an unwind */
test dword ptr [eax+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
jnz except_unwind3
/* Save exception pointers structure */
mov [ebp-8+EXCEPTION_POINTERS_EXCEPTION_RECORD], eax
mov eax, [ebp+PARAM_Context]
mov [ebp-8+EXCEPTION_POINTERS_CONTEXT_RECORD], eax
lea eax, [ebp-8]
mov [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_unused], eax
/* Get the try level and scope table */
mov esi, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_Disable]
mov edi, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_SEHTable]
/* FIXME: Validate the SEH exception */
except_loop3:
/* Validate try level */
cmp esi, -1
je except_search3
/* Check if this is the termination handler */
lea ecx, [esi+esi*2]
mov eax, [edi+ecx*4+4]
test eax, eax
jz except_continue3
/* Save registers clear them all */
push esi
push ebp
lea ebp, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_OriginalEbp]
xor ebx, ebx
xor ecx, ecx
xor edx, edx
xor esi, esi
xor edi, edi
/* Call the filter and restore our registers */
call eax
pop ebp
pop esi
/* Restore ebx and check the result */
mov ebx, [ebp+PARAM_RegistrationFrame]
test eax, eax
jz except_continue3
js except_dismiss3
/* So this is an accept, call the termination handlers */
mov edi, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_SEHTable]
push ebx
call __global_unwind2
add esp, 4
/* Restore ebp */
lea ebp, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_OriginalEbp]
/* Do local unwind */
push esi
push ebx
call __local_unwind2
add esp, 8
/* FIXME: Do NLG Notification */
/* Set new try level */
lea ecx, [esi+esi*2]
mov eax, [edi+ecx*4]
mov [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_Disable], eax
/* Clear registers and call except handler */
mov eax, [edi+ecx*4+8]
xor ebx, ebx
xor ecx, ecx
xor edx, edx
xor esi, esi
xor edi, edi
call eax
except_continue3:
/* Reload try level and except again */
mov edi, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_SEHTable]
lea ecx, [esi+esi*2]
mov esi, [edi+ecx*4]
jmp except_loop3
except_dismiss3:
/* Dismiss it */
mov eax, DISPOSITION_DISMISS
jmp except_return3
/* Do local unwind */
except_unwind3:
push ebp
lea ebp, [ebx-SEH_FRAME_PreviousRecord+SEH_FRAME_OriginalEbp]
push -1
push ebx
call __local_unwind2
add esp, 8
/* Restore EBP */
pop ebp
except_search3:
/* Continue searching */
mov eax, DISPOSITION_CONTINUE_SEARCH
except_return3:
/* Restore registers and stack */
pop ebp
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
END