Alexandre Julliard : ntdll: Initial support for dispatching exceptions to stack handlers on x86_64.

Alexandre Julliard julliard at winehq.org
Fri May 22 08:25:34 CDT 2009


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri May 22 11:52:13 2009 +0200

ntdll: Initial support for dispatching exceptions to stack handlers on x86_64.

---

 dlls/ntdll/signal_x86_64.c |  109 +++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 103 insertions(+), 6 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index cc65dc8..c9db2fe 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -52,6 +52,27 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(seh);
 
+struct _DISPATCHER_CONTEXT;
+
+typedef EXCEPTION_DISPOSITION (WINAPI *PEXCEPTION_ROUTINE)( EXCEPTION_RECORD *rec,
+                                                            ULONG64 frame,
+                                                            CONTEXT *context,
+                                                            struct _DISPATCHER_CONTEXT *dispatch );
+
+typedef struct _DISPATCHER_CONTEXT
+{
+    ULONG64               ControlPc;
+    ULONG64               ImageBase;
+    PRUNTIME_FUNCTION     FunctionEntry;
+    ULONG64               EstablisherFrame;
+    ULONG64               TargetIp;
+    PCONTEXT              ContextRecord;
+    PEXCEPTION_ROUTINE    LanguageHandler;
+    PVOID                 HandlerData;
+    PUNWIND_HISTORY_TABLE HistoryTable;
+    ULONG                 ScopeIndex;
+} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+
 
 /***********************************************************************
  * signal context platform-specific definitions
@@ -649,15 +670,92 @@ static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
  *
  * Call the stack handlers chain.
  */
-static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
+static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_context )
 {
     EXCEPTION_POINTERS ptrs;
+    UNWIND_HISTORY_TABLE table;
+    ULONG64 frame;
+    RUNTIME_FUNCTION *dir, *info;
+    PEXCEPTION_ROUTINE handler;
+    DISPATCHER_CONTEXT dispatch;
+    CONTEXT context, new_context;
+    LDR_MODULE *module;
+    DWORD size;
+
+    context = *orig_context;
+    for (;;)
+    {
+        /* FIXME: should use the history table to make things faster */
+
+        if (LdrFindEntryForAddress( (void *)context.Rip, &module ))
+        {
+            ERR( "no module found for rip %p, can't dispatch exception\n", (void *)context.Rip );
+            break;
+        }
+        if (!(dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
+                                                  IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
+        {
+            ERR( "module %s doesn't contain exception data, can't dispatch exception\n",
+                 debugstr_w(module->BaseDllName.Buffer) );
+            break;
+        }
+        if (!(info = find_function_info( context.Rip, module->BaseAddress, dir, size )))
+        {
+            /* leaf function */
+            context.Rip = *(ULONG64 *)context.Rsp;
+            context.Rsp += sizeof(ULONG64);
+            continue;
+        }
+
+        new_context = context;
 
-    FIXME( "not implemented on x86_64\n" );
+        handler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, (ULONG64)module->BaseAddress, context.Rip,
+                                    info, &new_context, &dispatch.HandlerData, &frame, NULL );
+
+        if ((frame & 7) ||
+            frame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
+            frame >= (ULONG64)NtCurrentTeb()->Tib.StackBase)
+        {
+            ERR( "invalid frame %lx\n", frame );
+            rec->ExceptionFlags |= EH_STACK_INVALID;
+            break;
+        }
+
+        if (handler)
+        {
+            dispatch.ControlPc        = context.Rip;
+            dispatch.ImageBase        = (ULONG64)module->BaseAddress;
+            dispatch.FunctionEntry    = info;
+            dispatch.EstablisherFrame = frame;
+            dispatch.TargetIp         = 0; /* FIXME */
+            dispatch.ContextRecord    = &context;
+            dispatch.LanguageHandler  = handler;
+            dispatch.HistoryTable     = &table;
+            dispatch.ScopeIndex       = 0; /* FIXME */
+
+            TRACE( "calling handler %p (rec=%p, frame=%lx context=%p, dispatch=%p)\n",
+                   handler, rec, frame, &context, &dispatch );
+
+            switch( handler( rec, frame, &context, &dispatch ))
+            {
+            case ExceptionContinueExecution:
+                if (rec->ExceptionFlags & EH_NONCONTINUABLE) return STATUS_NONCONTINUABLE_EXCEPTION;
+                *orig_context = context;
+                return STATUS_SUCCESS;
+            case ExceptionContinueSearch:
+                break;
+            case ExceptionNestedException:
+                break;
+            default:
+                return STATUS_INVALID_DISPOSITION;
+            }
+        }
+        context = new_context;
+    }
 
     /* hack: call unhandled exception filter directly */
     ptrs.ExceptionRecord = rec;
-    ptrs.ContextRecord = context;
+    ptrs.ContextRecord = orig_context;
     unhandled_exception_filter( &ptrs );
     return STATUS_UNHANDLED_EXCEPTION;
 }
@@ -679,7 +777,7 @@ static NTSTATUS raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL f
         TRACE( "code=%x flags=%x addr=%p ip=%lx tid=%04x\n",
                rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress,
                context->Rip, GetCurrentThreadId() );
-        for (c = 0; c < rec->NumberParameters; c++)
+        for (c = 0; c < min( EXCEPTION_MAXIMUM_PARAMETERS, rec->NumberParameters ); c++)
             TRACE( " info[%d]=%08lx\n", c, rec->ExceptionInformation[c] );
         if (rec->ExceptionCode == EXCEPTION_WINE_STUB)
         {
@@ -1241,8 +1339,7 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc,
     unsigned int i, prolog_offset;
 
     TRACE( "type %x rip %lx rsp %lx\n", type, pc, context->Rsp );
-
-    dump_unwind_info( base, function );
+    if (TRACE_ON(seh)) dump_unwind_info( base, function );
 
     frame = *frame_ret = context->Rsp;
     for (;;)




More information about the wine-cvs mailing list