* linux-low.h (struct lwp_info): New fields

`stopped_by_watchpoint' and `stopped_data_address'.
	* linux-low.c (linux_wait_for_lwp): Check for watchpoint triggers
	here, and cache them in the lwp object.
	(wait_for_sigstop): Check stopped_by_watchpoint lwp field
	directly.
	(linux_resume_one_lwp): Clear the lwp's stopped_by_watchpoint
	field.
	(linux_stopped_by_watchpoint): Rewrite.
	(linux_stopped_data_address): Rewrite.
This commit is contained in:
Pedro Alves 2010-03-14 18:46:40 +00:00
parent 51f4c0b08e
commit c3adc08c6f
3 changed files with 76 additions and 9 deletions

View File

@ -1,3 +1,16 @@
2010-03-14 Pedro Alves <pedro@codesourcery.com>
* linux-low.h (struct lwp_info): New fields
`stopped_by_watchpoint' and `stopped_data_address'.
* linux-low.c (linux_wait_for_lwp): Check for watchpoint triggers
here, and cache them in the lwp object.
(wait_for_sigstop): Check stopped_by_watchpoint lwp field
directly.
(linux_resume_one_lwp): Clear the lwp's stopped_by_watchpoint
field.
(linux_stopped_by_watchpoint): Rewrite.
(linux_stopped_data_address): Rewrite.
2010-03-06 Simo Melenius <simo.melenius@iki.fi>
* linux-low.c (linux_wait_for_lwp): Fetch the regcache after

View File

@ -1062,6 +1062,51 @@ retry:
new_inferior = 0;
}
/* Fetch the possibly triggered data watchpoint info and store it in
CHILD.
On some archs, like x86, that use debug registers to set
watchpoints, it's possible that the way to know which watched
address trapped, is to check the register that is used to select
which address to watch. Problem is, between setting the
watchpoint and reading back which data address trapped, the user
may change the set of watchpoints, and, as a consequence, GDB
changes the debug registers in the inferior. To avoid reading
back a stale stopped-data-address when that happens, we cache in
LP the fact that a watchpoint trapped, and the corresponding data
address, as soon as we see CHILD stop with a SIGTRAP. If GDB
changes the debug registers meanwhile, we have the cached data we
can rely on. */
if (WIFSTOPPED (*wstatp) && WSTOPSIG (*wstatp) == SIGTRAP)
{
if (the_low_target.stopped_by_watchpoint == NULL)
{
child->stopped_by_watchpoint = 0;
}
else
{
struct thread_info *saved_inferior;
saved_inferior = current_inferior;
current_inferior = get_lwp_thread (child);
child->stopped_by_watchpoint
= the_low_target.stopped_by_watchpoint ();
if (child->stopped_by_watchpoint)
{
if (the_low_target.stopped_data_address != NULL)
child->stopped_data_address
= the_low_target.stopped_data_address ();
else
child->stopped_data_address = 0;
}
current_inferior = saved_inferior;
}
}
if (debug_threads
&& WIFSTOPPED (*wstatp)
&& the_low_target.get_pc != NULL)
@ -1724,7 +1769,7 @@ wait_for_sigstop (struct inferior_list_entry *entry)
signal. */
if (WSTOPSIG (wstat) == SIGTRAP
&& lwp->stepping
&& !linux_stopped_by_watchpoint ())
&& !lwp->stopped_by_watchpoint)
{
if (debug_threads)
fprintf (stderr, " single-step SIGTRAP ignored\n");
@ -1878,6 +1923,7 @@ linux_resume_one_lwp (struct lwp_info *lwp,
get_lwp_thread (lwp));
errno = 0;
lwp->stopped = 0;
lwp->stopped_by_watchpoint = 0;
lwp->stepping = step;
ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp), 0,
/* Coerce to a uintptr_t first to avoid potential gcc warning
@ -2817,19 +2863,17 @@ linux_remove_point (char type, CORE_ADDR addr, int len)
static int
linux_stopped_by_watchpoint (void)
{
if (the_low_target.stopped_by_watchpoint != NULL)
return the_low_target.stopped_by_watchpoint ();
else
return 0;
struct lwp_info *lwp = get_thread_lwp (current_inferior);
return lwp->stopped_by_watchpoint;
}
static CORE_ADDR
linux_stopped_data_address (void)
{
if (the_low_target.stopped_data_address != NULL)
return the_low_target.stopped_data_address ();
else
return 0;
struct lwp_info *lwp = get_thread_lwp (current_inferior);
return lwp->stopped_data_address;
}
#if defined(__UCLIBC__) && defined(HAS_NOMMU)

View File

@ -161,6 +161,16 @@ struct lwp_info
int pending_is_breakpoint;
CORE_ADDR pending_stop_pc;
/* STOPPED_BY_WATCHPOINT is non-zero if this LWP stopped with a data
watchpoint trap. */
int stopped_by_watchpoint;
/* On architectures where it is possible to know the data address of
a triggered watchpoint, STOPPED_DATA_ADDRESS is non-zero, and
contains such data address. Only valid if STOPPED_BY_WATCHPOINT
is true. */
CORE_ADDR stopped_data_address;
/* If this is non-zero, it is a breakpoint to be reinserted at our next
stop (SIGTRAP stops only). */
CORE_ADDR bp_reinsert;