+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
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)
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");
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
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)
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;