reactos/sdk/lib/rtl/i386/except_asm.s

400 lines
8.7 KiB
ArmAsm

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Runtime Library (RTL)
* FILE: lib/rtl/i386/except_asm.s
* PURPOSE: User-mode exception support for IA-32
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* Stefan Ginsberg (stefan.ginsberg@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ks386.inc>
EXTERN _RtlpCheckForActiveDebugger@0:PROC
EXTERN _RtlDispatchException@8:PROC
EXTERN _ZwContinue@8:PROC
EXTERN _ZwRaiseException@12:PROC
#define ExceptionContinueSearch 1
#define ExceptionNestedException 2
#define ExceptionCollidedUnwind 3
/* FUNCTIONS *****************************************************************/
.code
PUBLIC _RtlpGetExceptionList@0
_RtlpGetExceptionList@0:
/* Return the exception list */
mov eax, fs:[TEB_EXCEPTION_LIST]
ret
PUBLIC _RtlpSetExceptionList@4
_RtlpSetExceptionList@4:
/* Get the new list */
mov ecx, [esp+4]
mov ecx, [ecx]
/* Write it */
mov fs:[TEB_EXCEPTION_LIST], ecx
/* Return */
ret 4
PUBLIC _RtlCaptureContext@4
_RtlCaptureContext@4:
/* Preserve EBX and put the context in it */
push ebx
mov ebx, [esp+8]
/* Save the basic register context */
mov [ebx+CONTEXT_EAX], eax
mov [ebx+CONTEXT_ECX], ecx
mov [ebx+CONTEXT_EDX], edx
mov eax, [esp]
mov [ebx+CONTEXT_EBX], eax
mov [ebx+CONTEXT_ESI], esi
mov [ebx+CONTEXT_EDI], edi
/* Capture the other regs */
jmp CaptureRest
PUBLIC _RtlpCaptureContext@4
_RtlpCaptureContext@4:
/* Preserve EBX and put the context in it */
push ebx
mov ebx, [esp+8]
/* Clear the basic register context */
mov dword ptr [ebx+CONTEXT_EAX], 0
mov dword ptr [ebx+CONTEXT_ECX], 0
mov dword ptr [ebx+CONTEXT_EDX], 0
mov dword ptr [ebx+CONTEXT_EBX], 0
mov dword ptr [ebx+CONTEXT_ESI], 0
mov dword ptr [ebx+CONTEXT_EDI], 0
CaptureRest:
/* Capture the segment registers */
mov [ebx+CONTEXT_SEGCS], cs
mov [ebx+CONTEXT_SEGDS], ds
mov [ebx+CONTEXT_SEGES], es
mov [ebx+CONTEXT_SEGFS], fs
mov [ebx+CONTEXT_SEGGS], gs
mov [ebx+CONTEXT_SEGSS], ss
/* Capture flags */
pushfd
pop [ebx+CONTEXT_EFLAGS]
/* The return address should be in [ebp+4] */
mov eax, [ebp+4]
mov [ebx+CONTEXT_EIP], eax
/* Get EBP */
mov eax, [ebp+0]
mov [ebx+CONTEXT_EBP], eax
/* And get ESP */
lea eax, [ebp+8]
mov [ebx+CONTEXT_ESP], eax
/* Return to the caller */
pop ebx
ret 4
PUBLIC _RtlpExecuteHandlerForException@20
_RtlpExecuteHandlerForException@20:
/* Copy the routine in EDX */
mov edx, offset _RtlpExceptionProtector
/* Jump to common routine */
jmp _RtlpExecuteHandler@20
PUBLIC _RtlpExecuteHandlerForUnwind@20
_RtlpExecuteHandlerForUnwind@20:
/* Copy the routine in EDX */
mov edx, offset _RtlpUnwindProtector
.PROC _RtlpExecuteHandler@20
FPO 0, 0, 0, 0, 0, FRAME_FPO
/* Save non-volatile */
push ebx
push esi
push edi
/* Clear registers */
xor eax, eax
xor ebx, ebx
xor esi, esi
xor edi, edi
/* Call the 2nd-stage executer */
push [esp+32]
push [esp+32]
push [esp+32]
push [esp+32]
push [esp+32]
call _RtlpExecuteHandler2@20
/* Restore non-volatile */
pop edi
pop esi
pop ebx
ret 20
.ENDP
PUBLIC _RtlpExecuteHandler2@20
_RtlpExecuteHandler2@20:
/* Set up stack frame */
push ebp
mov ebp, esp
/* Save the Frame */
push [ebp+12]
/* Push handler address */
push edx
/* Push the exception list */
push [fs:TEB_EXCEPTION_LIST]
/* Link us to it */
mov [fs:TEB_EXCEPTION_LIST], esp
/* Call the handler */
push [ebp+20]
push [ebp+16]
push [ebp+12]
push [ebp+8]
mov ecx, [ebp+24]
call ecx
/* Unlink us */
mov esp, [fs:TEB_EXCEPTION_LIST]
/* Restore it */
pop [fs:TEB_EXCEPTION_LIST]
/* Undo stack frame and return */
mov esp, ebp
pop ebp
ret 20
_RtlpExceptionProtector:
/* Assume we'll continue */
mov eax, ExceptionContinueSearch
/* Put the exception record in ECX and check the Flags */
mov ecx, [esp+4]
test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND
jnz return
/* Save the frame in ECX and Context in EDX */
mov ecx, [esp+8]
mov edx, [esp+16]
/* Get the nested frame */
mov eax, [ecx+8]
/* Set it as the dispatcher context */
mov [edx], eax
/* Return nested exception */
mov eax, ExceptionNestedException
return:
ret 16
_RtlpUnwindProtector:
/* Assume we'll continue */
mov eax, ExceptionContinueSearch
/* Put the exception record in ECX and check the Flags */
mov ecx, [esp+4]
test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND
jz .return
/* Save the frame in ECX and Context in EDX */
mov ecx, [esp+8]
mov edx, [esp+16]
/* Get the nested frame */
mov eax, [ecx+8]
/* Set it as the dispatcher context */
mov [edx], eax
/* Return collided unwind */
mov eax, ExceptionCollidedUnwind
.return:
ret 16
PUBLIC _RtlRaiseException@4
_RtlRaiseException@4:
/* Set up stack frame */
push ebp
mov ebp, esp
/*
* Save the context while preserving everything but ESP and EBP.
* This is vital because the caller will be restored with this context
* in case the execution is continued, which means we must not clobber
* the non-volatiles. We preserve the volatiles too because the context
* could get passed to a debugger.
*/
lea esp, [esp-CONTEXT_FRAME_LENGTH]
push esp
call _RtlCaptureContext@4
/* Adjust ESP to account for the argument that was passed */
add dword ptr [esp+CONTEXT_ESP], 4
/* Save the exception address */
mov edx, [ebp+4]
mov eax, [ebp+8]
mov [eax+EXCEPTION_RECORD_EXCEPTION_ADDRESS], edx
/* Write the context flag */
mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL
/* Check if user mode debugger is active */
call _RtlpCheckForActiveDebugger@0
test al, al
jnz DebuggerActive1
/* Dispatch the exception */
push esp
push [ebp+8]
call _RtlDispatchException@8
test al, al
jz RaiseException
/* Continue, go back to previous context */
mov ecx, esp
push 0
push ecx
call _ZwContinue@8
jmp RaiseStatus1
DebuggerActive1:
/* Raise an exception immediately */
mov ecx, esp
push 1
push ecx
push [ebp+8]
call _ZwRaiseException@12
jmp RaiseStatus1
RaiseException:
/* Raise the exception */
mov ecx, esp
push 0
push ecx
push [ebp+8]
call _ZwRaiseException@12
RaiseStatus1:
/* If we returned, raise a status */
push eax
call _RtlRaiseStatus@4
PUBLIC _RtlRaiseStatus@4
_RtlRaiseStatus@4:
/* Set up stack frame */
push ebp
mov ebp, esp
/*
* Save the context while preserving everything but ESP and EBP.
* This is vital because the caller will be restored with this context
* in case the execution is continued, which means we must not clobber
* the non-volatiles. We preserve the volatiles too because the context
* could get passed to a debugger.
*/
lea esp, [esp-CONTEXT_FRAME_LENGTH-EXCEPTION_RECORD_LENGTH]
push esp
call _RtlCaptureContext@4
/* Adjust ESP to account for the argument that was passed */
add dword ptr [esp+CONTEXT_ESP], 4
/* Set up the exception record */
lea ecx, [esp+CONTEXT_FRAME_LENGTH]
mov eax, [ebp+8]
mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_CODE], eax
mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_NONCONTINUABLE
and dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_RECORD], 0
mov eax, [ebp+4]
mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_ADDRESS], eax
and dword ptr [ecx+EXCEPTION_RECORD_NUMBER_PARAMETERS], 0
/* Write the context flag */
mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL
/* Check if user mode debugger is active */
call _RtlpCheckForActiveDebugger@0
/* Restore ECX and jump if debugger is active */
lea ecx, [esp+CONTEXT_FRAME_LENGTH]
test al, al
jnz DebuggerActive2
/* Dispatch the exception */
push esp
push ecx
call _RtlDispatchException@8
/* Raise exception if we got here */
lea ecx, [esp+CONTEXT_FRAME_LENGTH]
mov edx, esp
push 0
push edx
push ecx
call _ZwRaiseException@12
jmp RaiseStatus2
DebuggerActive2:
/* Raise an exception immediately */
mov edx, esp
push 1
push edx
push ecx
call _ZwRaiseException@12
RaiseStatus2:
/* If we returned, raise a status */
push eax
call _RtlRaiseStatus@4
END