mirror of
https://github.com/reactos/reactos.git
synced 2024-08-30 23:28:58 +00:00
453 lines
9.2 KiB
ArmAsm
453 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
|