diff options
author | Joel Brobecker <brobecker@adacore.com> | 2014-10-14 23:18:35 +0200 |
---|---|---|
committer | Joel Brobecker <brobecker@adacore.com> | 2014-10-15 07:27:54 -0700 |
commit | a70c6d64c936f981640b8e3315ddadb141af7aad (patch) | |
tree | 739311a5dcce98d42437a01321a1175cabd63a77 /gdb | |
parent | a39611f90c9a8ae50ab08c17e68af0490ab95352 (diff) | |
download | binutils-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/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/gdbserver/win32-i386-low.c | 1 |
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; } } |