2011-12-13 Pedro Alves <pedro@codesourcery.com>
PR remote/13492 * i386-low.c (i386_low_stopped_data_address): Avoid fetching DR_CONTROL unless necessary. Extend comments. * linux-x86-low.c (x86_linux_prepare_to_resume): Don't write to DR0-3 if not used. If any watchpoint was set, clear DR_STATUS.
This commit is contained in:
parent
fabde4854c
commit
6210a125f8
3 changed files with 68 additions and 13 deletions
|
@ -1,3 +1,12 @@
|
|||
2011-12-13 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
PR remote/13492
|
||||
|
||||
* i386-low.c (i386_low_stopped_data_address): Avoid fetching
|
||||
DR_CONTROL unless necessary. Extend comments.
|
||||
* linux-x86-low.c (x86_linux_prepare_to_resume): Don't write to
|
||||
DR0-3 if not used. If any watchpoint was set, clear DR_STATUS.
|
||||
|
||||
2011-12-13 Yao Qi <yao@codesourcery.com>
|
||||
|
||||
* tracepoint.c (trace_buffer_alloc): Replace magic numbers with
|
||||
|
|
|
@ -559,24 +559,60 @@ i386_low_stopped_data_address (struct i386_debug_reg_state *state,
|
|||
CORE_ADDR addr = 0;
|
||||
int i;
|
||||
int rc = 0;
|
||||
/* The current thread's DR_STATUS. We always need to read this to
|
||||
check whether some watchpoint caused the trap. */
|
||||
unsigned status;
|
||||
/* We need DR_CONTROL as well, but only iff DR_STATUS indicates a
|
||||
data breakpoint trap. Only fetch it when necessary, to avoid an
|
||||
unnecessary extra syscall when no watchpoint triggered. */
|
||||
int control_p = 0;
|
||||
unsigned control;
|
||||
|
||||
/* Get the current values the inferior has. If the thread was
|
||||
running when we last changed watchpoints, the mirror no longer
|
||||
represents what was set in this LWP's debug registers. */
|
||||
/* In non-stop/async, threads can be running while we change the
|
||||
global dr_mirror (and friends). Say, we set a watchpoint, and
|
||||
let threads resume. Now, say you delete the watchpoint, or
|
||||
add/remove watchpoints such that dr_mirror changes while threads
|
||||
are running. On targets that support non-stop,
|
||||
inserting/deleting watchpoints updates the global dr_mirror only.
|
||||
It does not update the real thread's debug registers; that's only
|
||||
done prior to resume. Instead, if threads are running when the
|
||||
mirror changes, a temporary and transparent stop on all threads
|
||||
is forced so they can get their copy of the debug registers
|
||||
updated on re-resume. Now, say, a thread hit a watchpoint before
|
||||
having been updated with the new dr_mirror contents, and we
|
||||
haven't yet handled the corresponding SIGTRAP. If we trusted
|
||||
dr_mirror below, we'd mistake the real trapped address (from the
|
||||
last time we had updated debug registers in the thread) with
|
||||
whatever was currently in dr_mirror. So to fix this, dr_mirror
|
||||
always represents intention, what we _want_ threads to have in
|
||||
debug registers. To get at the address and cause of the trap, we
|
||||
need to read the state the thread still has in its debug
|
||||
registers.
|
||||
|
||||
In sum, always get the current debug register values the current
|
||||
thread has, instead of trusting the global mirror. If the thread
|
||||
was running when we last changed watchpoints, the mirror no
|
||||
longer represents what was set in this thread's debug
|
||||
registers. */
|
||||
status = i386_dr_low_get_status ();
|
||||
control = i386_dr_low_get_control ();
|
||||
|
||||
ALL_DEBUG_REGISTERS (i)
|
||||
{
|
||||
if (I386_DR_WATCH_HIT (status, i)
|
||||
if (!I386_DR_WATCH_HIT (status, i))
|
||||
continue;
|
||||
|
||||
if (!control_p)
|
||||
{
|
||||
control = i386_dr_low_get_control ();
|
||||
control_p = 1;
|
||||
}
|
||||
|
||||
/* This second condition makes sure DRi is set up for a data
|
||||
watchpoint, not a hardware breakpoint. The reason is
|
||||
that GDB doesn't call the target_stopped_data_address
|
||||
method except for data watchpoints. In other words, I'm
|
||||
being paranoiac. */
|
||||
&& I386_DR_GET_RW_LEN (control, i) != 0)
|
||||
watchpoint, not a hardware breakpoint. The reason is that
|
||||
GDB doesn't call the target_stopped_data_address method
|
||||
except for data watchpoints. In other words, I'm being
|
||||
paranoiac. */
|
||||
if (I386_DR_GET_RW_LEN (control, i) != 0)
|
||||
{
|
||||
addr = i386_dr_low_get_addr (i);
|
||||
rc = 1;
|
||||
|
|
|
@ -655,6 +655,7 @@ static void
|
|||
x86_linux_prepare_to_resume (struct lwp_info *lwp)
|
||||
{
|
||||
ptid_t ptid = ptid_of (lwp);
|
||||
int clear_status = 0;
|
||||
|
||||
if (lwp->arch_private->debug_registers_changed)
|
||||
{
|
||||
|
@ -665,14 +666,23 @@ x86_linux_prepare_to_resume (struct lwp_info *lwp)
|
|||
= &proc->private->arch_private->debug_reg_state;
|
||||
|
||||
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
||||
if (state->dr_ref_count[i] > 0)
|
||||
{
|
||||
x86_linux_dr_set (ptid, i, state->dr_mirror[i]);
|
||||
|
||||
/* If we're setting a watchpoint, any change the inferior
|
||||
had done itself to the debug registers needs to be
|
||||
discarded, otherwise, i386_low_stopped_data_address can
|
||||
get confused. */
|
||||
clear_status = 1;
|
||||
}
|
||||
|
||||
x86_linux_dr_set (ptid, DR_CONTROL, state->dr_control_mirror);
|
||||
|
||||
lwp->arch_private->debug_registers_changed = 0;
|
||||
}
|
||||
|
||||
if (lwp->stopped_by_watchpoint)
|
||||
if (clear_status || lwp->stopped_by_watchpoint)
|
||||
x86_linux_dr_set (ptid, DR_STATUS, 0);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue