Alexandre Julliard : server: Initialize debug registers in new threads if necessary.

Alexandre Julliard julliard at winehq.org
Thu Jul 27 15:26:14 CDT 2017


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

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Thu Jul 27 10:55:30 2017 +0200

server: Initialize debug registers in new threads if necessary.

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

---

 dlls/ntdll/tests/exception.c | 10 +++++-----
 server/ptrace.c              | 34 +++++++++++++++++++++++++++++++---
 server/thread.c              |  2 ++
 server/thread.h              |  1 +
 4 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 7cb704c..2308472 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -904,7 +904,7 @@ static void test_exceptions(void)
     res = pNtGetContextThread( h, &ctx );
     ok( res == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", res );
     ok( ctx.Dr0 == 0, "dr0 %x\n", ctx.Dr0 );
-    todo_wine ok( ctx.Dr7 == 0, "dr7 %x\n", ctx.Dr7 );
+    ok( ctx.Dr7 == 0, "dr7 %x\n", ctx.Dr7 );
     ctx.Dr0 = (DWORD)code_mem;
     ctx.Dr7 = 3;
     res = pNtSetContextThread( h, &ctx );
@@ -2168,8 +2168,8 @@ static DWORD WINAPI register_check_thread(void *arg)
     ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
     ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
     ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3);
-    todo_wine ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
-    todo_wine ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
+    ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
+    ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
 
     return 0;
 }
@@ -2238,8 +2238,8 @@ static void test_debug_registers(void)
     ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
     ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
     ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3);
-    todo_wine ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
-    todo_wine ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
+    ok(!ctx.Dr6, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr6);
+    ok(!ctx.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
 
     ResumeThread(thread);
     WaitForSingleObject(thread, 10000);
diff --git a/server/ptrace.c b/server/ptrace.c
index 7de506b..a647df9 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -545,6 +545,8 @@ void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
 /* initialize registers in new thread if necessary */
 void init_thread_context( struct thread *thread )
 {
+    /* Linux doesn't clear all registers, but hopefully enough to avoid spurious breakpoints */
+    thread->system_regs = 0;
 }
 
 /* retrieve the thread x86 registers */
@@ -558,6 +560,13 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int
 
     if (!suspend_for_ptrace( thread )) return;
 
+    if (!(thread->system_regs & SERVER_CTX_DEBUG_REGISTERS))
+    {
+        /* caller has initialized everything to 0 already, just return */
+        context->flags |= SERVER_CTX_DEBUG_REGISTERS;
+        goto done;
+    }
+
     for (i = 0; i < 8; i++)
     {
         if (i == 4 || i == 5) continue;
@@ -625,6 +634,7 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
         ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 | 0x55 );
         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.i386_regs.dr7 ) == -1) goto error;
         if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7;
+        thread->system_regs |= SERVER_CTX_DEBUG_REGISTERS;
         break;
     case CPU_x86_64:
         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 & 0xffff0000 ) == -1) goto error;
@@ -641,6 +651,7 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
         ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 | 0x55 );
         if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 ) == -1) goto error;
         if (thread->context) thread->context->debug.x86_64_regs.dr7 = context->debug.x86_64_regs.dr7;
+        thread->system_regs |= SERVER_CTX_DEBUG_REGISTERS;
         break;
     default:
         set_error( STATUS_INVALID_PARAMETER );
@@ -660,6 +671,18 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
 /* initialize registers in new thread if necessary */
 void init_thread_context( struct thread *thread )
 {
+    if (!(thread->system_regs & SERVER_CTX_DEBUG_REGISTERS)) return;
+
+    /* FreeBSD doesn't clear the debug registers in new threads */
+    if (suspend_for_ptrace( thread ))
+    {
+        struct dbreg dbregs;
+
+        memset( &dbregs, 0, sizeof(dbregs) );
+        ptrace( PTRACE_SETDBREGS, get_ptrace_tid( thread ), (caddr_t)&dbregs, 0 );
+        resume_after_ptrace( thread );
+    }
+    thread->system_regs = 0;
 }
 
 /* retrieve the thread x86 registers */
@@ -728,9 +751,14 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
     dbregs.dr6 = context->debug.i386_regs.dr6;
     dbregs.dr7 = context->debug.i386_regs.dr7;
 #endif
-    if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error();
-    else if (thread->context)
-        thread->context->debug.i386_regs = context->debug.i386_regs;  /* update the cached values */
+    if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t)&dbregs, 0 ) != -1)
+    {
+        if (thread->context)
+            thread->context->debug.i386_regs = context->debug.i386_regs;  /* update the cached values */
+        thread->system_regs |= SERVER_CTX_DEBUG_REGISTERS;
+    }
+    else file_set_error();
+
     resume_after_ptrace( thread );
 }
 
diff --git a/server/thread.c b/server/thread.c
index 24e9af5..903420b 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -182,6 +182,7 @@ static inline void init_thread_structure( struct thread *thread )
     thread->debug_ctx       = NULL;
     thread->debug_event     = NULL;
     thread->debug_break     = 0;
+    thread->system_regs     = 0;
     thread->queue           = NULL;
     thread->wait            = NULL;
     thread->error           = 0;
@@ -1245,6 +1246,7 @@ DECL_HANDLER(new_thread)
 
     if ((thread = create_thread( request_fd, current->process )))
     {
+        thread->system_regs = current->system_regs;
         if (req->suspend) thread->suspend++;
         reply->tid = get_thread_id( thread );
         if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes )))
diff --git a/server/thread.h b/server/thread.h
index 2fdfd66..1d81d61 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -57,6 +57,7 @@ struct thread
     struct debug_ctx      *debug_ctx;     /* debugger context if this thread is a debugger */
     struct debug_event    *debug_event;   /* debug event being sent to debugger */
     int                    debug_break;   /* debug breakpoint pending? */
+    unsigned int           system_regs;   /* which system regs have been set */
     struct msg_queue      *queue;         /* message queue */
     struct thread_wait    *wait;          /* current wait condition if sleeping */
     struct list            system_apc;    /* queue of system async procedure calls */




More information about the wine-cvs mailing list