Commit abe0b1c5 authored by Alexandre Julliard's avatar Alexandre Julliard

server: Initialize debug registers in new threads if necessary.

parent 9a07d210
...@@ -904,7 +904,7 @@ static void test_exceptions(void) ...@@ -904,7 +904,7 @@ static void test_exceptions(void)
res = pNtGetContextThread( h, &ctx ); res = pNtGetContextThread( h, &ctx );
ok( res == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", res ); ok( res == STATUS_SUCCESS, "NtGetContextThread failed with %x\n", res );
ok( ctx.Dr0 == 0, "dr0 %x\n", ctx.Dr0 ); 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.Dr0 = (DWORD)code_mem;
ctx.Dr7 = 3; ctx.Dr7 = 3;
res = pNtSetContextThread( h, &ctx ); res = pNtSetContextThread( h, &ctx );
...@@ -2168,8 +2168,8 @@ static DWORD WINAPI register_check_thread(void *arg) ...@@ -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.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1);
ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2); ok(!ctx.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3); 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); 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.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
return 0; return 0;
} }
...@@ -2238,8 +2238,8 @@ static void test_debug_registers(void) ...@@ -2238,8 +2238,8 @@ static void test_debug_registers(void)
ok(!ctx.Dr1, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr1); 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.Dr2, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr2);
ok(!ctx.Dr3, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr3); 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); 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.Dr7, "expected 0, got %lx\n", (DWORD_PTR)ctx.Dr7);
ResumeThread(thread); ResumeThread(thread);
WaitForSingleObject(thread, 10000); WaitForSingleObject(thread, 10000);
......
...@@ -545,6 +545,8 @@ void get_selector_entry( struct thread *thread, int entry, unsigned int *base, ...@@ -545,6 +545,8 @@ void get_selector_entry( struct thread *thread, int entry, unsigned int *base,
/* initialize registers in new thread if necessary */ /* initialize registers in new thread if necessary */
void init_thread_context( struct thread *thread ) 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 */ /* retrieve the thread x86 registers */
...@@ -558,6 +560,13 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int ...@@ -558,6 +560,13 @@ void get_thread_context( struct thread *thread, context_t *context, unsigned int
if (!suspend_for_ptrace( thread )) return; 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++) for (i = 0; i < 8; i++)
{ {
if (i == 4 || i == 5) continue; if (i == 4 || i == 5) continue;
...@@ -625,6 +634,7 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign ...@@ -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 ); 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 (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; if (thread->context) thread->context->debug.i386_regs.dr7 = context->debug.i386_regs.dr7;
thread->system_regs |= SERVER_CTX_DEBUG_REGISTERS;
break; break;
case CPU_x86_64: case CPU_x86_64:
if (ptrace( PTRACE_POKEUSER, pid, DR_OFFSET(7), context->debug.x86_64_regs.dr7 & 0xffff0000 ) == -1) goto error; 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 ...@@ -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 ); 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 (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; if (thread->context) thread->context->debug.x86_64_regs.dr7 = context->debug.x86_64_regs.dr7;
thread->system_regs |= SERVER_CTX_DEBUG_REGISTERS;
break; break;
default: default:
set_error( STATUS_INVALID_PARAMETER ); set_error( STATUS_INVALID_PARAMETER );
...@@ -660,6 +671,18 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign ...@@ -660,6 +671,18 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
/* initialize registers in new thread if necessary */ /* initialize registers in new thread if necessary */
void init_thread_context( struct thread *thread ) 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 */ /* retrieve the thread x86 registers */
...@@ -728,9 +751,14 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign ...@@ -728,9 +751,14 @@ void set_thread_context( struct thread *thread, const context_t *context, unsign
dbregs.dr6 = context->debug.i386_regs.dr6; dbregs.dr6 = context->debug.i386_regs.dr6;
dbregs.dr7 = context->debug.i386_regs.dr7; dbregs.dr7 = context->debug.i386_regs.dr7;
#endif #endif
if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t) &dbregs, 0 ) == -1) file_set_error(); if (ptrace( PTRACE_SETDBREGS, pid, (caddr_t)&dbregs, 0 ) != -1)
else if (thread->context) {
thread->context->debug.i386_regs = context->debug.i386_regs; /* update the cached values */ 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 ); resume_after_ptrace( thread );
} }
......
...@@ -182,6 +182,7 @@ static inline void init_thread_structure( struct thread *thread ) ...@@ -182,6 +182,7 @@ static inline void init_thread_structure( struct thread *thread )
thread->debug_ctx = NULL; thread->debug_ctx = NULL;
thread->debug_event = NULL; thread->debug_event = NULL;
thread->debug_break = 0; thread->debug_break = 0;
thread->system_regs = 0;
thread->queue = NULL; thread->queue = NULL;
thread->wait = NULL; thread->wait = NULL;
thread->error = 0; thread->error = 0;
...@@ -1245,6 +1246,7 @@ DECL_HANDLER(new_thread) ...@@ -1245,6 +1246,7 @@ DECL_HANDLER(new_thread)
if ((thread = create_thread( request_fd, current->process ))) if ((thread = create_thread( request_fd, current->process )))
{ {
thread->system_regs = current->system_regs;
if (req->suspend) thread->suspend++; if (req->suspend) thread->suspend++;
reply->tid = get_thread_id( thread ); reply->tid = get_thread_id( thread );
if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes ))) if ((reply->handle = alloc_handle( current->process, thread, req->access, req->attributes )))
......
...@@ -57,6 +57,7 @@ struct thread ...@@ -57,6 +57,7 @@ struct thread
struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */ struct debug_ctx *debug_ctx; /* debugger context if this thread is a debugger */
struct debug_event *debug_event; /* debug event being sent to debugger */ struct debug_event *debug_event; /* debug event being sent to debugger */
int debug_break; /* debug breakpoint pending? */ int debug_break; /* debug breakpoint pending? */
unsigned int system_regs; /* which system regs have been set */
struct msg_queue *queue; /* message queue */ struct msg_queue *queue; /* message queue */
struct thread_wait *wait; /* current wait condition if sleeping */ struct thread_wait *wait; /* current wait condition if sleeping */
struct list system_apc; /* queue of system async procedure calls */ struct list system_apc; /* queue of system async procedure calls */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment