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(®);
+
+ 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
More information about the wine-cvs
mailing list