summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@adacore.com>2014-10-14 23:18:35 +0200
committerJoel Brobecker <brobecker@adacore.com>2014-10-15 07:27:54 -0700
commita70c6d64c936f981640b8e3315ddadb141af7aad (patch)
tree739311a5dcce98d42437a01321a1175cabd63a77 /gdb
parenta39611f90c9a8ae50ab08c17e68af0490ab95352 (diff)
downloadbinutils-gdb-a70c6d64c936f981640b8e3315ddadb141af7aad.tar.gz
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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/gdbserver/ChangeLog6
-rw-r--r--gdb/gdbserver/win32-i386-low.c1
2 files changed, 6 insertions, 1 deletions
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 <brobecker@adacore.com>
+
+ PR server/17487
+ * win32-i386-low.c (i386_get_thread_context): Do not set
+ dr->dr_control_mirror.
+
2014-07-11 Pedro Alves <palves@redhat.com>
* 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;
}
}