* linux-low.h (struct lwp_info): New fields
authorPedro Alves <palves@redhat.com>
Sun, 14 Mar 2010 18:46:40 +0000 (18:46 +0000)
committerPedro Alves <palves@redhat.com>
Sun, 14 Mar 2010 18:46:40 +0000 (18:46 +0000)
`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.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h

index 27af34e8fa789b1ac45b08abbd2df77bc5ed10a3..f2e39fd64a9b58e4380b739aa949f07163712927 100644 (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
index 6499ca7e52e0aca7efad979ca8805a1f09c12f60..31ee6e95a27406280a558bb55fd4921c8c19d4e5 100644 (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)
index 82ad00c256fbf5471972adc4c7e30a2b548e125f..82f29d8dd6d04638ced7c32ffd4e10c3a7c0370e 100644 (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;