Alexandre Julliard : ntdll: Get registers on the client side for NtGetContextThread on the current thread .

Alexandre Julliard julliard at wine.codeweavers.com
Thu Apr 20 08:46:18 CDT 2006


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Apr 20 15:40:28 2006 +0200

ntdll: Get registers on the client side for NtGetContextThread on the current thread.

---

 dlls/ntdll/ntdll_misc.h     |    1 +
 dlls/ntdll/signal_i386.c    |   32 ++++++++++++++++---
 dlls/ntdll/signal_powerpc.c |   11 ++++++
 dlls/ntdll/signal_sparc.c   |   11 ++++++
 dlls/ntdll/signal_x86_64.c  |   11 ++++++
 dlls/ntdll/thread.c         |   74 ++++++++++++++++++++++++++-----------------
 server/context_i386.c       |    5 +--
 7 files changed, 109 insertions(+), 36 deletions(-)

diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h
index 35cbd5b..fa18e46 100644
--- a/dlls/ntdll/ntdll_misc.h
+++ b/dlls/ntdll/ntdll_misc.h
@@ -32,6 +32,7 @@ #define MAX_NT_PATH_LENGTH 277
 /* exceptions */
 extern void wait_suspend( CONTEXT *context );
 extern void WINAPI __regs_RtlRaiseException( PEXCEPTION_RECORD, PCONTEXT );
+extern void get_cpu_context( CONTEXT *context );
 extern void set_cpu_context( const CONTEXT *context );
 
 /* debug helper */
diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c
index 39b20d0..398dbdf 100644
--- a/dlls/ntdll/signal_i386.c
+++ b/dlls/ntdll/signal_i386.c
@@ -704,6 +704,20 @@ #endif
 
 
 /***********************************************************************
+ *           save_fpu
+ *
+ * Save the thread FPU context.
+ */
+inline static void save_fpu( CONTEXT *context )
+{
+#ifdef __GNUC__
+    context->ContextFlags |= CONTEXT_FLOATING_POINT;
+    __asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
+#endif
+}
+
+
+/***********************************************************************
  *           restore_fpu
  *
  * Restore the FPU context to a sigcontext.
@@ -762,10 +776,7 @@ #ifdef FPU_sig
     else
 #endif
     {
-#ifdef __GNUC__
-        context->ContextFlags |= CONTEXT_FLOATING_POINT;
-        __asm__ __volatile__( "fnsave %0; fwait" : "=m" (context->FloatSave) );
-#endif
+        save_fpu( context );
     }
 }
 
@@ -824,6 +835,19 @@ #endif
 
 
 /***********************************************************************
+ *              get_cpu_context
+ *
+ * Register function to get the context of the current thread.
+ */
+void WINAPI __regs_get_cpu_context( CONTEXT *context, CONTEXT *regs )
+{
+    *context = *regs;
+    save_fpu( context );
+}
+DEFINE_REGS_ENTRYPOINT( get_cpu_context, 4, 4 );
+
+
+/***********************************************************************
  *           set_cpu_context
  *
  * Set the new CPU context. Used by NtSetContextThread.
diff --git a/dlls/ntdll/signal_powerpc.c b/dlls/ntdll/signal_powerpc.c
index 50d48d4..cbe4f80 100644
--- a/dlls/ntdll/signal_powerpc.c
+++ b/dlls/ntdll/signal_powerpc.c
@@ -269,6 +269,17 @@ #undef C
 
 
 /***********************************************************************
+ *              get_cpu_context
+ *
+ * Get the context of the current thread.
+ */
+void get_cpu_context( CONTEXT *context )
+{
+    FIXME("not implemented\n");
+}
+
+
+/***********************************************************************
  *           set_cpu_context
  *
  * Set the new CPU context.
diff --git a/dlls/ntdll/signal_sparc.c b/dlls/ntdll/signal_sparc.c
index 4ae3340..0bf8dac 100644
--- a/dlls/ntdll/signal_sparc.c
+++ b/dlls/ntdll/signal_sparc.c
@@ -149,6 +149,17 @@ static void restore_fpu( CONTEXT *contex
 
 
 /***********************************************************************
+ *              get_cpu_context
+ *
+ * Get the context of the current thread.
+ */
+void get_cpu_context( CONTEXT *context )
+{
+    FIXME("not implemented\n");
+}
+
+
+/***********************************************************************
  *           set_cpu_context
  *
  * Set the new CPU context.
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 87d40b5..4ae61e7 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -199,6 +199,17 @@ static void restore_context( const CONTE
 
 
 /***********************************************************************
+ *              get_cpu_context
+ *
+ * Get the context of the current thread.
+ */
+void get_cpu_context( CONTEXT *context )
+{
+    FIXME("not implemented\n");
+}
+
+
+/***********************************************************************
  *           set_cpu_context
  *
  * Set the new CPU context.
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index b4226f9..67e6930 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -921,47 +921,64 @@ NTSTATUS WINAPI NtGetContextThread( HAND
     NTSTATUS ret;
     CONTEXT ctx;
     DWORD dummy, i;
-    BOOL self = FALSE;
+    DWORD needed_flags = context->ContextFlags;
+    BOOL self = (handle == GetCurrentThread());
 
-    SERVER_START_REQ( get_thread_context )
-    {
-        req->handle  = handle;
-        req->flags   = context->ContextFlags;
-        req->suspend = 0;
-        wine_server_set_reply( req, &ctx, sizeof(ctx) );
-        ret = wine_server_call( req );
-        self = reply->self;
-    }
-    SERVER_END_REQ;
+#ifdef __i386__
+    /* on i386 debug registers always require a server call */
+    if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)) self = FALSE;
+#endif
 
-    if (ret == STATUS_PENDING)
+    if (!self)
     {
-        if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
+        SERVER_START_REQ( get_thread_context )
+        {
+            req->handle  = handle;
+            req->flags   = context->ContextFlags;
+            req->suspend = 0;
+            wine_server_set_reply( req, &ctx, sizeof(ctx) );
+            ret = wine_server_call( req );
+            self = reply->self;
+        }
+        SERVER_END_REQ;
+
+        if (ret == STATUS_PENDING)
         {
-            for (i = 0; i < 100; i++)
+            if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
             {
-                SERVER_START_REQ( get_thread_context )
+                for (i = 0; i < 100; i++)
                 {
-                    req->handle  = handle;
-                    req->flags   = context->ContextFlags;
-                    req->suspend = 0;
-                    wine_server_set_reply( req, &ctx, sizeof(ctx) );
-                    ret = wine_server_call( req );
+                    SERVER_START_REQ( get_thread_context )
+                    {
+                        req->handle  = handle;
+                        req->flags   = context->ContextFlags;
+                        req->suspend = 0;
+                        wine_server_set_reply( req, &ctx, sizeof(ctx) );
+                        ret = wine_server_call( req );
+                    }
+                    SERVER_END_REQ;
+                    if (ret != STATUS_PENDING) break;
+                    NtYieldExecution();
                 }
-                SERVER_END_REQ;
-                if (ret != STATUS_PENDING) break;
-                NtYieldExecution();
+                NtResumeThread( handle, &dummy );
             }
-            NtResumeThread( handle, &dummy );
+            if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
         }
+        if (ret) return ret;
+        copy_context( context, &ctx, context->ContextFlags & ctx.ContextFlags );
+        needed_flags &= ~ctx.ContextFlags;
     }
 
-    if (ret == STATUS_SUCCESS)
+    if (self)
     {
-        copy_context( context, &ctx, context->ContextFlags );
+        if (needed_flags)
+        {
+            get_cpu_context( &ctx );
+            copy_context( context, &ctx, ctx.ContextFlags & needed_flags );
+        }
 #ifdef __i386__
         /* update the cached version of the debug registers */
-        if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
+        if (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386))
         {
             struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
             regs->dr0 = context->Dr0;
@@ -973,8 +990,7 @@ #ifdef __i386__
         }
 #endif
     }
-    else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
-    return ret;
+    return STATUS_SUCCESS;
 }
 
 
diff --git a/server/context_i386.c b/server/context_i386.c
index ce7fd9b..0a3a329 100644
--- a/server/context_i386.c
+++ b/server/context_i386.c
@@ -550,10 +550,9 @@ void get_thread_context( struct thread *
     flags &= ~CONTEXT_i386;  /* get rid of CPU id */
 
     if (thread->context)  /* thread is inside an exception event or suspended */
-    {
         copy_context( context, thread->context, flags );
-        flags &= CONTEXT_DEBUG_REGISTERS;
-    }
+
+    flags &= CONTEXT_DEBUG_REGISTERS;
 
     if (flags && suspend_for_ptrace( thread ))
     {




More information about the wine-cvs mailing list