/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS NT Library * FILE: lib/rtl/i386/except.S * PURPOSE: User-mode exception support for IA-32 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) * Casper S. Hornstrup (chorns@users.sourceforge.net) */ /* INCLUDES ******************************************************************/ #include .intel_syntax noprefix #define EXCEPTION_UNWINDING 2 #define EXCEPTION_EXIT_UNWIND 4 #define EXCEPTION_UNWIND (EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND) #define ExceptionContinueExecution 0 #define ExceptionContinueSearch 1 #define ExceptionNestedException 2 #define ExceptionCollidedUnwind 3 /* FUNCTIONS ****************************************************************/ .globl _RtlpGetExceptionList@0 _RtlpGetExceptionList@0: /* Return the exception list */ mov eax, [fs:TEB_EXCEPTION_LIST] ret .globl _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 .globl _RtlpGetExceptionAddress@0 _RtlpGetExceptionAddress@0: /* Return the address from the stack */ mov eax, [ebp+4] /* Return */ ret .globl _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] /* We pushed EBX, remember? ;) */ mov [ebx+CONTEXT_EBX], eax mov [ebx+CONTEXT_ESI], esi mov [ebx+CONTEXT_EDI], edi /* Capture the other regs */ jmp CaptureRest .globl _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 .globl _RtlpExecuteHandlerForException@20 _RtlpExecuteHandlerForException@20: /* Copy the routine in EDX */ mov edx, offset _RtlpExceptionProtector /* Jump to common routine */ jmp _RtlpExecuteHandler@20 .globl _RtlpExecuteHandlerForUnwind@20 _RtlpExecuteHandlerForUnwind@20: /* Copy the routine in EDX */ mov edx, offset _RtlpExceptionProtector /* Run the common routine */ _RtlpExecuteHandler@20: /* 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+0x20] push [esp+0x20] push [esp+0x20] push [esp+0x20] push [esp+0x20] call _RtlpExecuteHandler2@20 /* Restore non-volatile */ pop edi pop esi pop ebx ret 0x14 .globl _RtlpExecuteHandler2@20 _RtlpExecuteHandler2@20: /* Set up stack frame */ push ebp mov ebp, esp /* Save the Frame */ push [ebp+0xC] /* 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+0x14] push [ebp+0x10] push [ebp+0xC] push [ebp+8] mov ecx, [ebp+0x18] 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 0x14 _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_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_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 collided unwind */ mov eax, ExceptionCollidedUnwind .return: ret 16