Alexandre Julliard : ntdll: Add support for debug registers in exceptions on x86-64.

Alexandre Julliard julliard at winehq.org
Wed Jul 19 16:05:33 CDT 2017


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Jul 19 17:11:38 2017 +0200

ntdll: Add support for debug registers in exceptions on x86-64.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/signal_x86_64.c | 114 ++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 96 insertions(+), 18 deletions(-)

diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index f0127f7..08881e7 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -310,6 +310,12 @@ static wine_signal_handler handlers[256];
 
 struct amd64_thread_data
 {
+    DWORD_PTR dr0;           /* debug registers */
+    DWORD_PTR dr1;
+    DWORD_PTR dr2;
+    DWORD_PTR dr3;
+    DWORD_PTR dr6;
+    DWORD_PTR dr7;
     void     *exit_frame;    /* exit frame pointer */
 };
 
@@ -1661,7 +1667,7 @@ static inline BOOL is_inside_signal_stack( void *ptr )
  */
 static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
 {
-    context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
+    context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS;
     context->Rax    = RAX_sig(sigcontext);
     context->Rcx    = RCX_sig(sigcontext);
     context->Rdx    = RDX_sig(sigcontext);
@@ -1698,6 +1704,12 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
 #else
     __asm__("movw %%ss,%0" : "=m" (context->SegSs));
 #endif
+    context->Dr0    = amd64_thread_data()->dr0;
+    context->Dr1    = amd64_thread_data()->dr1;
+    context->Dr2    = amd64_thread_data()->dr2;
+    context->Dr3    = amd64_thread_data()->dr3;
+    context->Dr6    = amd64_thread_data()->dr6;
+    context->Dr7    = amd64_thread_data()->dr7;
     if (FPU_sig(sigcontext))
     {
         context->ContextFlags |= CONTEXT_FLOATING_POINT;
@@ -1714,6 +1726,12 @@ static void save_context( CONTEXT *context, const ucontext_t *sigcontext )
  */
 static void restore_context( const CONTEXT *context, ucontext_t *sigcontext )
 {
+    amd64_thread_data()->dr0 = context->Dr0;
+    amd64_thread_data()->dr1 = context->Dr1;
+    amd64_thread_data()->dr2 = context->Dr2;
+    amd64_thread_data()->dr3 = context->Dr3;
+    amd64_thread_data()->dr6 = context->Dr6;
+    amd64_thread_data()->dr7 = context->Dr7;
     RAX_sig(sigcontext) = context->Rax;
     RCX_sig(sigcontext) = context->Rcx;
     RDX_sig(sigcontext) = context->Rdx;
@@ -1873,6 +1891,16 @@ __ASM_GLOBAL_FUNC( set_full_cpu_context,
 static void set_cpu_context( const CONTEXT *context )
 {
     DWORD flags = context->ContextFlags & ~CONTEXT_AMD64;
+
+    if (flags & CONTEXT_DEBUG_REGISTERS)
+    {
+        amd64_thread_data()->dr0 = context->Dr0;
+        amd64_thread_data()->dr1 = context->Dr1;
+        amd64_thread_data()->dr2 = context->Dr2;
+        amd64_thread_data()->dr3 = context->Dr3;
+        amd64_thread_data()->dr6 = context->Dr6;
+        amd64_thread_data()->dr7 = context->Dr7;
+    }
     if (flags & CONTEXT_FULL)
     {
         if (!(flags & CONTEXT_CONTROL))
@@ -2081,10 +2109,20 @@ NTSTATUS context_from_server( CONTEXT *to, const context_t *from )
  */
 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
 {
-    NTSTATUS ret;
-    BOOL self;
+    NTSTATUS ret = STATUS_SUCCESS;
+    BOOL self = (handle == GetCurrentThread());
+
+    /* debug registers require a server call */
+    if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64)))
+        self = (amd64_thread_data()->dr0 == context->Dr0 &&
+                amd64_thread_data()->dr1 == context->Dr1 &&
+                amd64_thread_data()->dr2 == context->Dr2 &&
+                amd64_thread_data()->dr3 == context->Dr3 &&
+                amd64_thread_data()->dr6 == context->Dr6 &&
+                amd64_thread_data()->dr7 == context->Dr7);
+
+    if (!self) ret = set_thread_context( handle, context, &self );
 
-    ret = set_thread_context( handle, context, &self );
     if (self && ret == STATUS_SUCCESS) set_cpu_context( context );
     return ret;
 }
@@ -2109,12 +2147,25 @@ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
         needed_flags &= ~context->ContextFlags;
     }
 
-    if (self && needed_flags)
+    if (self)
     {
-        CONTEXT ctx;
-        RtlCaptureContext( &ctx );
-        copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
-        context->ContextFlags |= ctx.ContextFlags & needed_flags;
+        if (needed_flags)
+        {
+            CONTEXT ctx;
+            RtlCaptureContext( &ctx );
+            copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
+            context->ContextFlags |= ctx.ContextFlags & needed_flags;
+        }
+        /* update the cached version of the debug registers */
+        if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_AMD64))
+        {
+            amd64_thread_data()->dr0 = context->Dr0;
+            amd64_thread_data()->dr1 = context->Dr1;
+            amd64_thread_data()->dr2 = context->Dr2;
+            amd64_thread_data()->dr3 = context->Dr3;
+            amd64_thread_data()->dr6 = context->Dr6;
+            amd64_thread_data()->dr7 = context->Dr7;
+        }
     }
     return STATUS_SUCCESS;
 }
@@ -2618,14 +2669,42 @@ static void raise_segv_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
             case 3: /* BREAKPOINT_LOAD_SYMBOLS */
             case 4: /* BREAKPOINT_UNLOAD_SYMBOLS */
             case 5: /* BREAKPOINT_COMMAND_STRING (>= Win2003) */
-                goto done;
+                set_cpu_context( context );
         }
         break;
     }
-    status = raise_exception( rec, context, TRUE );
-    if (status) raise_status( status, rec );
-done:
-    set_cpu_context( context );
+    status = NtRaiseException( rec, context, TRUE );
+    raise_status( status, rec );
+}
+
+
+/**********************************************************************
+ *		raise_trap_exception
+ */
+static void raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
+{
+    NTSTATUS status;
+
+    if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
+    {
+        /* when single stepping can't tell whether this is a hw bp or a
+         * single step interrupt. try to avoid as much overhead as possible
+         * and only do a server call if there is any hw bp enabled. */
+
+        if( !(context->EFlags & 0x100) || (amd64_thread_data()->dr7 & 0xff) )
+        {
+            /* (possible) hardware breakpoint, fetch the debug registers */
+            DWORD saved_flags = context->ContextFlags;
+            context->ContextFlags = CONTEXT_DEBUG_REGISTERS;
+            NtGetContextThread(GetCurrentThread(), context);
+            context->ContextFlags |= saved_flags;  /* restore flags */
+        }
+
+        context->EFlags &= ~0x100;  /* clear single-step flag */
+    }
+
+    status = NtRaiseException( rec, context, TRUE );
+    raise_status( status, rec );
 }
 
 
@@ -2636,9 +2715,8 @@ done:
  */
 static void raise_generic_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
 {
-    NTSTATUS status = raise_exception( rec, context, TRUE );
-    if (status) raise_status( status, rec );
-    set_cpu_context( context );
+    NTSTATUS status = NtRaiseException( rec, context, TRUE );
+    raise_status( status, rec );
 }
 
 
@@ -2747,7 +2825,7 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext )
  */
 static void trap_handler( int signal, siginfo_t *siginfo, void *sigcontext )
 {
-    EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_generic_exception );
+    EXCEPTION_RECORD *rec = setup_exception( sigcontext, raise_trap_exception );
 
     switch (siginfo->si_code)
     {




More information about the wine-cvs mailing list