Module: wine Branch: master Commit: a1e99f544b40e54d90e4d102186ba526f1489ca5 URL: http://source.winehq.org/git/wine.git/?a=commit;h=a1e99f544b40e54d90e4d10218...
Author: Alexandre Julliard julliard@winehq.org Date: Wed Apr 14 14:30:46 2010 +0200
msvcrt: Implement support for version 4 exception tables.
---
dlls/msvcr80/msvcr80.spec | 4 +- dlls/msvcr90/msvcr90.spec | 4 +- dlls/msvcrt/except.c | 121 +++++++++++++++++++++++++++++++++++++++++++++ dlls/msvcrt/msvcrt.spec | 4 +- 4 files changed, 127 insertions(+), 6 deletions(-)
diff --git a/dlls/msvcr80/msvcr80.spec b/dlls/msvcr80/msvcr80.spec index 2154478..75c0f3a 100644 --- a/dlls/msvcr80/msvcr80.spec +++ b/dlls/msvcr80/msvcr80.spec @@ -379,7 +379,7 @@ @ cdecl _errno() msvcrt._errno @ cdecl -i386 _except_handler2(ptr ptr ptr ptr) msvcrt._except_handler2 @ cdecl -i386 _except_handler3(ptr ptr ptr ptr) msvcrt._except_handler3 -@ stub _except_handler4_common +@ cdecl -i386 _except_handler4_common(ptr ptr ptr ptr ptr ptr) msvcrt._except_handler4_common @ varargs _execl(str str) msvcrt._execl @ varargs _execle(str str) msvcrt._execle @ varargs _execlp(str str) msvcrt._execlp @@ -637,7 +637,7 @@ @ stub _lfind_s @ cdecl _loaddll(str) msvcrt._loaddll @ cdecl -i386 _local_unwind2(ptr long) msvcrt._local_unwind2 -@ stub _local_unwind4 +@ cdecl -i386 _local_unwind4(ptr ptr long) msvcrt._local_unwind4 @ cdecl _localtime32(ptr) msvcrt._localtime32 @ stub _localtime32_s @ cdecl _localtime64(ptr) msvcrt._localtime64 diff --git a/dlls/msvcr90/msvcr90.spec b/dlls/msvcr90/msvcr90.spec index 1b85a6e..ed5a4bf 100644 --- a/dlls/msvcr90/msvcr90.spec +++ b/dlls/msvcr90/msvcr90.spec @@ -371,7 +371,7 @@ @ cdecl _errno() msvcrt._errno @ cdecl -i386 _except_handler2(ptr ptr ptr ptr) msvcrt._except_handler2 @ cdecl -i386 _except_handler3(ptr ptr ptr ptr) msvcrt._except_handler3 -@ stub _except_handler4_common +@ cdecl -i386 _except_handler4_common(ptr ptr ptr ptr ptr ptr) msvcrt._except_handler4_common @ varargs _execl(str str) msvcrt._execl @ varargs _execle(str str) msvcrt._execle @ varargs _execlp(str str) msvcrt._execlp @@ -625,7 +625,7 @@ @ stub _lfind_s @ cdecl _loaddll(str) msvcrt._loaddll @ cdecl -i386 _local_unwind2(ptr long) msvcrt._local_unwind2 -@ stub _local_unwind4 +@ cdecl -i386 _local_unwind4(ptr ptr long) msvcrt._local_unwind4 @ cdecl _localtime32(ptr) msvcrt._localtime32 @ stub _localtime32_s @ cdecl _localtime64(ptr) msvcrt._localtime64 diff --git a/dlls/msvcrt/except.c b/dlls/msvcrt/except.c index fdb1757..494b5af 100644 --- a/dlls/msvcrt/except.c +++ b/dlls/msvcrt/except.c @@ -56,6 +56,15 @@ typedef struct _MSVCRT_EXCEPTION_FRAME PEXCEPTION_POINTERS xpointers; } MSVCRT_EXCEPTION_FRAME;
+typedef struct +{ + int gs_cookie_offset; + ULONG gs_cookie_xor; + int eh_cookie_offset; + ULONG eh_cookie_xor; + SCOPETABLE entries[1]; +} SCOPETABLE_V4; + #define TRYLEVEL_END (-1) /* End of trylevel list */
#if defined(__GNUC__) && defined(__i386__) @@ -99,6 +108,11 @@ static inline int call_unwind_func( int (*func)(void), void *ebp )
#ifdef __i386__
+static const SCOPETABLE_V4 *get_scopetable_v4( MSVCRT_EXCEPTION_FRAME *frame, ULONG_PTR cookie ) +{ + return (const SCOPETABLE_V4 *)((ULONG_PTR)frame->scopetable ^ cookie); +} + static DWORD MSVCRT_nested_handler(PEXCEPTION_RECORD rec, EXCEPTION_REGISTRATION_RECORD* frame, PCONTEXT context, @@ -158,6 +172,33 @@ static void msvcrt_local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel, vo TRACE("unwound OK\n"); }
+static void msvcrt_local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel, void *ebp ) +{ + EXCEPTION_REGISTRATION_RECORD reg; + const SCOPETABLE_V4 *scopetable = get_scopetable_v4( frame, *cookie ); + + TRACE("(%p,%d,%d)\n",frame, frame->trylevel, trylevel); + + /* Register a handler in case of a nested exception */ + reg.Handler = MSVCRT_nested_handler; + reg.Prev = NtCurrentTeb()->Tib.ExceptionList; + __wine_push_frame(®); + + while (frame->trylevel != -2 && frame->trylevel != trylevel) + { + int level = frame->trylevel; + frame->trylevel = scopetable->entries[level].previousTryLevel; + if (!scopetable->entries[level].lpfnFilter) + { + TRACE( "__try block cleanup level %d handler %p ebp %p\n", + level, scopetable->entries[level].lpfnHandler, ebp ); + call_unwind_func( scopetable->entries[level].lpfnHandler, ebp ); + } + } + __wine_pop_frame(®); + TRACE("unwound OK\n"); +} + /******************************************************************* * _local_unwind2 (MSVCRT.@) */ @@ -167,6 +208,14 @@ void CDECL _local_unwind2(MSVCRT_EXCEPTION_FRAME* frame, int trylevel) }
/******************************************************************* + * _local_unwind4 (MSVCRT.@) + */ +void CDECL _local_unwind4( ULONG *cookie, MSVCRT_EXCEPTION_FRAME* frame, int trylevel ) +{ + msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp ); +} + +/******************************************************************* * _global_unwind2 (MSVCRT.@) */ void CDECL _global_unwind2(EXCEPTION_REGISTRATION_RECORD* frame) @@ -259,6 +308,78 @@ int CDECL _except_handler3(PEXCEPTION_RECORD rec, return ExceptionContinueSearch; }
+/********************************************************************* + * _except_handler4_common (MSVCRT.@) + */ +int CDECL _except_handler4_common( ULONG *cookie, void (*check_cookie)(void), + EXCEPTION_RECORD *rec, MSVCRT_EXCEPTION_FRAME *frame, + CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher ) +{ + int retval, trylevel; + EXCEPTION_POINTERS exceptPtrs; + const SCOPETABLE_V4 *scope_table = get_scopetable_v4( frame, *cookie ); + + TRACE( "exception %x flags=%x at %p handler=%p %p %p cookie=%x scope table=%p cookies=%d/%x,%d/%x\n", + rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress, + frame->handler, context, dispatcher, *cookie, scope_table, + scope_table->gs_cookie_offset, scope_table->gs_cookie_xor, + scope_table->eh_cookie_offset, scope_table->eh_cookie_xor ); + + /* FIXME: no cookie validation yet */ + + if (rec->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) + { + /* Unwinding the current frame */ + msvcrt_local_unwind4( cookie, frame, -2, &frame->_ebp ); + TRACE("unwound current frame, returning ExceptionContinueSearch\n"); + return ExceptionContinueSearch; + } + else + { + /* Hunting for handler */ + exceptPtrs.ExceptionRecord = rec; + exceptPtrs.ContextRecord = context; + *((DWORD *)frame-1) = (DWORD)&exceptPtrs; + trylevel = frame->trylevel; + + while (trylevel != -2) + { + TRACE( "level %d prev %d filter %p\n", trylevel, + scope_table->entries[trylevel].previousTryLevel, + scope_table->entries[trylevel].lpfnFilter ); + if (scope_table->entries[trylevel].lpfnFilter) + { + retval = call_filter( scope_table->entries[trylevel].lpfnFilter, &exceptPtrs, &frame->_ebp ); + + 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((EXCEPTION_REGISTRATION_RECORD*)frame); + msvcrt_local_unwind4( cookie, frame, trylevel, &frame->_ebp ); + + /* Set our trylevel to the enclosing block, and call the __finally + * code, which won't return + */ + frame->trylevel = scope_table->entries[trylevel].previousTryLevel; + TRACE("__finally block %p\n",scope_table->entries[trylevel].lpfnHandler); + call_finally_block(scope_table->entries[trylevel].lpfnHandler, &frame->_ebp); + ERR("Returned from __finally block - expect crash!\n"); + } + } + trylevel = scope_table->entries[trylevel].previousTryLevel; + } + } + TRACE("reached -2, returning ExceptionContinueSearch\n"); + return ExceptionContinueSearch; +} +
/* * setjmp/longjmp implementation diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec index 8482863..9af243f 100644 --- a/dlls/msvcrt/msvcrt.spec +++ b/dlls/msvcrt/msvcrt.spec @@ -348,7 +348,7 @@ @ cdecl _errno() MSVCRT__errno @ cdecl -i386 _except_handler2(ptr ptr ptr ptr) @ cdecl -i386 _except_handler3(ptr ptr ptr ptr) -# stub _except_handler4_common +@ cdecl -i386 _except_handler4_common(ptr ptr ptr ptr ptr ptr) @ varargs _execl(str str) @ varargs _execle(str str) @ varargs _execlp(str str) @@ -578,7 +578,7 @@ # stub _lfind_s @ cdecl _loaddll(str) @ cdecl -i386 _local_unwind2(ptr long) -# stub _local_unwind4 +@ cdecl -i386 _local_unwind4(ptr ptr long) @ cdecl _localtime32(ptr) MSVCRT__localtime32 # stub _localtime32_s @ cdecl _localtime64(ptr) MSVCRT__localtime64