From: Joel Brobecker Date: Tue, 14 Oct 2014 21:18:35 +0000 (+0200) Subject: state->dr_control_mirror == 0 failed assertion in gdbserver on Windows XP X-Git-Tag: gdb-7.8.1-release~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a70c6d64c936f981640b8e3315ddadb141af7aad;p=thirdparty%2Fbinutils-gdb.git state->dr_control_mirror == 0 failed assertion in gdbserver on Windows XP When using GDBserver on Windows XP, GDBserver reports an assertion failure after hitting a hardware watchpoint. The problem was reproduced using the sources from gdb.ada/int_deref, but should probably reproduce with any scenario involving hardware watchpoints. In our scenario, we break on line 5, just before the increment, insert a watchhpoint on it, and then continue: (gdb) b foo.adb:5 Breakpoint 1 at 0x4017c2: file foo.adb, line 5. (gdb) cont Continuing. Breakpoint 1, foo () at foo.adb:5 5 Pck.Watch := Pck.Watch + 1; (gdb) watch watch Hardware watchpoint 2: watch (gdb) c Continuing. Remote communication error. Target disconnected.: Invalid argument. The immediate cause for the communication error is easily explained, gdbserver crashes due to a failed assertion: x86_remove_aligned_watchpoint: Assertion `state->dr_control_mirror == 0' failed. The assertion occurs because debug_reg_state.dr_control_mirror gets overwritten by the value read from the inferior, when processing the watchpoint event in win32_wait: win32_wait finds that we stopped, calls get_thread_regcache which causes i386_get_thread_context to get called, which then... if (th->tid == current_event->dwThreadId) { /* Copy dr values from the current thread. */ struct x86_debug_reg_state *dr = &debug_reg_state; [...] dr->dr_control_mirror = th->context.Dr7; } Both should be identical, normally making this a no-op, but it turns out that bits 12-11-10 are documented as being fixed and equal to 001. Our handling of dr_control_mirror does not manage those bits, and leaves them as zeros instead. So, when we overwrite the value from the thread's DR7 register, we accidentally set bit 10, causing state->dr_control_mirror to be 0x400 after we've cleared everything internally. This patch fixes the issue by removing the statement setting state->dr_control_mirror to the thread's DR7 register value. gdb/gdbserver/ChangeLog: PR server/17487 * win32-i386-low.c (i386_get_thread_context): Do not set dr->dr_control_mirror. --- diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index f6622489e97..62ca872b053 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,9 @@ +2014-10-15 Joel Brobecker + + PR server/17487 + * win32-i386-low.c (i386_get_thread_context): Do not set + dr->dr_control_mirror. + 2014-07-11 Pedro Alves * linux-low.c (kill_wait_lwp): New function, based on diff --git a/gdb/gdbserver/win32-i386-low.c b/gdb/gdbserver/win32-i386-low.c index 08242aa30f0..8ab1b73474a 100644 --- a/gdb/gdbserver/win32-i386-low.c +++ b/gdb/gdbserver/win32-i386-low.c @@ -212,7 +212,6 @@ i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event) dr->dr_mirror[2] = th->context.Dr2; dr->dr_mirror[3] = th->context.Dr3; dr->dr_status_mirror = th->context.Dr6; - dr->dr_control_mirror = th->context.Dr7; } }