From 5f308d3cb08b4d032f3fa0f026f9f65b63c39d88 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 12 Jan 2001 20:41:03 +0000 Subject: [PATCH] Added some exception handling functions. --- dlls/msvcrt/except.c | 149 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 122 insertions(+), 27 deletions(-) diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c index ec455f867cb..b2e6e3782d3 100644 --- a/dlls/msvcrt/except.c +++ b/dlls/msvcrt/except.c @@ -6,10 +6,10 @@ * See http://www.microsoft.com/msj/0197/exception/exception.htm, * but don't believe all of it. * - * FIXME: Incomplete, no support for nested exceptions or try block cleanup. + * FIXME: Incomplete support for nested exceptions/try block cleanup. */ -#include #include "ntddk.h" +#include "wine/exception.h" #include "thread.h" #include "msvcrt.h" @@ -21,28 +21,41 @@ typedef void (*MSVCRT_sig_handler_func)(void); typedef struct _SCOPETABLE { DWORD previousTryLevel; - int (__cdecl *lpfnFilter)(int, PEXCEPTION_POINTERS); - int (__cdecl *lpfnHandler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, - PCONTEXT, PEXCEPTION_FRAME *); + int (__cdecl *lpfnFilter)(PEXCEPTION_POINTERS); + int (__cdecl *lpfnHandler)(void); } SCOPETABLE, *PSCOPETABLE; -typedef struct _MSVCRT_EXCEPTION_REGISTRATION +typedef struct _MSVCRT_EXCEPTION_FRAME { - struct _EXCEPTION_REGISTRATION *prev; + EXCEPTION_FRAME *prev; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, PCONTEXT, PEXCEPTION_RECORD); PSCOPETABLE scopetable; - int trylevel; + DWORD trylevel; int _ebp; PEXCEPTION_POINTERS xpointers; -} MSVCRT_EXCEPTION_REGISTRATION; +} MSVCRT_EXCEPTION_FRAME; -typedef struct _EXCEPTION_REGISTRATION +#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 __cdecl MSVCRT_nested_handler(PEXCEPTION_RECORD rec, + struct __EXCEPTION_FRAME *frame, + PCONTEXT context WINE_UNUSED, + struct __EXCEPTION_FRAME **dispatch) { - struct _EXCEPTION_REGISTRATION *prev; - void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_FRAME, - PCONTEXT, PEXCEPTION_RECORD); -} EXCEPTION_REGISTRATION; + if (rec->ExceptionFlags & 0x6) + return ExceptionContinueSearch; + *dispatch = frame; + return ExceptionCollidedUnwind; +} +#endif + /********************************************************************* * _XcptFilter (MSVCRT.@) @@ -75,22 +88,42 @@ __ASM_GLOBAL_FUNC(MSVCRT__EH_prolog, */ void __cdecl MSVCRT__global_unwind2(PEXCEPTION_FRAME frame) { -#if defined(__GNUC__) && defined(__i386__) - TRACE("(%p)\n",frame); - if (0) -unwind_label: return; - RtlUnwind( frame, &&unwind_label, 0, 0 ); -#else - FIXME("(%p) stub\n",frame); -#endif + TRACE("(%p)\n",frame); + RtlUnwind( frame, 0, 0, 0 ); } /******************************************************************* * _local_unwind2 (MSVCRT.@) */ -void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_REGISTRATION *endframe, DWORD nr ) +void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_FRAME *frame, + DWORD trylevel) { - FIXME("(%p,%ld) stub\n",endframe,nr); + 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"); } /********************************************************************* @@ -98,7 +131,8 @@ void __cdecl MSVCRT__local_unwind2(MSVCRT_EXCEPTION_REGISTRATION *endframe, DWOR */ int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec, PEXCEPTION_FRAME frame, - PCONTEXT context, PEXCEPTION_FRAME *dispatcher) + PCONTEXT context, + PEXCEPTION_FRAME *dispatcher) { FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, @@ -110,12 +144,73 @@ int __cdecl MSVCRT__except_handler2(PEXCEPTION_RECORD rec, * _except_handler3 (MSVCRT.@) */ int __cdecl MSVCRT__except_handler3(PEXCEPTION_RECORD rec, - MSVCRT_EXCEPTION_REGISTRATION *frame, + MSVCRT_EXCEPTION_FRAME *frame, PCONTEXT context,void *dispatcher) { - FIXME("exception %lx flags=%lx at %p handler=%p %p %p stub\n", +#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 */ + MSVCRT__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 */ + MSVCRT__global_unwind2((PEXCEPTION_FRAME)frame); + MSVCRT__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; }