/* * msvcrt.dll exception handling * * Copyright 2000 Jon Griffiths * * See http://www.microsoft.com/msj/0197/exception/exception.htm, * but don't believe all of it. * * FIXME: Incomplete support for nested exceptions/try block cleanup. */ #include "ntddk.h" #include "wine/exception.h" #include "thread.h" #include "msvcrt.h" DEFAULT_DEBUG_CHANNEL(msvcrt); typedef void (*MSVCRT_sig_handler_func)(void); /* VC++ extensions to Win32 SEH */ typedef struct _SCOPETABLE { DWORD previousTryLevel; int (*lpfnFilter)(PEXCEPTION_POINTERS); int (*lpfnHandler)(void); } SCOPETABLE, *PSCOPETABLE; typedef struct _MSVCRT_EXCEPTION_FRAME { EXCEPTION_FRAME *prev; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, PCONTEXT, PEXCEPTION_RECORD); PSCOPETABLE scopetable; DWORD trylevel; int _ebp; PEXCEPTION_POINTERS xpointers; } MSVCRT_EXCEPTION_FRAME; #define TRYLEVEL_END 0xff /* End of trylevel list */ #if defined(__GNUC__) && defined(__i386__) #define CALL_FINALLY_BLOCK(code_block, base_ptr) \ __asm__ __volatile__ ("movl %0,%%eax; movl %1,%%ebp; call *%%eax" \ : : "g" (code_block), "g" (base_ptr)) static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec, struct __EXCEPTION_FRAME* frame, PCONTEXT context WINE_UNUSED, struct __EXCEPTION_FRAME** dispatch) { if (rec->ExceptionFlags & 0x6) return ExceptionContinueSearch; *dispatch = frame; return ExceptionCollidedUnwind; } #endif /********************************************************************* * _XcptFilter (MSVCRT.@) */ int _XcptFilter(int ex, PEXCEPTION_POINTERS ptr) { FIXME("(%d,%p)semi-stub\n", ex, ptr); return UnhandledExceptionFilter(ptr); } /********************************************************************* * _EH_prolog (MSVCRT.@) */ #ifdef __i386__ /* Provided for VC++ binary compatability only */ __ASM_GLOBAL_FUNC(_EH_prolog, "pushl $0xff\n\t" "pushl %eax\n\t" "pushl %fs:0\n\t" "movl %esp, %fs:0\n\t" "movl 12(%esp), %eax\n\t" "movl %ebp, 12(%esp)\n\t" "leal 12(%esp), %ebp\n\t" "pushl %eax\n\t" "ret"); #endif /******************************************************************* * _global_unwind2 (MSVCRT.@) */ void _global_unwind2(PEXCEPTION_FRAME frame) { TRACE("(%p)\n",frame); RtlUnwind( frame, 0, 0, 0 ); } /******************************************************************* * _local_unwind2 (MSVCRT.@) */ void _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, DWORD trylevel) { MSVCRT_EXCEPTION_FRAME *curframe = frame; DWORD curtrylevel = 0xfe; EXCEPTION_FRAME reg; TRACE("(%p,%ld,%ld)\n",frame, frame->trylevel, trylevel); /* Register a handler in case of a nested exception */ reg.Handler = (PEXCEPTION_HANDLER)MSVCRT_nested_handler; reg.Prev = NtCurrentTeb()->except; __wine_push_frame(®); while (frame->trylevel != TRYLEVEL_END && frame->trylevel != trylevel) { curtrylevel = frame->scopetable[frame->trylevel].previousTryLevel; curframe = frame; curframe->trylevel = curtrylevel; if (!frame->scopetable[curtrylevel].lpfnFilter) { ERR("__try block cleanup not implemented - expect crash!\n"); /* FIXME: Remove current frame, set ebp, call * frame->scopetable[curtrylevel].lpfnHandler() */ } } __wine_pop_frame(®); TRACE("unwound OK\n"); } /********************************************************************* * _except_handler2 (MSVCRT.@) */ int _except_handler2(PEXCEPTION_RECORD rec, PEXCEPTION_FRAME frame, PCONTEXT context, PEXCEPTION_FRAME* dispatcher) { FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, frame->Handler, context, dispatcher); return ExceptionContinueSearch; } /********************************************************************* * _except_handler3 (MSVCRT.@) */ int _except_handler3(PEXCEPTION_RECORD rec, MSVCRT_EXCEPTION_FRAME* frame, PCONTEXT context, void* dispatcher) { #if defined(__GNUC__) && defined(__i386__) long retval, trylevel; EXCEPTION_POINTERS exceptPtrs; PSCOPETABLE pScopeTable; TRACE("exception %lx flags=%lx at %p handler=%p %p %p semi-stub\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, frame->handler, context, dispatcher); __asm__ __volatile__ ("cld"); if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) { /* Unwinding the current frame */ _local_unwind2(frame, TRYLEVEL_END); return ExceptionContinueSearch; } else { /* Hunting for handler */ exceptPtrs.ExceptionRecord = rec; exceptPtrs.ContextRecord = context; *((DWORD *)frame-1) = (DWORD)&exceptPtrs; trylevel = frame->trylevel; pScopeTable = frame->scopetable; while (trylevel != TRYLEVEL_END) { if (pScopeTable[trylevel].lpfnFilter) { TRACE("filter = %p\n", pScopeTable[trylevel].lpfnFilter); retval = pScopeTable[trylevel].lpfnFilter(&exceptPtrs); TRACE("filter returned %s\n", retval == EXCEPTION_CONTINUE_EXECUTION ? "CONTINUE_EXECUTION" : retval == EXCEPTION_EXECUTE_HANDLER ? "EXECUTE_HANDLER" : "CONTINUE_SEARCH"); if (retval == EXCEPTION_CONTINUE_EXECUTION) return ExceptionContinueExecution; if (retval == EXCEPTION_EXECUTE_HANDLER) { /* Unwind all higher frames, this one will handle the exception */ _global_unwind2((PEXCEPTION_FRAME)frame); _local_unwind2(frame, trylevel); /* Set our trylevel to the enclosing block, and call the __finally * code, which won't return */ frame->trylevel = pScopeTable->previousTryLevel; TRACE("__finally block %p\n",pScopeTable[trylevel].lpfnHandler); CALL_FINALLY_BLOCK(pScopeTable[trylevel].lpfnHandler, frame->_ebp); ERR("Returned from __finally block - expect crash!\n"); } } trylevel = pScopeTable->previousTryLevel; } } #else TRACE("exception %lx flags=%lx at %p handler=%p %p %p stub\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, frame->handler, context, dispatcher); #endif return ExceptionContinueSearch; } /********************************************************************* * _abnormal_termination (MSVCRT.@) */ int _abnormal_termination(void) { FIXME("(void)stub\n"); return 0; } /******************************************************************* * _setjmp (MSVCRT.@) */ int MSVCRT__setjmp(LPDWORD* jmpbuf) { FIXME(":(%p): stub\n",jmpbuf); return 0; } /******************************************************************* * _setjmp3 (MSVCRT.@) */ int __cdecl MSVCRT__setjmp3(LPDWORD *jmpbuf, int x) { FIXME(":(%p %x): stub\n",jmpbuf,x); return 0; } /********************************************************************* * longjmp (MSVCRT.@) */ void MSVCRT_longjmp(jmp_buf env, int val) { FIXME("MSVCRT_longjmp semistub, expect crash\n"); longjmp(env, val); } /********************************************************************* * signal (MSVCRT.@) */ void* MSVCRT_signal(int sig, MSVCRT_sig_handler_func func) { FIXME("(%d %p):stub\n", sig, func); return (void*)-1; }