aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2010-03-14 18:46:40 +0000
committerPedro Alves <palves@redhat.com>2010-03-14 18:46:40 +0000
commitc3adc08c6f4fb5f67d49946d4c45e50b842b1d83 (patch)
tree0b8f77bb139aa7efba2a5e48576cde8eee98721d /gdb
parent51f4c0b08eed762435b7aa6c1784ade7ab20165c (diff)
downloadgdb-c3adc08c6f4fb5f67d49946d4c45e50b842b1d83.zip
gdb-c3adc08c6f4fb5f67d49946d4c45e50b842b1d83.tar.gz
gdb-c3adc08c6f4fb5f67d49946d4c45e50b842b1d83.tar.bz2
* 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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/gdbserver/ChangeLog13
-rw-r--r--gdb/gdbserver/linux-low.c62
-rw-r--r--gdb/gdbserver/linux-low.h10
3 files changed, 76 insertions, 9 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 27af34e..f2e39fd 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -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
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 6499ca7..31ee6e9 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -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)
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 82ad00c..82f29d8 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -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;