1c2c66affSColin Finck/* 2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory 3c2c66affSColin Finck * PROJECT: ReactOS Runtime Library (RTL) 4c2c66affSColin Finck * FILE: lib/rtl/i386/except_asm.s 5c2c66affSColin Finck * PURPOSE: User-mode exception support for IA-32 6c2c66affSColin Finck * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 7c2c66affSColin Finck * Stefan Ginsberg (stefan.ginsberg@reactos.org) 8c2c66affSColin Finck */ 9c2c66affSColin Finck 10c2c66affSColin Finck/* INCLUDES ******************************************************************/ 11c2c66affSColin Finck 12c2c66affSColin Finck#include <asm.inc> 13c2c66affSColin Finck#include <ks386.inc> 14c2c66affSColin Finck 15c2c66affSColin FinckEXTERN _RtlpCheckForActiveDebugger@0:PROC 16c2c66affSColin FinckEXTERN _RtlDispatchException@8:PROC 17c2c66affSColin FinckEXTERN _ZwContinue@8:PROC 18c2c66affSColin FinckEXTERN _ZwRaiseException@12:PROC 19c2c66affSColin Finck 20c2c66affSColin Finck#define ExceptionContinueSearch 1 21c2c66affSColin Finck#define ExceptionNestedException 2 22c2c66affSColin Finck#define ExceptionCollidedUnwind 3 23c2c66affSColin Finck 24c2c66affSColin Finck/* FUNCTIONS *****************************************************************/ 25c2c66affSColin Finck 26c2c66affSColin Finck.code 27c2c66affSColin Finck 28c2c66affSColin FinckPUBLIC _RtlpGetExceptionList@0 29c2c66affSColin Finck_RtlpGetExceptionList@0: 30c2c66affSColin Finck 31c2c66affSColin Finck /* Return the exception list */ 32c2c66affSColin Finck mov eax, fs:[TEB_EXCEPTION_LIST] 33c2c66affSColin Finck ret 34c2c66affSColin Finck 35c2c66affSColin Finck 36c2c66affSColin FinckPUBLIC _RtlpSetExceptionList@4 37c2c66affSColin Finck_RtlpSetExceptionList@4: 38c2c66affSColin Finck 39c2c66affSColin Finck /* Get the new list */ 40c2c66affSColin Finck mov ecx, [esp+4] 41c2c66affSColin Finck mov ecx, [ecx] 42c2c66affSColin Finck 43c2c66affSColin Finck /* Write it */ 44c2c66affSColin Finck mov fs:[TEB_EXCEPTION_LIST], ecx 45c2c66affSColin Finck 46c2c66affSColin Finck /* Return */ 47c2c66affSColin Finck ret 4 48c2c66affSColin Finck 49c2c66affSColin Finck 50c2c66affSColin FinckPUBLIC _RtlCaptureContext@4 51c2c66affSColin Finck_RtlCaptureContext@4: 52c2c66affSColin Finck 53c2c66affSColin Finck /* Preserve EBX and put the context in it */ 54c2c66affSColin Finck push ebx 55c2c66affSColin Finck mov ebx, [esp+8] 56c2c66affSColin Finck 57c2c66affSColin Finck /* Save the basic register context */ 58c2c66affSColin Finck mov [ebx+CONTEXT_EAX], eax 59c2c66affSColin Finck mov [ebx+CONTEXT_ECX], ecx 60c2c66affSColin Finck mov [ebx+CONTEXT_EDX], edx 61c2c66affSColin Finck mov eax, [esp] 62c2c66affSColin Finck mov [ebx+CONTEXT_EBX], eax 63c2c66affSColin Finck mov [ebx+CONTEXT_ESI], esi 64c2c66affSColin Finck mov [ebx+CONTEXT_EDI], edi 65c2c66affSColin Finck 66c2c66affSColin Finck /* Capture the other regs */ 67c2c66affSColin Finck jmp CaptureRest 68c2c66affSColin Finck 69c2c66affSColin Finck 70c2c66affSColin FinckPUBLIC _RtlpCaptureContext@4 71c2c66affSColin Finck_RtlpCaptureContext@4: 72c2c66affSColin Finck 73c2c66affSColin Finck /* Preserve EBX and put the context in it */ 74c2c66affSColin Finck push ebx 75c2c66affSColin Finck mov ebx, [esp+8] 76c2c66affSColin Finck 77c2c66affSColin Finck /* Clear the basic register context */ 78c2c66affSColin Finck mov dword ptr [ebx+CONTEXT_EAX], 0 79c2c66affSColin Finck mov dword ptr [ebx+CONTEXT_ECX], 0 80c2c66affSColin Finck mov dword ptr [ebx+CONTEXT_EDX], 0 81c2c66affSColin Finck mov dword ptr [ebx+CONTEXT_EBX], 0 82c2c66affSColin Finck mov dword ptr [ebx+CONTEXT_ESI], 0 83c2c66affSColin Finck mov dword ptr [ebx+CONTEXT_EDI], 0 84c2c66affSColin Finck 85c2c66affSColin FinckCaptureRest: 86c2c66affSColin Finck /* Capture the segment registers */ 87c2c66affSColin Finck mov [ebx+CONTEXT_SEGCS], cs 88c2c66affSColin Finck mov [ebx+CONTEXT_SEGDS], ds 89c2c66affSColin Finck mov [ebx+CONTEXT_SEGES], es 90c2c66affSColin Finck mov [ebx+CONTEXT_SEGFS], fs 91c2c66affSColin Finck mov [ebx+CONTEXT_SEGGS], gs 92c2c66affSColin Finck mov [ebx+CONTEXT_SEGSS], ss 93c2c66affSColin Finck 94c2c66affSColin Finck /* Capture flags */ 95c2c66affSColin Finck pushfd 96c2c66affSColin Finck pop [ebx+CONTEXT_EFLAGS] 97c2c66affSColin Finck 98c2c66affSColin Finck /* The return address should be in [ebp+4] */ 99c2c66affSColin Finck mov eax, [ebp+4] 100c2c66affSColin Finck mov [ebx+CONTEXT_EIP], eax 101c2c66affSColin Finck 102c2c66affSColin Finck /* Get EBP */ 103c2c66affSColin Finck mov eax, [ebp+0] 104c2c66affSColin Finck mov [ebx+CONTEXT_EBP], eax 105c2c66affSColin Finck 106c2c66affSColin Finck /* And get ESP */ 107c2c66affSColin Finck lea eax, [ebp+8] 108c2c66affSColin Finck mov [ebx+CONTEXT_ESP], eax 109c2c66affSColin Finck 110c2c66affSColin Finck /* Return to the caller */ 111c2c66affSColin Finck pop ebx 112c2c66affSColin Finck ret 4 113c2c66affSColin Finck 114c2c66affSColin Finck 115c2c66affSColin FinckPUBLIC _RtlpExecuteHandlerForException@20 116c2c66affSColin Finck_RtlpExecuteHandlerForException@20: 117c2c66affSColin Finck 118c2c66affSColin Finck /* Copy the routine in EDX */ 119c2c66affSColin Finck mov edx, offset _RtlpExceptionProtector 120c2c66affSColin Finck 121c2c66affSColin Finck /* Jump to common routine */ 122c2c66affSColin Finck jmp _RtlpExecuteHandler@20 123c2c66affSColin Finck 124c2c66affSColin Finck 125c2c66affSColin FinckPUBLIC _RtlpExecuteHandlerForUnwind@20 126c2c66affSColin Finck_RtlpExecuteHandlerForUnwind@20: 127c2c66affSColin Finck /* Copy the routine in EDX */ 128c2c66affSColin Finck mov edx, offset _RtlpUnwindProtector 129c2c66affSColin Finck 130c2c66affSColin Finck 131*4dedc8ffSThomas Faber.PROC _RtlpExecuteHandler@20 132*4dedc8ffSThomas Faber FPO 0, 0, 0, 0, 0, FRAME_FPO 133c2c66affSColin Finck 134c2c66affSColin Finck /* Save non-volatile */ 135c2c66affSColin Finck push ebx 136c2c66affSColin Finck push esi 137c2c66affSColin Finck push edi 138c2c66affSColin Finck 139c2c66affSColin Finck /* Clear registers */ 140c2c66affSColin Finck xor eax, eax 141c2c66affSColin Finck xor ebx, ebx 142c2c66affSColin Finck xor esi, esi 143c2c66affSColin Finck xor edi, edi 144c2c66affSColin Finck 145c2c66affSColin Finck /* Call the 2nd-stage executer */ 146c2c66affSColin Finck push [esp+32] 147c2c66affSColin Finck push [esp+32] 148c2c66affSColin Finck push [esp+32] 149c2c66affSColin Finck push [esp+32] 150c2c66affSColin Finck push [esp+32] 151c2c66affSColin Finck call _RtlpExecuteHandler2@20 152c2c66affSColin Finck 153c2c66affSColin Finck /* Restore non-volatile */ 154c2c66affSColin Finck pop edi 155c2c66affSColin Finck pop esi 156c2c66affSColin Finck pop ebx 157c2c66affSColin Finck ret 20 158c2c66affSColin Finck 159*4dedc8ffSThomas Faber.ENDP 160c2c66affSColin Finck 161c2c66affSColin FinckPUBLIC _RtlpExecuteHandler2@20 162c2c66affSColin Finck_RtlpExecuteHandler2@20: 163c2c66affSColin Finck 164c2c66affSColin Finck /* Set up stack frame */ 165c2c66affSColin Finck push ebp 166c2c66affSColin Finck mov ebp, esp 167c2c66affSColin Finck 168c2c66affSColin Finck /* Save the Frame */ 169c2c66affSColin Finck push [ebp+12] 170c2c66affSColin Finck 171c2c66affSColin Finck /* Push handler address */ 172c2c66affSColin Finck push edx 173c2c66affSColin Finck 174c2c66affSColin Finck /* Push the exception list */ 175c2c66affSColin Finck push [fs:TEB_EXCEPTION_LIST] 176c2c66affSColin Finck 177c2c66affSColin Finck /* Link us to it */ 178c2c66affSColin Finck mov [fs:TEB_EXCEPTION_LIST], esp 179c2c66affSColin Finck 180c2c66affSColin Finck /* Call the handler */ 181c2c66affSColin Finck push [ebp+20] 182c2c66affSColin Finck push [ebp+16] 183c2c66affSColin Finck push [ebp+12] 184c2c66affSColin Finck push [ebp+8] 185c2c66affSColin Finck mov ecx, [ebp+24] 186c2c66affSColin Finck call ecx 187c2c66affSColin Finck 188c2c66affSColin Finck /* Unlink us */ 189c2c66affSColin Finck mov esp, [fs:TEB_EXCEPTION_LIST] 190c2c66affSColin Finck 191c2c66affSColin Finck /* Restore it */ 192c2c66affSColin Finck pop [fs:TEB_EXCEPTION_LIST] 193c2c66affSColin Finck 194c2c66affSColin Finck /* Undo stack frame and return */ 195c2c66affSColin Finck mov esp, ebp 196c2c66affSColin Finck pop ebp 197c2c66affSColin Finck ret 20 198c2c66affSColin Finck 199c2c66affSColin Finck 200c2c66affSColin Finck_RtlpExceptionProtector: 201c2c66affSColin Finck 202c2c66affSColin Finck /* Assume we'll continue */ 203c2c66affSColin Finck mov eax, ExceptionContinueSearch 204c2c66affSColin Finck 205c2c66affSColin Finck /* Put the exception record in ECX and check the Flags */ 206c2c66affSColin Finck mov ecx, [esp+4] 207c2c66affSColin Finck test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND 208c2c66affSColin Finck jnz return 209c2c66affSColin Finck 210c2c66affSColin Finck /* Save the frame in ECX and Context in EDX */ 211c2c66affSColin Finck mov ecx, [esp+8] 212c2c66affSColin Finck mov edx, [esp+16] 213c2c66affSColin Finck 214c2c66affSColin Finck /* Get the nested frame */ 215c2c66affSColin Finck mov eax, [ecx+8] 216c2c66affSColin Finck 217c2c66affSColin Finck /* Set it as the dispatcher context */ 218c2c66affSColin Finck mov [edx], eax 219c2c66affSColin Finck 220c2c66affSColin Finck /* Return nested exception */ 221c2c66affSColin Finck mov eax, ExceptionNestedException 222c2c66affSColin Finck 223c2c66affSColin Finckreturn: 224c2c66affSColin Finck ret 16 225c2c66affSColin Finck 226c2c66affSColin Finck 227c2c66affSColin Finck_RtlpUnwindProtector: 228c2c66affSColin Finck 229c2c66affSColin Finck /* Assume we'll continue */ 230c2c66affSColin Finck mov eax, ExceptionContinueSearch 231c2c66affSColin Finck 232c2c66affSColin Finck /* Put the exception record in ECX and check the Flags */ 233c2c66affSColin Finck mov ecx, [esp+4] 234c2c66affSColin Finck test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND 235c2c66affSColin Finck jz .return 236c2c66affSColin Finck 237c2c66affSColin Finck /* Save the frame in ECX and Context in EDX */ 238c2c66affSColin Finck mov ecx, [esp+8] 239c2c66affSColin Finck mov edx, [esp+16] 240c2c66affSColin Finck 241c2c66affSColin Finck /* Get the nested frame */ 242c2c66affSColin Finck mov eax, [ecx+8] 243c2c66affSColin Finck 244c2c66affSColin Finck /* Set it as the dispatcher context */ 245c2c66affSColin Finck mov [edx], eax 246c2c66affSColin Finck 247c2c66affSColin Finck /* Return collided unwind */ 248c2c66affSColin Finck mov eax, ExceptionCollidedUnwind 249c2c66affSColin Finck 250c2c66affSColin Finck.return: 251c2c66affSColin Finck ret 16 252c2c66affSColin Finck 253c2c66affSColin Finck 254c2c66affSColin FinckPUBLIC _RtlRaiseException@4 255c2c66affSColin Finck_RtlRaiseException@4: 256c2c66affSColin Finck 257c2c66affSColin Finck /* Set up stack frame */ 258c2c66affSColin Finck push ebp 259c2c66affSColin Finck mov ebp, esp 260c2c66affSColin Finck 261c2c66affSColin Finck /* 262c2c66affSColin Finck * Save the context while preserving everything but ESP and EBP. 263c2c66affSColin Finck * This is vital because the caller will be restored with this context 264c2c66affSColin Finck * in case the execution is continued, which means we must not clobber 265c2c66affSColin Finck * the non-volatiles. We preserve the volatiles too because the context 266c2c66affSColin Finck * could get passed to a debugger. 267c2c66affSColin Finck */ 268c2c66affSColin Finck lea esp, [esp-CONTEXT_FRAME_LENGTH] 269c2c66affSColin Finck push esp 270c2c66affSColin Finck call _RtlCaptureContext@4 271c2c66affSColin Finck 272c2c66affSColin Finck /* Adjust ESP to account for the argument that was passed */ 273c2c66affSColin Finck add dword ptr [esp+CONTEXT_ESP], 4 274c2c66affSColin Finck 275c2c66affSColin Finck /* Save the exception address */ 276c2c66affSColin Finck mov edx, [ebp+4] 277c2c66affSColin Finck mov eax, [ebp+8] 278c2c66affSColin Finck mov [eax+EXCEPTION_RECORD_EXCEPTION_ADDRESS], edx 279c2c66affSColin Finck 280c2c66affSColin Finck /* Write the context flag */ 281c2c66affSColin Finck mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL 282c2c66affSColin Finck 283c2c66affSColin Finck /* Check if user mode debugger is active */ 284c2c66affSColin Finck call _RtlpCheckForActiveDebugger@0 285c2c66affSColin Finck test al, al 286c2c66affSColin Finck jnz DebuggerActive1 287c2c66affSColin Finck 288c2c66affSColin Finck /* Dispatch the exception */ 289c2c66affSColin Finck push esp 290c2c66affSColin Finck push [ebp+8] 291c2c66affSColin Finck call _RtlDispatchException@8 292c2c66affSColin Finck test al, al 293c2c66affSColin Finck jz RaiseException 294c2c66affSColin Finck 295c2c66affSColin Finck /* Continue, go back to previous context */ 296c2c66affSColin Finck mov ecx, esp 297c2c66affSColin Finck push 0 298c2c66affSColin Finck push ecx 299c2c66affSColin Finck call _ZwContinue@8 300c2c66affSColin Finck jmp RaiseStatus1 301c2c66affSColin Finck 302c2c66affSColin FinckDebuggerActive1: 303c2c66affSColin Finck 304c2c66affSColin Finck /* Raise an exception immediately */ 305c2c66affSColin Finck mov ecx, esp 306c2c66affSColin Finck push 1 307c2c66affSColin Finck push ecx 308c2c66affSColin Finck push [ebp+8] 309c2c66affSColin Finck call _ZwRaiseException@12 310c2c66affSColin Finck jmp RaiseStatus1 311c2c66affSColin Finck 312c2c66affSColin FinckRaiseException: 313c2c66affSColin Finck 314c2c66affSColin Finck /* Raise the exception */ 315c2c66affSColin Finck mov ecx, esp 316c2c66affSColin Finck push 0 317c2c66affSColin Finck push ecx 318c2c66affSColin Finck push [ebp+8] 319c2c66affSColin Finck call _ZwRaiseException@12 320c2c66affSColin Finck 321c2c66affSColin FinckRaiseStatus1: 322c2c66affSColin Finck 323c2c66affSColin Finck /* If we returned, raise a status */ 324c2c66affSColin Finck push eax 325c2c66affSColin Finck call _RtlRaiseStatus@4 326c2c66affSColin Finck 327c2c66affSColin Finck 328c2c66affSColin FinckPUBLIC _RtlRaiseStatus@4 329c2c66affSColin Finck_RtlRaiseStatus@4: 330c2c66affSColin Finck 331c2c66affSColin Finck /* Set up stack frame */ 332c2c66affSColin Finck push ebp 333c2c66affSColin Finck mov ebp, esp 334c2c66affSColin Finck 335c2c66affSColin Finck /* 336c2c66affSColin Finck * Save the context while preserving everything but ESP and EBP. 337c2c66affSColin Finck * This is vital because the caller will be restored with this context 338c2c66affSColin Finck * in case the execution is continued, which means we must not clobber 339c2c66affSColin Finck * the non-volatiles. We preserve the volatiles too because the context 340c2c66affSColin Finck * could get passed to a debugger. 341c2c66affSColin Finck */ 342c2c66affSColin Finck lea esp, [esp-CONTEXT_FRAME_LENGTH-EXCEPTION_RECORD_LENGTH] 343c2c66affSColin Finck push esp 344c2c66affSColin Finck call _RtlCaptureContext@4 345c2c66affSColin Finck 346c2c66affSColin Finck /* Adjust ESP to account for the argument that was passed */ 347c2c66affSColin Finck add dword ptr [esp+CONTEXT_ESP], 4 348c2c66affSColin Finck 349c2c66affSColin Finck /* Set up the exception record */ 350c2c66affSColin Finck lea ecx, [esp+CONTEXT_FRAME_LENGTH] 351c2c66affSColin Finck mov eax, [ebp+8] 352c2c66affSColin Finck mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_CODE], eax 353c2c66affSColin Finck mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_NONCONTINUABLE 354c2c66affSColin Finck and dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_RECORD], 0 355c2c66affSColin Finck mov eax, [ebp+4] 356c2c66affSColin Finck mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_ADDRESS], eax 357c2c66affSColin Finck and dword ptr [ecx+EXCEPTION_RECORD_NUMBER_PARAMETERS], 0 358c2c66affSColin Finck 359c2c66affSColin Finck /* Write the context flag */ 360c2c66affSColin Finck mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL 361c2c66affSColin Finck 362c2c66affSColin Finck /* Check if user mode debugger is active */ 363c2c66affSColin Finck call _RtlpCheckForActiveDebugger@0 364c2c66affSColin Finck 365c2c66affSColin Finck /* Restore ECX and jump if debugger is active */ 366c2c66affSColin Finck lea ecx, [esp+CONTEXT_FRAME_LENGTH] 367c2c66affSColin Finck test al, al 368c2c66affSColin Finck jnz DebuggerActive2 369c2c66affSColin Finck 370c2c66affSColin Finck /* Dispatch the exception */ 371c2c66affSColin Finck push esp 372c2c66affSColin Finck push ecx 373c2c66affSColin Finck call _RtlDispatchException@8 374c2c66affSColin Finck 375c2c66affSColin Finck /* Raise exception if we got here */ 376c2c66affSColin Finck lea ecx, [esp+CONTEXT_FRAME_LENGTH] 377c2c66affSColin Finck mov edx, esp 378c2c66affSColin Finck push 0 379c2c66affSColin Finck push edx 380c2c66affSColin Finck push ecx 381c2c66affSColin Finck call _ZwRaiseException@12 382c2c66affSColin Finck jmp RaiseStatus2 383c2c66affSColin Finck 384c2c66affSColin FinckDebuggerActive2: 385c2c66affSColin Finck 386c2c66affSColin Finck /* Raise an exception immediately */ 387c2c66affSColin Finck mov edx, esp 388c2c66affSColin Finck push 1 389c2c66affSColin Finck push edx 390c2c66affSColin Finck push ecx 391c2c66affSColin Finck call _ZwRaiseException@12 392c2c66affSColin Finck 393c2c66affSColin FinckRaiseStatus2: 394c2c66affSColin Finck 395c2c66affSColin Finck /* If we returned, raise a status */ 396c2c66affSColin Finck push eax 397c2c66affSColin Finck call _RtlRaiseStatus@4 398c2c66affSColin Finck 399c2c66affSColin FinckEND 400