Alexandre Julliard : ntdll: Add debug registers to the context of all exceptions.

Alexandre Julliard julliard at wine.codeweavers.com
Fri Jan 13 07:31:20 CST 2006


Module: wine
Branch: refs/heads/master
Commit: 2878d9921669aaceb840ce460be4026f039076ec
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=2878d9921669aaceb840ce460be4026f039076ec

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Fri Jan 13 13:58:14 2006 +0100

ntdll: Add debug registers to the context of all exceptions.
Maintain a local cache of the debug registers to avoid server calls
where possible.

---

 dlls/ntdll/ntdll_misc.h        |   17 ++++++++++++++
 dlls/ntdll/signal_i386.c       |   47 ++++++++++++++++++++++++----------------
 dlls/ntdll/thread.c            |   33 ++++++++++++++++++++++++++--
 include/wine/server_protocol.h |    3 ++-
 include/winternl.h             |    2 +-
 server/protocol.def            |    1 +
 server/thread.c                |    1 +
 server/trace.c                 |    1 +
 8 files changed, 81 insertions(+), 24 deletions(-)

diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index ac9acae..c63b700 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -134,4 +134,21 @@ static inline struct ntdll_thread_data *
     return (struct ntdll_thread_data *)NtCurrentTeb()->SystemReserved2;
 }
 
+/* thread registers, stored in NtCurrentTeb()->SpareBytes1 */
+struct ntdll_thread_regs
+{
+    DWORD              dr0;           /* debug registers */
+    DWORD              dr1;
+    DWORD              dr2;
+    DWORD              dr3;
+    DWORD              dr6;
+    DWORD              dr7;
+    DWORD              spare[4];      /* change this if you add fields! */
+};
+
+static inline struct ntdll_thread_regs *ntdll_get_thread_regs(void)
+{
+    return (struct ntdll_thread_regs *)NtCurrentTeb()->SpareBytes1;
+}
+
 #endif
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index be33458..1b2e8f0 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -740,7 +740,9 @@ inline static void restore_fpu( const CO
  */
 inline static void save_context( CONTEXT *context, const SIGCONTEXT *sigcontext, WORD fs, WORD gs )
 {
-    context->ContextFlags = CONTEXT_FULL;
+    struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+
+    context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
     context->Eax          = EAX_sig(sigcontext);
     context->Ebx          = EBX_sig(sigcontext);
     context->Ecx          = ECX_sig(sigcontext);
@@ -757,6 +759,12 @@ inline static void save_context( CONTEXT
     context->SegFs        = fs;
     context->SegGs        = gs;
     context->SegSs        = LOWORD(SS_sig(sigcontext));
+    context->Dr0          = regs->dr0;
+    context->Dr1          = regs->dr1;
+    context->Dr2          = regs->dr2;
+    context->Dr3          = regs->dr3;
+    context->Dr6          = regs->dr6;
+    context->Dr7          = regs->dr7;
 }
 
 
@@ -767,6 +775,14 @@ inline static void save_context( CONTEXT
  */
 inline static void restore_context( const CONTEXT *context, SIGCONTEXT *sigcontext )
 {
+    struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+
+    regs->dr0 = context->Dr0;
+    regs->dr1 = context->Dr1;
+    regs->dr2 = context->Dr2;
+    regs->dr3 = context->Dr3;
+    regs->dr6 = context->Dr6;
+    regs->dr7 = context->Dr7;
     EAX_sig(sigcontext) = context->Eax;
     EBX_sig(sigcontext) = context->Ebx;
     ECX_sig(sigcontext) = context->Ecx;
@@ -797,7 +813,7 @@ inline static void restore_context( cons
 /***********************************************************************
  *           set_cpu_context
  *
- * Set the new CPU context.
+ * Set the new CPU context. Used by NtSetContextThread.
  */
 void set_cpu_context( const CONTEXT *context )
 {
@@ -805,6 +821,16 @@ void set_cpu_context( const CONTEXT *con
 
     if (flags & CONTEXT_FLOATING_POINT) restore_fpu( context );
 
+    if (flags & CONTEXT_DEBUG_REGISTERS)
+    {
+        struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+        regs->dr0 = context->Dr0;
+        regs->dr1 = context->Dr1;
+        regs->dr2 = context->Dr2;
+        regs->dr3 = context->Dr3;
+        regs->dr6 = context->Dr6;
+        regs->dr7 = context->Dr7;
+    }
     if (flags & CONTEXT_FULL)
     {
         if ((flags & CONTEXT_FULL) != (CONTEXT_FULL & ~CONTEXT_i386))
@@ -1027,8 +1053,6 @@ done:
  */
 static void WINAPI raise_trap_exception( EXCEPTION_RECORD *rec, CONTEXT *context )
 {
-    DWORD dr0, dr1, dr2, dr3, dr6, dr7;
-
     if (rec->ExceptionCode == EXCEPTION_SINGLE_STEP)
     {
         if (context->EFlags & 0x100)
@@ -1048,22 +1072,7 @@ static void WINAPI raise_trap_exception(
         }
     }
 
-    dr0 = context->Dr0;
-    dr1 = context->Dr1;
-    dr2 = context->Dr2;
-    dr3 = context->Dr3;
-    dr6 = context->Dr6;
-    dr7 = context->Dr7;
-
     __regs_RtlRaiseException( rec, context );
-
-    context->ContextFlags = CONTEXT_FULL;
-    if (dr0 != context->Dr0 || dr1 != context->Dr1 || dr2 != context->Dr2 ||
-        dr3 != context->Dr3 || dr6 != context->Dr6 || dr7 != context->Dr7)
-    {
-        /* the debug registers have changed, set the new values */
-        context->ContextFlags |= CONTEXT_DEBUG_REGISTERS;
-    }
     NtSetContextThread( GetCurrentThread(), context );
 }
 
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 9a2e2bd..d189bf7 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -294,6 +294,9 @@ NTSTATUS WINAPI RtlCreateUserThread( HAN
     teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
     teb->ClientId.UniqueThread  = (HANDLE)tid;
 
+    /* inherit registers from parent thread */
+    memcpy( teb->SpareBytes1, ntdll_get_thread_regs(), sizeof(teb->SpareBytes1) );
+
     thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
     thread_data->request_fd  = request_pipe[1];
 
@@ -495,8 +498,14 @@ NTSTATUS WINAPI NtSetContextThread( HAND
 
 #ifdef __i386__
     /* on i386 debug registers always require a server call */
-    self = ((handle == GetCurrentThread()) &&
-            !(context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)));
+    self = (handle == GetCurrentThread());
+    if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
+    {
+        struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+        self = (regs->dr0 == context->Dr0 && regs->dr1 == context->Dr1 &&
+                regs->dr2 == context->Dr2 && regs->dr3 == context->Dr3 &&
+                regs->dr6 == context->Dr6 && regs->dr7 == context->Dr7);
+    }
 #endif
 
     if (!self)
@@ -781,6 +790,7 @@ NTSTATUS WINAPI NtGetContextThread( HAND
     NTSTATUS ret;
     CONTEXT ctx;
     DWORD dummy, i;
+    BOOL self = FALSE;
 
     SERVER_START_REQ( get_thread_context )
     {
@@ -789,6 +799,7 @@ NTSTATUS WINAPI NtGetContextThread( HAND
         req->suspend = 0;
         wine_server_set_reply( req, &ctx, sizeof(ctx) );
         ret = wine_server_call( req );
+        self = reply->self;
     }
     SERVER_END_REQ;
 
@@ -814,7 +825,23 @@ NTSTATUS WINAPI NtGetContextThread( HAND
         }
     }
 
-    if (ret == STATUS_SUCCESS) copy_context( context, &ctx, context->ContextFlags );
+    if (ret == STATUS_SUCCESS)
+    {
+        copy_context( context, &ctx, context->ContextFlags );
+#ifdef __i386__
+        /* update the cached version of the debug registers */
+        if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
+        {
+            struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
+            regs->dr0 = context->Dr0;
+            regs->dr1 = context->Dr1;
+            regs->dr2 = context->Dr2;
+            regs->dr3 = context->Dr3;
+            regs->dr6 = context->Dr6;
+            regs->dr7 = context->Dr7;
+        }
+#endif
+    }
     else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
     return ret;
 }
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 5f2ad9e..4ab1467 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1990,6 +1990,7 @@ struct get_thread_context_request
 struct get_thread_context_reply
 {
     struct reply_header __header;
+    int          self;
     /* VARARG(context,context); */
 };
 
@@ -4348,6 +4349,6 @@ union generic_reply
     struct query_symlink_reply query_symlink_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 219
+#define SERVER_PROTOCOL_VERSION 220
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/winternl.h b/include/winternl.h
index 67403bb..a5a2e83 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -282,7 +282,7 @@ typedef struct _TEB
     PVOID           SystemReserved1[54];        /* 0cc used for kernel32 private data in Wine */
     PVOID           Spare1;                     /* 1a4 */
     LONG            ExceptionCode;              /* 1a8 */
-    BYTE            SpareBytes1[40];            /* 1ac */
+    BYTE            SpareBytes1[40];            /* 1ac used for ntdll private data in Wine */
     PVOID           SystemReserved2[10];        /* 1d4 used for ntdll private data in Wine */
     GDI_TEB_BATCH   GdiTebBatch;                /* 1fc */
     ULONG           gdiRgn;                     /* 6dc */
diff --git a/server/protocol.def b/server/protocol.def
index 55aef19..d3878cb 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1432,6 +1432,7 @@ enum char_info_mode
     unsigned int flags;        /* context flags */
     int          suspend;      /* if getting context during suspend */
 @REPLY
+    int          self;         /* was it a handle to the current thread? */
     VARARG(context,context);   /* thread context */
 @END
 
diff --git a/server/thread.c b/server/thread.c
index 3ffbf85..1c00ce7 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1094,6 +1094,7 @@ DECL_HANDLER(get_thread_context)
         memset( data, 0, sizeof(CONTEXT) );
         get_thread_context( thread, data, req->flags );
     }
+    reply->self = (thread == current);
     release_object( thread );
 }
 
diff --git a/server/trace.c b/server/trace.c
index 49ff25e..1aa964e 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1895,6 +1895,7 @@ static void dump_get_thread_context_requ
 
 static void dump_get_thread_context_reply( const struct get_thread_context_reply *req )
 {
+    fprintf( stderr, " self=%d,", req->self );
     fprintf( stderr, " context=" );
     dump_varargs_context( cur_size );
 }




More information about the wine-cvs mailing list