Alexandre Julliard : server: Initialize debug registers in new threads if necessary.
Module: wine Branch: master Commit: abe0b1c57bbe9a952e55d4f821073b0a5197d746 URL: http://source.winehq.org/git/wine.git/?a=commit;h=abe0b1c57bbe9a952e55d4f821... Author: Alexandre Julliard <julliard(a)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(a)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 */
participants (1)
-
Alexandre Julliard