Alexandre Julliard : msvcrt: Implement support for version 4 exception tables.

Alexandre Julliard julliard at winehq.org
Wed Apr 14 11:24:59 CDT 2010


Module: wine
Branch: master
Commit: a1e99f544b40e54d90e4d102186ba526f1489ca5
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a1e99f544b40e54d90e4d102186ba526f1489ca5

Author: Alexandre Julliard <julliard at 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(&reg);
+
+    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(&reg);
+    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




More information about the wine-cvs mailing list