Alexandre Julliard : ntdll: Add support for calling the TEB exception chain handlers on x86_64.

Alexandre Julliard julliard at winehq.org
Thu Jun 18 09:11:33 CDT 2009


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Jun 17 19:39:41 2009 +0200

ntdll: Add support for calling the TEB exception chain handlers on x86_64.

---

 dlls/ntdll/signal_x86_64.c |   90 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 90 insertions(+), 0 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 5e67398..83b84dc 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -1447,12 +1447,47 @@ static NTSTATUS call_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatc
 
 
 /**********************************************************************
+ *           call_teb_handler
+ *
+ * Call a single exception handler from the TEB chain.
+ * FIXME: Handle nested exceptions.
+ */
+static NTSTATUS call_teb_handler( EXCEPTION_RECORD *rec, DISPATCHER_CONTEXT *dispatch,
+                                  EXCEPTION_REGISTRATION_RECORD *teb_frame, CONTEXT *orig_context )
+{
+    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( "handler at %p returned %u\n", teb_frame->Handler, res );
+
+    switch (res)
+    {
+    case ExceptionContinueExecution:
+        if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
+        *orig_context = *dispatch->ContextRecord;
+        return STATUS_SUCCESS;
+    case ExceptionContinueSearch:
+        break;
+    case ExceptionNestedException:
+        break;
+    default:
+        return STATUS_INVALID_DISPOSITION;
+    }
+    return STATUS_UNHANDLED_EXCEPTION;
+}
+
+
+/**********************************************************************
  *           call_stack_handlers
  *
  * Call the stack handlers chain.
  */
 static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
 {
+    EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
     UNWIND_HISTORY_TABLE table;
     RUNTIME_FUNCTION *dir;
     DISPATCHER_CONTEXT dispatch;
@@ -1542,6 +1577,17 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
             status = call_handler( rec, &dispatch, orig_context );
             if (status != STATUS_UNHANDLED_EXCEPTION) return status;
         }
+        /* hack: call wine handlers registered in the tib list */
+        else while ((ULONG64)teb_frame < new_context.Rsp)
+        {
+            TRACE( "found wine frame %p rsp %lx handler %p\n",
+                   teb_frame, new_context.Rsp, teb_frame->Handler );
+            dispatch.EstablisherFrame = (ULONG64)teb_frame;
+            context = *orig_context;
+            status = call_teb_handler( rec, &dispatch, teb_frame, orig_context );
+            if (status != STATUS_UNHANDLED_EXCEPTION) return status;
+            teb_frame = teb_frame->Prev;
+        }
 
         if (new_context.Rsp == (ULONG64)NtCurrentTeb()->Tib.StackBase) break;
         context = new_context;
@@ -2239,12 +2285,44 @@ 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,
+                                     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( "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;
+    }
+}
+
+
 /*******************************************************************
  *		RtlUnwindEx (NTDLL.@)
  */
 void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD *rec,
                          ULONG64 retval, CONTEXT *orig_context, UNWIND_HISTORY_TABLE *table )
 {
+    EXCEPTION_REGISTRATION_RECORD *teb_frame = NtCurrentTeb()->Tib.ExceptionList;
     EXCEPTION_RECORD record;
     RUNTIME_FUNCTION *dir;
     DISPATCHER_CONTEXT dispatch;
@@ -2364,6 +2442,18 @@ void WINAPI RtlUnwindEx( ULONG64 end_frame, ULONG64 target_ip, EXCEPTION_RECORD
             }
             call_unwind_handler( rec, &dispatch );
         }
+        else  /* hack: call builtin handlers registered in the tib list */
+        {
+            while ((ULONG64)teb_frame < new_context.Rsp && (ULONG64)teb_frame < end_frame)
+            {
+                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 );
+                teb_frame = __wine_pop_frame( teb_frame );
+            }
+            if ((ULONG64)teb_frame == end_frame && end_frame < new_context.Rsp) break;
+            dispatch.EstablisherFrame = new_context.Rsp;
+        }
 
         context = new_context;
     }




More information about the wine-cvs mailing list