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
|
@ -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>
|
2011-12-13 Yao Qi <yao@codesourcery.com>
|
||||||
|
|
||||||
* tracepoint.c (trace_buffer_alloc): Replace magic numbers with
|
* 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;
|
CORE_ADDR addr = 0;
|
||||||
int i;
|
int i;
|
||||||
int rc = 0;
|
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;
|
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;
|
unsigned control;
|
||||||
|
|
||||||
/* Get the current values the inferior has. If the thread was
|
/* In non-stop/async, threads can be running while we change the
|
||||||
running when we last changed watchpoints, the mirror no longer
|
global dr_mirror (and friends). Say, we set a watchpoint, and
|
||||||
represents what was set in this LWP's debug registers. */
|
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 ();
|
status = i386_dr_low_get_status ();
|
||||||
control = i386_dr_low_get_control ();
|
|
||||||
|
|
||||||
ALL_DEBUG_REGISTERS (i)
|
ALL_DEBUG_REGISTERS (i)
|
||||||
{
|
{
|
||||||
if (I386_DR_WATCH_HIT (status, i)
|
if (!I386_DR_WATCH_HIT (status, i))
|
||||||
/* This second condition makes sure DRi is set up for a data
|
continue;
|
||||||
watchpoint, not a hardware breakpoint. The reason is
|
|
||||||
that GDB doesn't call the target_stopped_data_address
|
if (!control_p)
|
||||||
method except for data watchpoints. In other words, I'm
|
{
|
||||||
being paranoiac. */
|
control = i386_dr_low_get_control ();
|
||||||
&& I386_DR_GET_RW_LEN (control, i) != 0)
|
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. */
|
||||||
|
if (I386_DR_GET_RW_LEN (control, i) != 0)
|
||||||
{
|
{
|
||||||
addr = i386_dr_low_get_addr (i);
|
addr = i386_dr_low_get_addr (i);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
|
|
|
@ -655,6 +655,7 @@ static void
|
||||||
x86_linux_prepare_to_resume (struct lwp_info *lwp)
|
x86_linux_prepare_to_resume (struct lwp_info *lwp)
|
||||||
{
|
{
|
||||||
ptid_t ptid = ptid_of (lwp);
|
ptid_t ptid = ptid_of (lwp);
|
||||||
|
int clear_status = 0;
|
||||||
|
|
||||||
if (lwp->arch_private->debug_registers_changed)
|
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;
|
= &proc->private->arch_private->debug_reg_state;
|
||||||
|
|
||||||
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
|
||||||
x86_linux_dr_set (ptid, i, state->dr_mirror[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);
|
x86_linux_dr_set (ptid, DR_CONTROL, state->dr_control_mirror);
|
||||||
|
|
||||||
lwp->arch_private->debug_registers_changed = 0;
|
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);
|
x86_linux_dr_set (ptid, DR_STATUS, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue