Piotr Caban : ntdll: Add support for collided unwinds.

Alexandre Julliard julliard at winehq.org
Thu Aug 18 10:23:24 CDT 2016


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

Author: Piotr Caban <piotr at codeweavers.com>
Date:   Wed Aug 17 12:48:00 2016 +0200

ntdll: Add support for collided unwinds.

Based on work by Alexandre Julliard.

Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/signal_x86_64.c | 90 +++++++++++++++++++++++++++++++++++++---------
 include/wine/exception.h   |  1 +
 2 files changed, 75 insertions(+), 16 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 4c88536..79ca846 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -3376,35 +3376,69 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
     return (char *)base + handler_data->handler;
 }
 
+struct unwind_exception_frame
+{
+    EXCEPTION_REGISTRATION_RECORD frame;
+    DISPATCHER_CONTEXT *dispatch;
+};
+
+/**********************************************************************
+ *           unwind_exception_handler
+ *
+ * Handler for exceptions happening while calling an unwind handler.
+ */
+static DWORD unwind_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
+                                       CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
+{
+    struct unwind_exception_frame *unwind_frame = (struct unwind_exception_frame *)frame;
+    DISPATCHER_CONTEXT *dispatch = (DISPATCHER_CONTEXT *)dispatcher;
+
+    /* copy the original dispatcher into the current one, except for the TargetIp */
+    dispatch->ControlPc        = unwind_frame->dispatch->ControlPc;
+    dispatch->ImageBase        = unwind_frame->dispatch->ImageBase;
+    dispatch->FunctionEntry    = unwind_frame->dispatch->FunctionEntry;
+    dispatch->EstablisherFrame = unwind_frame->dispatch->EstablisherFrame;
+    dispatch->ContextRecord    = unwind_frame->dispatch->ContextRecord;
+    dispatch->LanguageHandler  = unwind_frame->dispatch->LanguageHandler;
+    dispatch->HandlerData      = unwind_frame->dispatch->HandlerData;
+    dispatch->HistoryTable     = unwind_frame->dispatch->HistoryTable;
+    dispatch->ScopeIndex       = unwind_frame->dispatch->ScopeIndex;
+    TRACE( "detected collided unwind\n" );
+    return ExceptionCollidedUnwind;
+}
 
 /**********************************************************************
  *           call_unwind_handler
  *
  * Call a single unwind handler.
- * FIXME: Handle nested exceptions.
  */
-static void call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
+static DWORD call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch )
 {
+    struct unwind_exception_frame frame;
     DWORD res;
 
-    dispatch->ControlPc = dispatch->ContextRecord->Rip;
+    frame.frame.Handler = unwind_exception_handler;
+    frame.dispatch = dispatch;
+    __wine_push_frame( &frame.frame );
 
     TRACE( "calling handler %p (rec=%p, frame=0x%lx context=%p, dispatch=%p)\n",
          dispatch->LanguageHandler, rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
     res = dispatch->LanguageHandler( rec, dispatch->EstablisherFrame, dispatch->ContextRecord, dispatch );
     TRACE( "handler %p returned %x\n", dispatch->LanguageHandler, res );
 
+    __wine_pop_frame( &frame.frame );
+
     switch (res)
     {
     case ExceptionContinueSearch:
-        break;
     case ExceptionCollidedUnwind:
-        FIXME( "ExceptionCollidedUnwind not supported yet\n" );
         break;
     default:
         raise_status( STATUS_INVALID_DISPOSITION, rec );
         break;
     }
+
+    return res;
 }
 
 
@@ -3412,30 +3446,28 @@ static void call_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *disp
  *           call_teb_unwind_handler
  *
  * Call a single unwind handler from the TEB chain.
- * FIXME: Handle nested exceptions.
  */
-static void call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
+static DWORD call_teb_unwind_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
                                      EXCEPTION_REGISTRATION_RECORD *teb_frame )
 {
-    EXCEPTION_REGISTRATION_RECORD *dispatcher;
     DWORD res;
 
-    TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatcher=%p)\n",
-           teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, &dispatcher );
-    res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, &dispatcher );
+    TRACE( "calling TEB handler %p (rec=%p, frame=%p context=%p, dispatch=%p)\n",
+           teb_frame->Handler, rec, teb_frame, dispatch->ContextRecord, dispatch );
+    res = teb_frame->Handler( rec, teb_frame, dispatch->ContextRecord, (EXCEPTION_REGISTRATION_RECORD**)dispatch );
     TRACE( "handler at %p returned %u\n", teb_frame->Handler, res );
 
     switch (res)
     {
     case ExceptionContinueSearch:
-        break;
     case ExceptionCollidedUnwind:
-        FIXME( "ExceptionCollidedUnwind not supported yet\n" );
         break;
     default:
         raise_status( STATUS_INVALID_DISPOSITION, rec );
         break;
     }
+
+    return res;
 }
 
 
@@ -3588,7 +3620,8 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
         /* FIXME: should use the history table to make things faster */
 
         dispatch.ImageBase = 0;
-        dispatch.ScopeIndex = 0; /* FIXME */
+        dispatch.ScopeIndex = 0;
+        dispatch.ControlPc = context->Rip;
 
         /* first look for PE exception information */
 
@@ -3674,7 +3707,19 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
                 raise_status( STATUS_INVALID_UNWIND_TARGET, rec );
             }
             if (dispatch.EstablisherFrame == (ULONG64)end_frame) rec->ExceptionFlags |= EH_TARGET_UNWIND;
-            call_unwind_handler( rec, &dispatch );
+            if (call_unwind_handler( rec, &dispatch ) == ExceptionCollidedUnwind)
+            {
+                ULONG64 frame;
+
+                *context = new_context = *dispatch.ContextRecord;
+                dispatch.ContextRecord = context;
+                RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
+                        dispatch.ControlPc, dispatch.FunctionEntry,
+                        &new_context, NULL, &frame, NULL );
+                rec->ExceptionFlags |= EH_COLLIDED_UNWIND;
+                goto unwind_done;
+            }
+            rec->ExceptionFlags &= ~EH_COLLIDED_UNWIND;
         }
         else  /* hack: call builtin handlers registered in the tib list */
         {
@@ -3683,7 +3728,20 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
             {
                 TRACE( "found builtin frame %p handler %p\n", teb_frame, teb_frame->Handler );
                 dispatch.EstablisherFrame = (ULONG64)teb_frame;
-                call_teb_unwind_handler( rec, &dispatch, teb_frame );
+                if (call_teb_unwind_handler( rec, &dispatch, teb_frame ) == ExceptionCollidedUnwind)
+                {
+                    ULONG64 frame;
+
+                    teb_frame = __wine_pop_frame( teb_frame );
+
+                    *context = new_context = *dispatch.ContextRecord;
+                    dispatch.ContextRecord = context;
+                    RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase,
+                            dispatch.ControlPc, dispatch.FunctionEntry,
+                            &new_context, NULL, &frame, NULL );
+                    rec->ExceptionFlags |= EH_COLLIDED_UNWIND;
+                    goto unwind_done;
+                }
                 teb_frame = __wine_pop_frame( teb_frame );
             }
             if ((ULONG64)teb_frame == (ULONG64)end_frame && (ULONG64)end_frame < new_context.Rsp) break;
diff --git a/include/wine/exception.h b/include/wine/exception.h
index 8b807c1..f275568 100644
--- a/include/wine/exception.h
+++ b/include/wine/exception.h
@@ -253,6 +253,7 @@ static inline EXCEPTION_REGISTRATION_RECORD *__wine_get_frame(void)
 #define EH_STACK_INVALID    0x08
 #define EH_NESTED_CALL      0x10
 #define EH_TARGET_UNWIND    0x20
+#define EH_COLLIDED_UNWIND  0x40
 
 /* Wine-specific exceptions codes */
 




More information about the wine-cvs mailing list