public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
@ 2011-12-05 16:46 Pedro Alves
  2011-12-05 17:06 ` Eli Zaretskii
  2011-12-05 21:24 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil
  0 siblings, 2 replies; 37+ messages in thread
From: Pedro Alves @ 2011-12-05 16:46 UTC (permalink / raw)
  To: gdb-patches

On native x86 targets, the desired state of hardware watchpoints is
kept on a local mirror of the inferior's debug registers, and copied
to each thread whenever the mirror changes.  If any of the threads
being copied to are currently running, the copying fails with an ugly
error.

GDBserver solves this by instead only updating the threads' debug
registers prior to resume, and, when the local mirror changes, forcing
a temporary and transparent stop on running threads, so they can
update the debug registers when re-resumed.  When deciding whether an
LWP stopped due to a hardware watchpoint or breakpoint, the current
state of the debug registers in the stopping thread is read, rather
than trusting the mirror still mirrors what was last copied to the
thread.

This patch matches teaches linux-nat.c to do the same as
GDBserver.

I suspect this change gets rid of a couple of workarounds we had in
place (e.g., i386_stopped_data_address), so I removed them --
GDBserver didn't have them.  No regressions popped up.

I have tested this on x86_64-linux (-m64|-m32), which showed no
regressions.  The patch also adjusts all other users of i396-nat.c:
djgpp/go32; i386 BSDs (FreeBSD only it seems); Windows (cygwin/mingw)
and macosx (darwin), but I haven't tested those.  I'd appreciate
testing or an extra pair of eyes.

Actually darwin has the i386 watchpoint hooks in place, but it doesn't
install them:

 $ grep i386_darwin_dr_get_status *
 i386-darwin-nat.c:i386_darwin_dr_get_status (void)
 $

??

This is necessary to fix a bunch of watchpoints regressions with my
all-stop on top of non-stop patches, as with those, we're not stopping
all threads at every internal event, and end up trying to install new
watchpoint locations with some threads still running.

P.S.:
GDBserver also supports multi-process watchpoints, but I left that
out of this patch.  It's now mostly just a matter of fixing:

/* The local mirror of the inferior's debug registers.  Currently this
   is a global, but it should really be per-inferior.  */
static struct i386_debug_reg_state dr_mirror;

2011-12-05  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* linux-nat.c (linux_nat_new_thread): Change parameter to an lwp
	pointer.
	(linux_nat_prepare_to_resume): New global.
	(lwp_free): New.
	(purge_lwp_list): Use it.
	(add_lwp): Call linux_nat_new_thread even on the first LWP.
	Adjust to interface change.
	(delete_lwp): Call lwp_free instead of xfree.
	(resume_lwp, linux_nat_resume, linux_handle_syscall_trap)
	(linux_handle_extended_wait, linux_nat_filter_event)
	(linux_nat_filter_event): Call linux_nat_prepare_to_resume before
	resuming.
	(linux_stop_lwp): New.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.
	* linux-nat.h (struct arch_lwp_info): Forward declare.
	(struct lwp_info) <arch_private>: New field.
	(linux_stop_lwp): Declare.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.

	* i386-nat.c (DR_NADDR, DR_STATUS, DR_CONTROL)
	(struct i386_debug_reg_state): Move to i386-nat.h.
	(dr_mirror): Comment.
	(i386_debug_reg_state): New.
	(i386_update_inferior_debug_regs): Simplify.
	(i386_stopped_data_address): Use the debug register state from the
	inferior, not from the local cache.
	* i386-nat.h (struct i386_dr_low_type): Delete reset_addr and
	unset_status fields.  New get_addr and get_control fields.
	(DR_FIRSTADDR, DR_LASTADDR, DR_CONTROL): Moved from i386-nat.c.
	(DR_NADDR, DR_STATUS): New.
	(struct i386_debug_reg_state): Moved from i386-nat.c.

	* amd64-linux-nat.c (struct arch_lwp_info): New.
	(amd64_linux_dr): Delete global.
	(amd64_linux_dr_get_addr): New.
	(amd64_linux_dr_get_control): New.
	(amd64_linux_dr_unset_status): Delete.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_dr_reset_addr): Delete.
	(update_debug_registers_callback): New.
	(amd64_linux_dr_set_control): Reimplement.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_prepare_to_resume): New.
	(amd64_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_amd64_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	amd64_linux_dr_get_control as i386_dr_low.get_control.  Install
	amd64_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	amd64_linux_prepare_to_resume.
	* i386-darwin-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(i386_darwin_dr_reset_addr): Delete.
	(i386_darwin_dr_get_addr): New.
	(i386_darwin_dr_get_control): New.
	* i386-linux-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(struct arch_lwp_info): New.
	(i386_linux_dr): Delete global.
	(i386_linux_dr_set_control): Reimplement.
	(i386_linux_dr_get_addr): New.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_dr_get_control): New.
	(update_debug_registers_callback): New.
	(i386_linux_dr_unset_status): Delete.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_prepare_to_resume): New.
	(i386_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_i386_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386_linux_dr_get_control as i386_dr_low.get_control.  Install
	i386_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	i386_linux_prepare_to_resume.

	* go32-nat.c
	(go32_get_dr7, go32_get_dr): New.
	(init_go32_ops): No longer install i386_dr_low.reset_addr.
	Install go32_get_dr7 as i386_dr_low.get_control.  Install
	go32_get_dr as i386_dr_low.get_addr.
	* i386bsd-nat.c (i386bsd_dr_get): New.
	(i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_status): Use i386bsd_dr_get.
	(i386bsd_dr_get_control): New.
	* i386bsd-nat.h (i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_control): New.
	* i386fbsd-nat.c (_initialize_i386fbsd_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386bsd_dr_get_control as i386_dr_low.get_control.  Install
	i386bsd_dr_get_addr as i386_dr_low.get_addr.
	* windows-nat.c (init_windows_ops): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	cygwin_get_dr7 as i386_dr_low.get_control.  Install cygwin_get_dr
	as i386_dr_low.get_addr.
	(cygwin_get_dr): New.
	(cygwin_get_dr7): New.
---
 gdb/amd64-linux-nat.c |  121 +++++++++++++++++++++++++++++---------------
 gdb/go32-nat.c        |   25 +++++++++
 gdb/i386-darwin-nat.c |   31 +++--------
 gdb/i386-linux-nat.c  |  134 +++++++++++++++++++++++++++++--------------------
 gdb/i386-nat.c        |   63 ++++++-----------------
 gdb/i386-nat.h        |   42 +++++++++++++--
 gdb/i386bsd-nat.c     |   32 ++++++++----
 gdb/i386bsd-nat.h     |    4 +
 gdb/i386fbsd-nat.c    |    3 +
 gdb/linux-nat.c       |   63 +++++++++++++++++++++--
 gdb/linux-nat.h       |   14 +++++
 gdb/windows-nat.c     |   20 +++++++
 12 files changed, 356 insertions(+), 196 deletions(-)

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index c673965..9699f84 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -64,6 +64,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 
@@ -265,8 +273,6 @@ amd64_linux_store_inferior_registers (struct target_ops *ops,
 \f
 /* Support for debug registers.  */
 
-static unsigned long amd64_linux_dr[DR_CONTROL + 1];
-
 static unsigned long
 amd64_linux_dr_get (ptid_t ptid, int regnum)
 {
@@ -304,75 +310,105 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-amd64_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+amd64_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  amd64_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return amd64_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+amd64_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
 
-  amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+static unsigned long
+amd64_linux_dr_get_status (void)
+{
+  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
 
-static void
-amd64_linux_dr_reset_addr (int regnum)
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
 {
-  amd64_linux_dr_set_addr (regnum, 0);
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set DR_CONTROL to CONTROL in all LWPs of the current inferior.  */
 
-static unsigned long
-amd64_linux_dr_get_status (void)
+static void
+amd64_linux_dr_set_control (unsigned long control)
 {
-  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
 static void
-amd64_linux_dr_unset_status (unsigned long mask)
+amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  struct lwp_info *lp;
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
 
-  ALL_LWPS (lp)
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
+}
+
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
+
+static void
+amd64_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
-      
-      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
+      int i;
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
+
+      amd64_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
-}
 
+  if (lwp->stopped_by_watchpoint)
+    amd64_linux_dr_set (lwp->ptid, DR_STATUS, 0);
+}
 
 static void
-amd64_linux_new_thread (ptid_t ptid)
+amd64_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -785,9 +821,9 @@ _initialize_amd64_linux_nat (void)
 
   i386_dr_low.set_control = amd64_linux_dr_set_control;
   i386_dr_low.set_addr = amd64_linux_dr_set_addr;
-  i386_dr_low.reset_addr = amd64_linux_dr_reset_addr;
+  i386_dr_low.get_addr = amd64_linux_dr_get_addr;
   i386_dr_low.get_status = amd64_linux_dr_get_status;
-  i386_dr_low.unset_status = amd64_linux_dr_unset_status;
+  i386_dr_low.get_control = amd64_linux_dr_get_control;
   i386_set_debug_register_length (8);
 
   /* Override the GNU/Linux inferior startup hook.  */
@@ -804,4 +840,5 @@ _initialize_amd64_linux_nat (void)
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, amd64_linux_new_thread);
   linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup);
+  linux_nat_set_prepare_to_resume (t, amd64_linux_prepare_to_resume);
 }
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 8295adf..b650a94 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -801,6 +801,28 @@ go32_get_dr6 (void)
   return STATUS;
 }
 
+/* Get the value of the DR6 debug status register from the inferior.
+   Here we just return the value stored in D_REGS, as we've got it
+   from the last go32_wait call.  */
+static unsigned long
+go32_get_dr7 (void)
+{
+  return CONTROL;
+}
+
+/* Get the value of the DR debug register I from the inferior.  Here
+   we just return the value stored in D_REGS, as we've got it from the
+   last go32_wait call.  */
+
+static CORE_ADDR
+go32_get_dr (int i)
+{
+  if (i < 0 || i > 3)
+    internal_error (__FILE__, __LINE__, 
+		    _("Invalid register %d in go32_get_dr.\n"), i);
+  return D_REGS[i];
+}
+
 /* Put the device open on handle FD into either raw or cooked
    mode, return 1 if it was in raw mode, zero otherwise.  */
 
@@ -984,8 +1006,9 @@ init_go32_ops (void)
 
   i386_dr_low.set_control = go32_set_dr7;
   i386_dr_low.set_addr = go32_set_dr;
-  i386_dr_low.reset_addr = NULL;
   i386_dr_low.get_status = go32_get_dr6;
+  i386_dr_low.get_control = go32_get_dr7;
+  i386_dr_low.get_addr = go32_get_dr;
   i386_set_debug_register_length (4);
 
   go32_ops.to_magic = OPS_MAGIC;
diff --git a/gdb/i386-darwin-nat.c b/gdb/i386-darwin-nat.c
index 61e2e15..23f6a6d 100644
--- a/gdb/i386-darwin-nat.c
+++ b/gdb/i386-darwin-nat.c
@@ -263,23 +263,6 @@ i386_darwin_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers, boosted mostly from i386-linux-nat.c.  */
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
-
 static void
 i386_darwin_dr_set (int regnum, uint32_t value)
 {
@@ -410,12 +393,10 @@ i386_darwin_dr_set_addr (int regnum, CORE_ADDR addr)
   i386_darwin_dr_set (DR_FIRSTADDR + regnum, addr);
 }
 
-void
-i386_darwin_dr_reset_addr (int regnum)
+CORE_ADDR
+i386_darwin_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
-
-  i386_darwin_dr_set (DR_FIRSTADDR + regnum, 0L);
+  return i386_darwin_dr_get (regnum);
 }
 
 unsigned long
@@ -424,6 +405,12 @@ i386_darwin_dr_get_status (void)
   return i386_darwin_dr_get (DR_STATUS);
 }
 
+unsigned long
+i386_darwin_dr_get_control (void)
+{
+  return i386_darwin_dr_get (DR_CONTROL);
+}
+
 void
 darwin_check_osabi (darwin_inferior *inf, thread_t thread)
 {
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 7eb49ae..70a5919 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -47,22 +47,6 @@
 #include <sys/debugreg.h>
 #endif
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
@@ -83,6 +67,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 \f
@@ -651,8 +643,6 @@ i386_linux_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers.  */
 
-static unsigned long i386_linux_dr[DR_CONTROL + 1];
-
 /* Get debug register REGNUM value from only the one LWP of PTID.  */
 
 static unsigned long
@@ -692,74 +682,105 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-i386_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+i386_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  i386_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return i386_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+i386_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return i386_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
 
-  i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+static unsigned long
+i386_linux_dr_get_status (void)
+{
+  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
 
-static void
-i386_linux_dr_reset_addr (int regnum)
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
 {
-  i386_linux_dr_set_addr (regnum, 0);
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set DR_CONTROL to ADDR in all LWPs of the current inferior.  */
 
-static unsigned long
-i386_linux_dr_get_status (void)
+static void
+i386_linux_dr_set_control (unsigned long control)
 {
-  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
 static void
-i386_linux_dr_unset_status (unsigned long mask)
+i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  struct lwp_info *lp;
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
 
-  ALL_LWPS (lp)
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
+}
+
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
+
+static void
+i386_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
+      int i;
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	i386_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
 
-      value = i386_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      i386_linux_dr_set (lp->ptid, DR_STATUS, value);
+      i386_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
+
+  if (lwp->stopped_by_watchpoint)
+    i386_linux_dr_set (lwp->ptid, DR_STATUS, 0);
 }
 
 static void
-i386_linux_new_thread (ptid_t ptid)
+i386_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    i386_linux_dr_set (ptid, i, i386_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -978,9 +999,9 @@ _initialize_i386_linux_nat (void)
 
   i386_dr_low.set_control = i386_linux_dr_set_control;
   i386_dr_low.set_addr = i386_linux_dr_set_addr;
-  i386_dr_low.reset_addr = i386_linux_dr_reset_addr;
+  i386_dr_low.get_addr = i386_linux_dr_get_addr;
   i386_dr_low.get_status = i386_linux_dr_get_status;
-  i386_dr_low.unset_status = i386_linux_dr_unset_status;
+  i386_dr_low.get_control = i386_linux_dr_get_control;
   i386_set_debug_register_length (4);
 
   /* Override the default ptrace resume method.  */
@@ -999,4 +1020,5 @@ _initialize_i386_linux_nat (void)
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, i386_linux_new_thread);
+  linux_nat_set_prepare_to_resume (t, i386_linux_prepare_to_resume);
 }
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 568b79b..94306a1 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -43,11 +43,6 @@ struct i386_dr_low_type i386_dr_low;
 /* Support for 8-byte wide hw watchpoints.  */
 #define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8)
 
-/* Debug registers' indices.  */
-#define DR_NADDR	4	/* The number of debug address registers.  */
-#define DR_STATUS	6	/* Index of debug status register (DR6).  */
-#define DR_CONTROL	7	/* Index of debug control register (DR7).  */
-
 /* DR7 Debug Control register fields.  */
 
 /* How many bits to skip in DR7 to get to R/W and LEN fields.  */
@@ -158,23 +153,6 @@ struct i386_dr_low_type i386_dr_low;
 /* A macro to loop over all debug registers.  */
 #define ALL_DEBUG_REGISTERS(i)	for (i = 0; i < DR_NADDR; i++)
 
-
-/* Global state needed to track h/w watchpoints.  */
-
-struct i386_debug_reg_state
-{
-  /* Mirror the inferior's DRi registers.  We keep the status and
-     control registers separated because they don't hold addresses.
-     Note that since we can change these mirrors while threads are
-     running, we never trust them to explain a cause of a trap.
-     For that, we need to peek directly in the inferior registers.  */
-  CORE_ADDR dr_mirror[DR_NADDR];
-  unsigned dr_status_mirror, dr_control_mirror;
-
-  /* Reference counts for each debug register.  */
-  int dr_ref_count[DR_NADDR];
-};
-
 /* Clear the reference counts and forget everything we knew about the
    debug registers.  */
 
@@ -192,8 +170,16 @@ i386_init_dregs (struct i386_debug_reg_state *state)
   state->dr_status_mirror  = 0;
 }
 
+/* The local mirror of the inferior's debug registers.  Currently this
+   is a global, but it should really be per-inferior.  */
 static struct i386_debug_reg_state dr_mirror;
 
+struct i386_debug_reg_state *
+i386_debug_reg_state (void)
+{
+  return &dr_mirror;
+}
+
 /* Whether or not to print the mirrored debug registers.  */
 static int maint_show_dr;
 
@@ -513,22 +499,7 @@ i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state)
   ALL_DEBUG_REGISTERS (i)
     {
       if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (&dr_mirror, i))
-	{
-	  if (!I386_DR_VACANT (new_state, i))
-	    {
-	      i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
-
-	      /* Only a sanity check for leftover bits (set possibly only
-		 by inferior).  */
-	      if (i386_dr_low.unset_status)
-		i386_dr_low.unset_status (I386_DR_WATCH_MASK (i));
-	    }
-	  else
-	    {
-	      if (i386_dr_low.reset_addr)
-		i386_dr_low.reset_addr (i);
-	    }
-	}
+	i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
       else
 	gdb_assert (new_state->dr_mirror[i] == dr_mirror.dr_mirror[i]);
     }
@@ -636,11 +607,12 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
   int rc = 0;
   unsigned status;
   unsigned control;
-  struct i386_debug_reg_state *state = &dr_mirror;
 
-  dr_mirror.dr_status_mirror = i386_dr_low.get_status ();
-  status = dr_mirror.dr_status_mirror;
-  control = dr_mirror.dr_control_mirror;
+  /* Get the current values the inferior has.  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 ();
+  control = i386_dr_low.get_control ();
 
   ALL_DEBUG_REGISTERS(i)
     {
@@ -650,12 +622,9 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
 	     that GDB doesn't call the target_stopped_data_address
 	     method except for data watchpoints.  In other words, I'm
 	     being paranoiac.  */
-	  && I386_DR_GET_RW_LEN (control, i) != 0
-	  /* This third condition makes sure DRi is not vacant, this
-	     avoids false positives in windows-nat.c.  */
-	  && !I386_DR_VACANT (state, i))
+	  && I386_DR_GET_RW_LEN (control, i) != 0)
 	{
-	  addr = state->dr_mirror[i];
+	  addr = i386_dr_low.get_addr (i);
 	  rc = 1;
 	  if (maint_show_dr)
 	    i386_show_dr (&dr_mirror, "watchpoint_hit", addr, -1, hw_write);
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 819c6b8..1a75daa 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -53,31 +53,54 @@ extern void i386_use_watchpoints (struct target_ops *);
       set_addr                 -- put an address into one debug
 				  register for all LWPs
 
-      reset_addr               -- reset the address stored in
-				  one debug register for all LWPs
+      get_addr                 -- return the address in a given debug
+				  register of the current LWP
 
       get_status               -- return the value of the debug
 				  status (DR6) register for current LWP
 
-      unset_status             -- unset the specified bits of the debug
-				  status (DR6) register for all LWPs
+      get_control               -- return the value of the debug
+				  control (DR7) register for current LWP
 
    Additionally, the native file should set the debug_register_length
    field to 4 or 8 depending on the number of bytes used for
    deubg registers.  */
 
-struct i386_dr_low_type 
+struct i386_dr_low_type
   {
     void (*set_control) (unsigned long);
     void (*set_addr) (int, CORE_ADDR);
-    void (*reset_addr) (int);
+    CORE_ADDR (*get_addr) (int);
     unsigned long (*get_status) (void);
-    void (*unset_status) (unsigned long);
+    unsigned long (*get_control) (void);
     int debug_register_length;
   };
 
 extern struct i386_dr_low_type i386_dr_low;
 
+/* Debug registers' indices.  */
+#define DR_FIRSTADDR 0
+#define DR_LASTADDR  3
+#define DR_NADDR     4	/* The number of debug address registers.  */
+#define DR_STATUS    6	/* Index of debug status register (DR6).  */
+#define DR_CONTROL   7	/* Index of debug control register (DR7).  */
+
+/* Global state needed to track h/w watchpoints.  */
+
+struct i386_debug_reg_state
+{
+  /* Mirror the inferior's DRi registers.  We keep the status and
+     control registers separated because they don't hold addresses.
+     Note that since we can change these mirrors while threads are
+     running, we never trust them to explain a cause of a trap.
+     For that, we need to peek directly in the inferior registers.  */
+  CORE_ADDR dr_mirror[DR_NADDR];
+  unsigned dr_status_mirror, dr_control_mirror;
+
+  /* Reference counts for each debug register.  */
+  int dr_ref_count[DR_NADDR];
+};
+
 /* Use this function to set i386_dr_low debug_register_length field
    rather than setting it directly to check that the length is only
    set once.  It also enables the 'maint set/show show-debug-regs' 
@@ -89,4 +112,9 @@ extern void i386_set_debug_register_length (int len);
 
 extern void i386_cleanup_dregs (void);
 
+/* Return a pointer to the the local mirror of the inferior's debug
+   registers.  */
+
+extern struct i386_debug_reg_state *i386_debug_reg_state (void);
+
 #endif /* I386_NAT_H */
diff --git a/gdb/i386bsd-nat.c b/gdb/i386bsd-nat.c
index fcd772f..22c79e2 100644
--- a/gdb/i386bsd-nat.c
+++ b/gdb/i386bsd-nat.c
@@ -264,6 +264,18 @@ i386bsd_target (void)
 #define DBREG_DRX(d, x) ((&d->dr0)[x])
 #endif
 
+static unsigned long
+i386bsd_dr_get (ptid_t ptid, int regnum)
+{
+  struct dbreg dbregs;
+
+  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
+    perror_with_name (_("Couldn't read debug registers"));
+
+  return DBREG_DRX ((&dbregs), regnum);
+}
+
 static void
 i386bsd_dr_set (int regnum, unsigned int value)
 {
@@ -299,24 +311,22 @@ i386bsd_dr_set_addr (int regnum, CORE_ADDR addr)
   i386bsd_dr_set (regnum, addr);
 }
 
-void
-i386bsd_dr_reset_addr (int regnum)
+CORE_ADDR
+i386bsd_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= 4);
-
-  i386bsd_dr_set (regnum, 0);
+  return i386bsd_dr_get (inferior_ptid, regnum);
 }
 
 unsigned long
 i386bsd_dr_get_status (void)
 {
-  struct dbreg dbregs;
-
-  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
-	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't read debug registers"));
+  return i386bsd_dr_get (inferior_ptid, 6);
+}
 
-  return DBREG_DRX ((&dbregs), 6);
+unsigned long
+i386bsd_dr_get_control (void)
+{
+  return i386bsd_dr_get (inferior_ptid, 7);
 }
 
 #endif /* PT_GETDBREGS */
diff --git a/gdb/i386bsd-nat.h b/gdb/i386bsd-nat.h
index 1c27ed5..df0b0f3 100644
--- a/gdb/i386bsd-nat.h
+++ b/gdb/i386bsd-nat.h
@@ -32,8 +32,10 @@ extern void i386bsd_dr_set_control (unsigned long control);
 
 extern void i386bsd_dr_set_addr (int regnum, CORE_ADDR addr);
 
-extern void i386bsd_dr_reset_addr (int regnum);
+extern CORE_ADDR i386bsd_dr_get_addr (int regnum);
 
 extern unsigned long i386bsd_dr_get_status (void);
 
+extern unsigned long i386bsd_dr_get_control (void);
+
 #endif /* i386bsd-nat.h */
diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c
index ecc797e..52ae031 100644
--- a/gdb/i386fbsd-nat.c
+++ b/gdb/i386fbsd-nat.c
@@ -134,8 +134,9 @@ _initialize_i386fbsd_nat (void)
 
   i386_dr_low.set_control = i386bsd_dr_set_control;
   i386_dr_low.set_addr = i386bsd_dr_set_addr;
-  i386_dr_low.reset_addr = i386bsd_dr_reset_addr;
+  i386_dr_low.get_addr = i386bsd_dr_get_addr;
   i386_dr_low.get_status = i386bsd_dr_get_status;
+  i386_dr_low.get_control = i386bsd_dr_get_control;
   i386_set_debug_register_length (4);
 
 #endif /* HAVE_PT_GETDBREGS */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index d54f303..f62c4de 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -175,7 +175,10 @@ static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The method to call, if any, when a new thread is attached.  */
-static void (*linux_nat_new_thread) (ptid_t);
+static void (*linux_nat_new_thread) (struct lwp_info *);
+
+/* Hook to call prior to resuming a thread.  */
+static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
 
 /* The method to call, if any, when the siginfo object needs to be
    converted between the layout returned by ptrace, and the layout in
@@ -1073,6 +1076,15 @@ status_to_str (int status)
   return buf;
 }
 
+/* Destroy and free LP.  */
+
+static void
+lwp_free (struct lwp_info *lp)
+{
+  xfree (lp->arch_private);
+  xfree (lp);
+}
+
 /* Remove all LWPs belong to PID from the lwp list.  */
 
 static void
@@ -1093,7 +1105,7 @@ purge_lwp_list (int pid)
 	  else
 	    lpprev->next = lp->next;
 
-	  xfree (lp);
+	  lwp_free (lp);
 	}
       else
 	lpprev = lp;
@@ -1139,8 +1151,8 @@ add_lwp (ptid_t ptid)
   lp->next = lwp_list;
   lwp_list = lp;
 
-  if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
-    linux_nat_new_thread (ptid);
+  if (linux_nat_new_thread != NULL)
+    linux_nat_new_thread (lp);
 
   return lp;
 }
@@ -1166,7 +1178,7 @@ delete_lwp (ptid_t ptid)
   else
     lwp_list = lp->next;
 
-  xfree (lp);
+  lwp_free (lp);
 }
 
 /* Return a pointer to the structure describing the LWP corresponding
@@ -1825,6 +1837,8 @@ resume_lwp (struct lwp_info *lp, int step)
 				"RC:  PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
 				target_pid_to_str (lp->ptid));
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops,
 				pid_to_ptid (GET_LWP (lp->ptid)),
 				step, TARGET_SIGNAL_0);
@@ -1969,6 +1983,8 @@ linux_nat_resume (struct target_ops *ops,
   /* Convert to something the lower layer understands.  */
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
   lp->stopped_by_watchpoint = 0;
@@ -2138,6 +2154,8 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
   /* Note that gdbarch_get_syscall_number may access registers, hence
      fill a regcache.  */
   registers_changed ();
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			lp->step, TARGET_SIGNAL_0);
   return 1;
@@ -2325,6 +2343,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 		    fprintf_unfiltered (gdb_stdlog,
 					"LHEW: resuming new LWP %ld\n",
 					GET_LWP (new_lp->ptid));
+		  if (linux_nat_prepare_to_resume != NULL)
+		    linux_nat_prepare_to_resume (new_lp);
 		  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
 					0, TARGET_SIGNAL_0);
 		  new_lp->stopped = 0;
@@ -2334,6 +2354,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	  if (debug_linux_nat)
 	    fprintf_unfiltered (gdb_stdlog,
 				"LHEW: resuming parent LWP %d\n", pid);
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				0, TARGET_SIGNAL_0);
 
@@ -2597,6 +2619,14 @@ stop_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+/* Request a stop on LWP.  */
+
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+  stop_callback (lwp, NULL);
+}
+
 /* Return non-zero if LWP PID has a pending SIGINT.  */
 
 static int
@@ -3333,6 +3363,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
 
 	  registers_changed ();
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
 	  if (debug_linux_nat)
@@ -3364,6 +3396,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
       lp->ignore_sigint = 0;
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3538,6 +3572,8 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3787,6 +3823,8 @@ retry:
 	     newly attached threads may cause an unwanted delay in
 	     getting them running.  */
 	  registers_changed ();
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				lp->step, signo);
 	  if (debug_linux_nat)
@@ -3939,6 +3977,8 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
 			    "RSRL: resuming stopped-resumed LWP %s\n",
 			    target_pid_to_str (lp->ptid));
 
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       lp->stopped = 0;
@@ -5836,7 +5876,8 @@ linux_nat_add_target (struct target_ops *t)
 
 /* Register a method to call whenever a new thread is attached.  */
 void
-linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+linux_nat_set_new_thread (struct target_ops *t,
+			  void (*new_thread) (struct lwp_info *))
 {
   /* Save the pointer.  We only support a single registered instance
      of the GNU/Linux native target, so we do not need to map this to
@@ -5857,6 +5898,16 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
   linux_nat_siginfo_fixup = siginfo_fixup;
 }
 
+/* Register a method to call prior to resuming a thread.  */
+
+void
+linux_nat_set_prepare_to_resume (struct target_ops *t,
+				 void (*prepare_to_resume) (struct lwp_info *))
+{
+  /* Save the pointer.  */
+  linux_nat_prepare_to_resume = prepare_to_resume;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 1fa94ce..33727d6 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -22,6 +22,8 @@
 
 #include <signal.h>
 
+struct arch_lwp_info;
+
 /* Ways to "resume" a thread.  */
 
 enum resume_kind
@@ -109,6 +111,9 @@ struct lwp_info
   /* The processor core this LWP was last seen on.  */
   int core;
 
+  /* Arch-specific additions.  */
+  struct arch_lwp_info *arch_private;
+
   /* Next LWP in list.  */
   struct lwp_info *next;
 };
@@ -146,6 +151,8 @@ extern void linux_enable_event_reporting (ptid_t ptid);
 
 extern int lin_lwp_attach_lwp (ptid_t ptid);
 
+extern void linux_stop_lwp (struct lwp_info *lwp);
+
 /* Iterator function for lin-lwp's lwp list.  */
 struct lwp_info *iterate_over_lwps (ptid_t filter,
 				    int (*callback) (struct lwp_info *,
@@ -166,7 +173,7 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int));
 void linux_nat_add_target (struct target_ops *);
 
 /* Register a method to call whenever a new thread is attached.  */
-void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t));
+void linux_nat_set_new_thread (struct target_ops *, void (*) (struct lwp_info *));
 
 /* Register a method that converts a siginfo object between the layout
    that ptrace returns, and the layout in the architecture of the
@@ -176,6 +183,11 @@ void linux_nat_set_siginfo_fixup (struct target_ops *,
 					   gdb_byte *,
 					   int));
 
+/* Register a method to call prior to resuming a thread.  */
+
+void linux_nat_set_prepare_to_resume (struct target_ops *,
+				      void (*) (struct lwp_info *));
+
 /* Update linux-nat internal state when changing from one fork
    to another.  */
 void linux_nat_switch_fork (ptid_t new_ptid);
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 20e3c67..7781276 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2494,8 +2494,9 @@ init_windows_ops (void)
 
   i386_dr_low.set_control = cygwin_set_dr7;
   i386_dr_low.set_addr = cygwin_set_dr;
-  i386_dr_low.reset_addr = NULL;
+  i386_dr_low.get_addr = cygwin_get_dr;
   i386_dr_low.get_status = cygwin_get_dr6;
+  i386_dr_low.get_control = cygwin_get_dr7;
 
   /* i386_dr_low.debug_register_length field is set by
      calling i386_set_debug_register_length function
@@ -2627,6 +2628,14 @@ cygwin_set_dr7 (unsigned long val)
   debug_registers_used = 1;
 }
 
+/* Get the value of debug register I from the inferior.  */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+  return dr[i];
+}
+
 /* Get the value of the DR6 debug status register from the inferior.
    Here we just return the value stored in dr[6]
    by the last call to thread_rec for current_event.dwThreadId id.  */
@@ -2636,6 +2645,15 @@ cygwin_get_dr6 (void)
   return (unsigned long) dr[6];
 }
 
+/* Get the value of the DR6 debug status register from the inferior.
+   Here we just return the value stored in dr[6]
+   by the last call to thread_rec for current_event.dwThreadId id.  */
+static unsigned long
+cygwin_get_dr7 (void)
+{
+  return (unsigned long) dr[7];
+}
+
 /* Determine if the thread referenced by "ptid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the thread has died.  Otherwise it is assumed to be alive.  */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-05 16:46 [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
@ 2011-12-05 17:06 ` Eli Zaretskii
  2011-12-09 16:30   ` New tests to watch regions larger than a machine word (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
  2011-12-05 21:24 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil
  1 sibling, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2011-12-05 17:06 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Mon, 5 Dec 2011 16:01:59 +0000
> 
> On native x86 targets, the desired state of hardware watchpoints is
> kept on a local mirror of the inferior's debug registers, and copied
> to each thread whenever the mirror changes.  If any of the threads
> being copied to are currently running, the copying fails with an ugly
> error.
> 
> GDBserver solves this by instead only updating the threads' debug
> registers prior to resume, and, when the local mirror changes, forcing
> a temporary and transparent stop on running threads, so they can
> update the debug registers when re-resumed.  When deciding whether an
> LWP stopped due to a hardware watchpoint or breakpoint, the current
> state of the debug registers in the stopping thread is read, rather
> than trusting the mirror still mirrors what was last copied to the
> thread.
> 
> This patch matches teaches linux-nat.c to do the same as
> GDBserver.
> 
> I suspect this change gets rid of a couple of workarounds we had in
> place (e.g., i386_stopped_data_address), so I removed them --
> GDBserver didn't have them.  No regressions popped up.

Be sure to test it with several watchpoints watching the same address,
either with different conditions or different types (rwatch vs awatch
vs watch), and also with watchpoints that watch regions longer than 4
bytes on IA32 (and similarly on 64-bit hosts).

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-05 16:46 [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
  2011-12-05 17:06 ` Eli Zaretskii
@ 2011-12-05 21:24 ` Jan Kratochvil
  2011-12-09 16:45   ` Pedro Alves
  1 sibling, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-05 21:24 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 05 Dec 2011 17:01:59 +0100, Pedro Alves wrote:
> On native x86 targets, the desired state of hardware watchpoints is
> kept on a local mirror of the inferior's debug registers, and copied
> to each thread whenever the mirror changes.

The patchset
	[patch 0/4] hw watchpoints across fork() + multi-inf

which I am rebasing now on top of HEAD which already reimplements its part by
	commit 96fd921972966166fda0eb300bfa4e5479f3b31f
	Author: Pedro Alves <pedro@codesourcery.com>
	Date:   Fri Jul 22 16:58:30 2011 +0000
	http://sourceware.org/ml/gdb-patches/2011-07/msg00586.html

The patch in Fedora since 2007 is solving this by having per-inferior copy of
the registers.

I miss some testcases in your patch.

I can rebase what remains from the patchset on this patch.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* New tests to watch regions larger than a machine word (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode)
  2011-12-05 17:06 ` Eli Zaretskii
@ 2011-12-09 16:30   ` Pedro Alves
  2011-12-09 19:11     ` Eli Zaretskii
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-09 16:30 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Monday 05 December 2011 17:02:54, Eli Zaretskii wrote:

> Be sure to test it with several watchpoints watching the same address,
> either with different conditions or different types (rwatch vs awatch
> vs watch), 

That's actually already tested by watch-read.exp.

> and also with watchpoints that watch regions longer than 4
> bytes on IA32 (and similarly on 64-bit hosts).

This however doesn't seem to be tested anywhere.

Here are a couple new tests to exercise that.  They pass cleanly
before and after the proposed patch, native and gdbserver linux,
x86 and x86_64.

The tests expects the regions to be coverable by hardware watchpoints by
default, unless gdb,no_hardware_watchpoints is set in the board file.
Rather than only doing that selectively on x86, it's better to default
to expect the target can support the largish watchpoints,
and explicitly list targets where we find it's not possible to watch a
region larger than a word (not sure which, but I'm sure they're out there).
Doing the opposite tends to have tests never enabled on targets where
they could and should be enabled.  We have such cases already in
watchpoint.exp even.  E.g.:

    # Only enabled for some targets merely because it has not been tested 
    # elsewhere.
    # On sparc-sun-sunos4.1.3, GDB was running all the way to the marker4 
    # breakpoint before stopping for the watchpoint.  I don't know why.
    if {[istarget "hppa*-*-*"]} then {
	test_watchpoint_triggered_in_syscall
    }

Comments?

gdb/testsuite/
2011-12-09  Pedro Alves  <pedro@codesourcery.com>

	* gdb.base/watchpoint.c (struct foo2, foo2, struct foo4, foo4)
	(func6, func7): New.
	(main): Call func6 and func7.
	* gdb.base/watchpoint.exp (test_wide_location_1)
	(test_wide_location_2): New.
	(top level): Re-enable hardware watchpoints if necessary.  Call
	test_wide_location_1 and test_wide_location_2.
---

 gdb/testsuite/gdb.base/watchpoint.c   |   32 +++++++++++++++
 gdb/testsuite/gdb.base/watchpoint.exp |   70 +++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 0 deletions(-)

diff --git a/gdb/testsuite/gdb.base/watchpoint.c b/gdb/testsuite/gdb.base/watchpoint.c
index 9ef9253..c4d8a69 100644
--- a/gdb/testsuite/gdb.base/watchpoint.c
+++ b/gdb/testsuite/gdb.base/watchpoint.c
@@ -42,6 +42,18 @@ int doread = 0;
 char *global_ptr;
 char **global_ptr_ptr;
 
+struct foo2
+{
+  int val[2];
+};
+struct foo2 foo2;
+
+struct foo4
+{
+  int val[4];
+};
+struct foo4 foo4;
+
 void marker1 ()
 {
 }
@@ -137,6 +149,22 @@ func5 ()
   val = 27;
 }
 
+void
+func6 (void)
+{
+  /* func6 breakpoint here */
+  foo2.val[1] = 0;
+  foo2.val[1] = 11;
+}
+
+void
+func7 (void)
+{
+  /* func7 breakpoint here */
+  foo4.val[3] = 0;
+  foo4.val[3] = 33;
+}
+
 int main ()
 {
 #ifdef usestubs
@@ -216,5 +244,9 @@ int main ()
 
   func5 ();
 
+  func6 ();
+
+  func7 ();
+
   return 0;
 }
diff --git a/gdb/testsuite/gdb.base/watchpoint.exp b/gdb/testsuite/gdb.base/watchpoint.exp
index 331b181..574dd8b 100644
--- a/gdb/testsuite/gdb.base/watchpoint.exp
+++ b/gdb/testsuite/gdb.base/watchpoint.exp
@@ -660,6 +660,68 @@ proc test_watch_location {} {
     gdb_test_no_output "delete \$bpnum" "delete watch -location"
 }
 
+# Tests watching areas larger than a word.
+
+proc test_wide_location_1 {} {
+    # This test watches two words on most 32-bit ABIs, and one word on
+    # most 64-bit ABIs.
+
+    # Platforms where the target can't watch such a large region
+    # should clear hw_expected below.
+    if [target_info exists gdb,no_hardware_watchpoints] {
+	set hw_expected 0
+    } else {
+	set hw_expected 1
+    }
+
+    gdb_breakpoint [gdb_get_line_number "func6 breakpoint here"]
+    gdb_continue_to_breakpoint "func6 breakpoint here"
+
+    if { $hw_expected } {
+	gdb_test "watch foo2" "Hardware watchpoint .*: .*" "watch foo2"
+	gdb_test "continue" \
+	    "Continuing.*Hardware watchpoint .*: .*New value = \\\{val = \\\{0, 11\\\}\\\}.*" \
+	    "continue with watch foo2"
+    } else {
+	gdb_test "watch foo2" "atchpoint .*: .*" "watch foo2"
+	gdb_test "continue" \
+	    "Continuing.*\[Ww\]atchpoint .*: .*New value = \\\{val = \\\{0, 11\\\}\\\}.*" \
+	    "continue with watch foo2"
+    }
+
+    gdb_test_no_output "delete \$bpnum" "delete watch foo2"
+}
+
+proc test_wide_location_2 {} {
+    # This test watches four words on most 32-bit ABIs, and two words
+    # on 64-bit ABIs.
+
+    # Platforms where the target can't watch such a large region
+    # should clear hw_expected below.
+    if [target_info exists gdb,no_hardware_watchpoints] {
+	set hw_expected 0
+    } else {
+	set hw_expected 1
+    }
+
+    gdb_breakpoint [gdb_get_line_number "func7 breakpoint here"]
+    gdb_continue_to_breakpoint "func7 breakpoint here"
+
+    if { $hw_expected } {
+	gdb_test "watch foo4" "Hardware watchpoint .*: .*" "watch foo4"
+	gdb_test "continue" \
+	    "Continuing.*Hardware watchpoint .*: .*New value = \\\{val = \\\{0, 0, 0, 33\\\}\\\}.*" \
+	    "continue with watch foo4"
+    } else {
+	gdb_test "watch foo4" "atchpoint .*: .*" "watch foo4"
+	gdb_test "continue" \
+	    "Continuing.*\[Ww\]atchpoint .*: .*New value = \\\{val = \\\{0, 0, 0, 33\\\}\\\}.*" \
+	    "continue with watch foo4"
+    }
+
+    gdb_test_no_output "delete \$bpnum" "delete watch foo4"
+}
+
 proc test_inaccessible_watchpoint {} {
     global gdb_prompt
 
@@ -923,6 +985,14 @@ if [initialize] then {
     test_disable_enable_software_watchpoint
 
     test_watch_location
+
+    # Re-enable hardware watchpoints if necessary.
+    if ![target_info exists gdb,no_hardware_watchpoints] {
+        gdb_test_no_output "set can-use-hw-watchpoints 1" ""
+    }
+
+    test_wide_location_1
+    test_wide_location_2
 }
 
 # Restore old timeout

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-05 21:24 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil
@ 2011-12-09 16:45   ` Pedro Alves
  2011-12-09 16:47     ` Tristan Gingold
                       ` (3 more replies)
  0 siblings, 4 replies; 37+ messages in thread
From: Pedro Alves @ 2011-12-09 16:45 UTC (permalink / raw)
  To: Jan Kratochvil, Tristan Gingold; +Cc: gdb-patches

On Monday 05 December 2011 20:25:13, Jan Kratochvil wrote:
> On Mon, 05 Dec 2011 17:01:59 +0100, Pedro Alves wrote:
> > On native x86 targets, the desired state of hardware watchpoints is
> > kept on a local mirror of the inferior's debug registers, and copied
> > to each thread whenever the mirror changes.
> 
> The patchset
> 	[patch 0/4] hw watchpoints across fork() + multi-inf
> 
> which I am rebasing now on top of HEAD which already reimplements its part by
> 	commit 96fd921972966166fda0eb300bfa4e5479f3b31f
> 	Author: Pedro Alves <pedro@codesourcery.com>
> 	Date:   Fri Jul 22 16:58:30 2011 +0000
> 	http://sourceware.org/ml/gdb-patches/2011-07/msg00586.html

You mean you were already pulling in this non-stop change from
gdbserver?  :-(  I only did this because it is blocking my
other patches...

> I miss some testcases in your patch.

Added a simple test now.

> I can rebase what remains from the patchset on this patch.

Great.

Below's the updated patch.  It also fixes a couple pastos in
windows-nat.c.

On Monday 05 December 2011 16:01:02, Pedro Alves wrote:
> I have tested this on x86_64-linux (-m64|-m32), which showed no
> regressions.  The patch also adjusts all other users of i396-nat.c:
> djgpp/go32; i386 BSDs (FreeBSD only it seems); Windows (cygwin/mingw)
> and macosx (darwin), but I haven't tested those.  I'd appreciate
> testing or an extra pair of eyes.
> 
> Actually darwin has the i386 watchpoint hooks in place, but it doesn't
> install them:
> 
>  $ grep i386_darwin_dr_get_status *
>  i386-darwin-nat.c:i386_darwin_dr_get_status (void)
>  $
> 
> ??

Anyone want to comment on those platform bits?

Tristan, are we just missing a patchlet to glue 
i386-darwin-nat.c with i386-nat.c.?

-- 
Pedro Alves

2011-12-07  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* linux-nat.c (linux_nat_new_thread): Change parameter to an lwp
	pointer.
	(linux_nat_prepare_to_resume): New global.
	(lwp_free): New.
	(purge_lwp_list): Use it.
	(add_lwp): Call linux_nat_new_thread even on the first LWP.
	Adjust to interface change.
	(delete_lwp): Call lwp_free instead of xfree.
	(resume_lwp, linux_nat_resume, linux_handle_syscall_trap)
	(linux_handle_extended_wait, linux_nat_filter_event)
	(linux_nat_filter_event): Call linux_nat_prepare_to_resume before
	resuming.
	(linux_stop_lwp): New.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.
	* linux-nat.h (struct arch_lwp_info): Forward declare.
	(struct lwp_info) <arch_private>: New field.
	(linux_stop_lwp): Declare.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.

	* i386-nat.c (DR_NADDR, DR_STATUS, DR_CONTROL)
	(struct i386_debug_reg_state): Move to i386-nat.h.
	(dr_mirror): Comment.
	(i386_debug_reg_state): New.
	(i386_update_inferior_debug_regs): Simplify.
	(i386_stopped_data_address): Use the debug register state from the
	inferior, not from the local cache.
	* i386-nat.h (struct i386_dr_low_type): Delete reset_addr and
	unset_status fields.  New get_addr and get_control fields.
	(DR_FIRSTADDR, DR_LASTADDR, DR_CONTROL): Moved from i386-nat.c.
	(DR_NADDR, DR_STATUS): New.
	(struct i386_debug_reg_state): Moved from i386-nat.c.

	* amd64-linux-nat.c (struct arch_lwp_info): New.
	(amd64_linux_dr): Delete global.
	(amd64_linux_dr_get_addr): New.
	(amd64_linux_dr_get_control): New.
	(amd64_linux_dr_unset_status): Delete.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_dr_reset_addr): Delete.
	(update_debug_registers_callback): New.
	(amd64_linux_dr_set_control): Reimplement.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_prepare_to_resume): New.
	(amd64_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_amd64_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	amd64_linux_dr_get_control as i386_dr_low.get_control.  Install
	amd64_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	amd64_linux_prepare_to_resume.
	* i386-darwin-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(i386_darwin_dr_reset_addr): Delete.
	(i386_darwin_dr_get_addr): New.
	(i386_darwin_dr_get_control): New.
	* i386-linux-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(struct arch_lwp_info): New.
	(i386_linux_dr): Delete global.
	(i386_linux_dr_set_control): Reimplement.
	(i386_linux_dr_get_addr): New.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_dr_get_control): New.
	(update_debug_registers_callback): New.
	(i386_linux_dr_unset_status): Delete.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_prepare_to_resume): New.
	(i386_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_i386_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386_linux_dr_get_control as i386_dr_low.get_control.  Install
	i386_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	i386_linux_prepare_to_resume.

	* go32-nat.c
	(go32_get_dr7, go32_get_dr): New.
	(init_go32_ops): No longer install i386_dr_low.reset_addr.
	Install go32_get_dr7 as i386_dr_low.get_control.  Install
	go32_get_dr as i386_dr_low.get_addr.
	* i386bsd-nat.c (i386bsd_dr_get): New.
	(i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_status): Use i386bsd_dr_get.
	(i386bsd_dr_get_control): New.
	* i386bsd-nat.h (i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_control): New.
	* i386fbsd-nat.c (_initialize_i386fbsd_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386bsd_dr_get_control as i386_dr_low.get_control.  Install
	i386bsd_dr_get_addr as i386_dr_low.get_addr.
	* windows-nat.c (init_windows_ops): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	cygwin_get_dr7 as i386_dr_low.get_control.  Install cygwin_get_dr
	as i386_dr_low.get_addr.
	(cygwin_get_dr): New.
	(cygwin_get_dr7): New.

gdb/testsuite/
2011-12-07  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* gdb.mi/watch-nonstop.c: New file.
 	* gdb.mi/mi-watch-nonstop.exp: New file.
---

 gdb/amd64-linux-nat.c                     |  121 +++++++++++++++++---------
 gdb/go32-nat.c                            |   25 +++++
 gdb/i386-darwin-nat.c                     |   31 ++-----
 gdb/i386-linux-nat.c                      |  134 +++++++++++++++++------------
 gdb/i386-nat.c                            |   63 +++-----------
 gdb/i386-nat.h                            |   42 ++++++++-
 gdb/i386bsd-nat.c                         |   32 +++++--
 gdb/i386bsd-nat.h                         |    4 +
 gdb/i386fbsd-nat.c                        |    3 -
 gdb/linux-nat.c                           |   63 ++++++++++++--
 gdb/linux-nat.h                           |   14 +++
 gdb/mi/mi-main.c                          |    3 -
 gdb/testsuite/gdb.mi/mi-watch-nonstop.exp |   77 +++++++++++++++++
 gdb/testsuite/gdb.mi/watch-nonstop.c      |   24 +++++
 gdb/windows-nat.c                         |   21 ++++-
 15 files changed, 459 insertions(+), 198 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
 create mode 100644 gdb/testsuite/gdb.mi/watch-nonstop.c

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index c673965..9699f84 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -64,6 +64,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 
@@ -265,8 +273,6 @@ amd64_linux_store_inferior_registers (struct target_ops *ops,
 \f
 /* Support for debug registers.  */
 
-static unsigned long amd64_linux_dr[DR_CONTROL + 1];
-
 static unsigned long
 amd64_linux_dr_get (ptid_t ptid, int regnum)
 {
@@ -304,75 +310,105 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-amd64_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+amd64_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  amd64_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return amd64_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+amd64_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
 
-  amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+static unsigned long
+amd64_linux_dr_get_status (void)
+{
+  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
 
-static void
-amd64_linux_dr_reset_addr (int regnum)
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
 {
-  amd64_linux_dr_set_addr (regnum, 0);
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set DR_CONTROL to CONTROL in all LWPs of the current inferior.  */
 
-static unsigned long
-amd64_linux_dr_get_status (void)
+static void
+amd64_linux_dr_set_control (unsigned long control)
 {
-  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
 static void
-amd64_linux_dr_unset_status (unsigned long mask)
+amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  struct lwp_info *lp;
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
 
-  ALL_LWPS (lp)
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
+}
+
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
+
+static void
+amd64_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
-      
-      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
+      int i;
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
+
+      amd64_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
-}
 
+  if (lwp->stopped_by_watchpoint)
+    amd64_linux_dr_set (lwp->ptid, DR_STATUS, 0);
+}
 
 static void
-amd64_linux_new_thread (ptid_t ptid)
+amd64_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -785,9 +821,9 @@ _initialize_amd64_linux_nat (void)
 
   i386_dr_low.set_control = amd64_linux_dr_set_control;
   i386_dr_low.set_addr = amd64_linux_dr_set_addr;
-  i386_dr_low.reset_addr = amd64_linux_dr_reset_addr;
+  i386_dr_low.get_addr = amd64_linux_dr_get_addr;
   i386_dr_low.get_status = amd64_linux_dr_get_status;
-  i386_dr_low.unset_status = amd64_linux_dr_unset_status;
+  i386_dr_low.get_control = amd64_linux_dr_get_control;
   i386_set_debug_register_length (8);
 
   /* Override the GNU/Linux inferior startup hook.  */
@@ -804,4 +840,5 @@ _initialize_amd64_linux_nat (void)
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, amd64_linux_new_thread);
   linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup);
+  linux_nat_set_prepare_to_resume (t, amd64_linux_prepare_to_resume);
 }
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 8295adf..b650a94 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -801,6 +801,28 @@ go32_get_dr6 (void)
   return STATUS;
 }
 
+/* Get the value of the DR6 debug status register from the inferior.
+   Here we just return the value stored in D_REGS, as we've got it
+   from the last go32_wait call.  */
+static unsigned long
+go32_get_dr7 (void)
+{
+  return CONTROL;
+}
+
+/* Get the value of the DR debug register I from the inferior.  Here
+   we just return the value stored in D_REGS, as we've got it from the
+   last go32_wait call.  */
+
+static CORE_ADDR
+go32_get_dr (int i)
+{
+  if (i < 0 || i > 3)
+    internal_error (__FILE__, __LINE__, 
+		    _("Invalid register %d in go32_get_dr.\n"), i);
+  return D_REGS[i];
+}
+
 /* Put the device open on handle FD into either raw or cooked
    mode, return 1 if it was in raw mode, zero otherwise.  */
 
@@ -984,8 +1006,9 @@ init_go32_ops (void)
 
   i386_dr_low.set_control = go32_set_dr7;
   i386_dr_low.set_addr = go32_set_dr;
-  i386_dr_low.reset_addr = NULL;
   i386_dr_low.get_status = go32_get_dr6;
+  i386_dr_low.get_control = go32_get_dr7;
+  i386_dr_low.get_addr = go32_get_dr;
   i386_set_debug_register_length (4);
 
   go32_ops.to_magic = OPS_MAGIC;
diff --git a/gdb/i386-darwin-nat.c b/gdb/i386-darwin-nat.c
index 61e2e15..23f6a6d 100644
--- a/gdb/i386-darwin-nat.c
+++ b/gdb/i386-darwin-nat.c
@@ -263,23 +263,6 @@ i386_darwin_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers, boosted mostly from i386-linux-nat.c.  */
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
-
 static void
 i386_darwin_dr_set (int regnum, uint32_t value)
 {
@@ -410,12 +393,10 @@ i386_darwin_dr_set_addr (int regnum, CORE_ADDR addr)
   i386_darwin_dr_set (DR_FIRSTADDR + regnum, addr);
 }
 
-void
-i386_darwin_dr_reset_addr (int regnum)
+CORE_ADDR
+i386_darwin_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
-
-  i386_darwin_dr_set (DR_FIRSTADDR + regnum, 0L);
+  return i386_darwin_dr_get (regnum);
 }
 
 unsigned long
@@ -424,6 +405,12 @@ i386_darwin_dr_get_status (void)
   return i386_darwin_dr_get (DR_STATUS);
 }
 
+unsigned long
+i386_darwin_dr_get_control (void)
+{
+  return i386_darwin_dr_get (DR_CONTROL);
+}
+
 void
 darwin_check_osabi (darwin_inferior *inf, thread_t thread)
 {
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 7eb49ae..70a5919 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -47,22 +47,6 @@
 #include <sys/debugreg.h>
 #endif
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
@@ -83,6 +67,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 \f
@@ -651,8 +643,6 @@ i386_linux_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers.  */
 
-static unsigned long i386_linux_dr[DR_CONTROL + 1];
-
 /* Get debug register REGNUM value from only the one LWP of PTID.  */
 
 static unsigned long
@@ -692,74 +682,105 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-i386_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+i386_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  i386_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return i386_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+i386_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return i386_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
 
-  i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+static unsigned long
+i386_linux_dr_get_status (void)
+{
+  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
 
-static void
-i386_linux_dr_reset_addr (int regnum)
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
 {
-  i386_linux_dr_set_addr (regnum, 0);
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set DR_CONTROL to ADDR in all LWPs of the current inferior.  */
 
-static unsigned long
-i386_linux_dr_get_status (void)
+static void
+i386_linux_dr_set_control (unsigned long control)
 {
-  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
 static void
-i386_linux_dr_unset_status (unsigned long mask)
+i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  struct lwp_info *lp;
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
 
-  ALL_LWPS (lp)
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
+}
+
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
+
+static void
+i386_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
+      int i;
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	i386_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
 
-      value = i386_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      i386_linux_dr_set (lp->ptid, DR_STATUS, value);
+      i386_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
+
+  if (lwp->stopped_by_watchpoint)
+    i386_linux_dr_set (lwp->ptid, DR_STATUS, 0);
 }
 
 static void
-i386_linux_new_thread (ptid_t ptid)
+i386_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    i386_linux_dr_set (ptid, i, i386_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -978,9 +999,9 @@ _initialize_i386_linux_nat (void)
 
   i386_dr_low.set_control = i386_linux_dr_set_control;
   i386_dr_low.set_addr = i386_linux_dr_set_addr;
-  i386_dr_low.reset_addr = i386_linux_dr_reset_addr;
+  i386_dr_low.get_addr = i386_linux_dr_get_addr;
   i386_dr_low.get_status = i386_linux_dr_get_status;
-  i386_dr_low.unset_status = i386_linux_dr_unset_status;
+  i386_dr_low.get_control = i386_linux_dr_get_control;
   i386_set_debug_register_length (4);
 
   /* Override the default ptrace resume method.  */
@@ -999,4 +1020,5 @@ _initialize_i386_linux_nat (void)
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, i386_linux_new_thread);
+  linux_nat_set_prepare_to_resume (t, i386_linux_prepare_to_resume);
 }
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 568b79b..94306a1 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -43,11 +43,6 @@ struct i386_dr_low_type i386_dr_low;
 /* Support for 8-byte wide hw watchpoints.  */
 #define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8)
 
-/* Debug registers' indices.  */
-#define DR_NADDR	4	/* The number of debug address registers.  */
-#define DR_STATUS	6	/* Index of debug status register (DR6).  */
-#define DR_CONTROL	7	/* Index of debug control register (DR7).  */
-
 /* DR7 Debug Control register fields.  */
 
 /* How many bits to skip in DR7 to get to R/W and LEN fields.  */
@@ -158,23 +153,6 @@ struct i386_dr_low_type i386_dr_low;
 /* A macro to loop over all debug registers.  */
 #define ALL_DEBUG_REGISTERS(i)	for (i = 0; i < DR_NADDR; i++)
 
-
-/* Global state needed to track h/w watchpoints.  */
-
-struct i386_debug_reg_state
-{
-  /* Mirror the inferior's DRi registers.  We keep the status and
-     control registers separated because they don't hold addresses.
-     Note that since we can change these mirrors while threads are
-     running, we never trust them to explain a cause of a trap.
-     For that, we need to peek directly in the inferior registers.  */
-  CORE_ADDR dr_mirror[DR_NADDR];
-  unsigned dr_status_mirror, dr_control_mirror;
-
-  /* Reference counts for each debug register.  */
-  int dr_ref_count[DR_NADDR];
-};
-
 /* Clear the reference counts and forget everything we knew about the
    debug registers.  */
 
@@ -192,8 +170,16 @@ i386_init_dregs (struct i386_debug_reg_state *state)
   state->dr_status_mirror  = 0;
 }
 
+/* The local mirror of the inferior's debug registers.  Currently this
+   is a global, but it should really be per-inferior.  */
 static struct i386_debug_reg_state dr_mirror;
 
+struct i386_debug_reg_state *
+i386_debug_reg_state (void)
+{
+  return &dr_mirror;
+}
+
 /* Whether or not to print the mirrored debug registers.  */
 static int maint_show_dr;
 
@@ -513,22 +499,7 @@ i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state)
   ALL_DEBUG_REGISTERS (i)
     {
       if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (&dr_mirror, i))
-	{
-	  if (!I386_DR_VACANT (new_state, i))
-	    {
-	      i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
-
-	      /* Only a sanity check for leftover bits (set possibly only
-		 by inferior).  */
-	      if (i386_dr_low.unset_status)
-		i386_dr_low.unset_status (I386_DR_WATCH_MASK (i));
-	    }
-	  else
-	    {
-	      if (i386_dr_low.reset_addr)
-		i386_dr_low.reset_addr (i);
-	    }
-	}
+	i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
       else
 	gdb_assert (new_state->dr_mirror[i] == dr_mirror.dr_mirror[i]);
     }
@@ -636,11 +607,12 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
   int rc = 0;
   unsigned status;
   unsigned control;
-  struct i386_debug_reg_state *state = &dr_mirror;
 
-  dr_mirror.dr_status_mirror = i386_dr_low.get_status ();
-  status = dr_mirror.dr_status_mirror;
-  control = dr_mirror.dr_control_mirror;
+  /* Get the current values the inferior has.  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 ();
+  control = i386_dr_low.get_control ();
 
   ALL_DEBUG_REGISTERS(i)
     {
@@ -650,12 +622,9 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
 	     that GDB doesn't call the target_stopped_data_address
 	     method except for data watchpoints.  In other words, I'm
 	     being paranoiac.  */
-	  && I386_DR_GET_RW_LEN (control, i) != 0
-	  /* This third condition makes sure DRi is not vacant, this
-	     avoids false positives in windows-nat.c.  */
-	  && !I386_DR_VACANT (state, i))
+	  && I386_DR_GET_RW_LEN (control, i) != 0)
 	{
-	  addr = state->dr_mirror[i];
+	  addr = i386_dr_low.get_addr (i);
 	  rc = 1;
 	  if (maint_show_dr)
 	    i386_show_dr (&dr_mirror, "watchpoint_hit", addr, -1, hw_write);
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 819c6b8..1a75daa 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -53,31 +53,54 @@ extern void i386_use_watchpoints (struct target_ops *);
       set_addr                 -- put an address into one debug
 				  register for all LWPs
 
-      reset_addr               -- reset the address stored in
-				  one debug register for all LWPs
+      get_addr                 -- return the address in a given debug
+				  register of the current LWP
 
       get_status               -- return the value of the debug
 				  status (DR6) register for current LWP
 
-      unset_status             -- unset the specified bits of the debug
-				  status (DR6) register for all LWPs
+      get_control               -- return the value of the debug
+				  control (DR7) register for current LWP
 
    Additionally, the native file should set the debug_register_length
    field to 4 or 8 depending on the number of bytes used for
    deubg registers.  */
 
-struct i386_dr_low_type 
+struct i386_dr_low_type
   {
     void (*set_control) (unsigned long);
     void (*set_addr) (int, CORE_ADDR);
-    void (*reset_addr) (int);
+    CORE_ADDR (*get_addr) (int);
     unsigned long (*get_status) (void);
-    void (*unset_status) (unsigned long);
+    unsigned long (*get_control) (void);
     int debug_register_length;
   };
 
 extern struct i386_dr_low_type i386_dr_low;
 
+/* Debug registers' indices.  */
+#define DR_FIRSTADDR 0
+#define DR_LASTADDR  3
+#define DR_NADDR     4	/* The number of debug address registers.  */
+#define DR_STATUS    6	/* Index of debug status register (DR6).  */
+#define DR_CONTROL   7	/* Index of debug control register (DR7).  */
+
+/* Global state needed to track h/w watchpoints.  */
+
+struct i386_debug_reg_state
+{
+  /* Mirror the inferior's DRi registers.  We keep the status and
+     control registers separated because they don't hold addresses.
+     Note that since we can change these mirrors while threads are
+     running, we never trust them to explain a cause of a trap.
+     For that, we need to peek directly in the inferior registers.  */
+  CORE_ADDR dr_mirror[DR_NADDR];
+  unsigned dr_status_mirror, dr_control_mirror;
+
+  /* Reference counts for each debug register.  */
+  int dr_ref_count[DR_NADDR];
+};
+
 /* Use this function to set i386_dr_low debug_register_length field
    rather than setting it directly to check that the length is only
    set once.  It also enables the 'maint set/show show-debug-regs' 
@@ -89,4 +112,9 @@ extern void i386_set_debug_register_length (int len);
 
 extern void i386_cleanup_dregs (void);
 
+/* Return a pointer to the the local mirror of the inferior's debug
+   registers.  */
+
+extern struct i386_debug_reg_state *i386_debug_reg_state (void);
+
 #endif /* I386_NAT_H */
diff --git a/gdb/i386bsd-nat.c b/gdb/i386bsd-nat.c
index fcd772f..22c79e2 100644
--- a/gdb/i386bsd-nat.c
+++ b/gdb/i386bsd-nat.c
@@ -264,6 +264,18 @@ i386bsd_target (void)
 #define DBREG_DRX(d, x) ((&d->dr0)[x])
 #endif
 
+static unsigned long
+i386bsd_dr_get (ptid_t ptid, int regnum)
+{
+  struct dbreg dbregs;
+
+  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
+    perror_with_name (_("Couldn't read debug registers"));
+
+  return DBREG_DRX ((&dbregs), regnum);
+}
+
 static void
 i386bsd_dr_set (int regnum, unsigned int value)
 {
@@ -299,24 +311,22 @@ i386bsd_dr_set_addr (int regnum, CORE_ADDR addr)
   i386bsd_dr_set (regnum, addr);
 }
 
-void
-i386bsd_dr_reset_addr (int regnum)
+CORE_ADDR
+i386bsd_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= 4);
-
-  i386bsd_dr_set (regnum, 0);
+  return i386bsd_dr_get (inferior_ptid, regnum);
 }
 
 unsigned long
 i386bsd_dr_get_status (void)
 {
-  struct dbreg dbregs;
-
-  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
-	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't read debug registers"));
+  return i386bsd_dr_get (inferior_ptid, 6);
+}
 
-  return DBREG_DRX ((&dbregs), 6);
+unsigned long
+i386bsd_dr_get_control (void)
+{
+  return i386bsd_dr_get (inferior_ptid, 7);
 }
 
 #endif /* PT_GETDBREGS */
diff --git a/gdb/i386bsd-nat.h b/gdb/i386bsd-nat.h
index 1c27ed5..df0b0f3 100644
--- a/gdb/i386bsd-nat.h
+++ b/gdb/i386bsd-nat.h
@@ -32,8 +32,10 @@ extern void i386bsd_dr_set_control (unsigned long control);
 
 extern void i386bsd_dr_set_addr (int regnum, CORE_ADDR addr);
 
-extern void i386bsd_dr_reset_addr (int regnum);
+extern CORE_ADDR i386bsd_dr_get_addr (int regnum);
 
 extern unsigned long i386bsd_dr_get_status (void);
 
+extern unsigned long i386bsd_dr_get_control (void);
+
 #endif /* i386bsd-nat.h */
diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c
index ecc797e..52ae031 100644
--- a/gdb/i386fbsd-nat.c
+++ b/gdb/i386fbsd-nat.c
@@ -134,8 +134,9 @@ _initialize_i386fbsd_nat (void)
 
   i386_dr_low.set_control = i386bsd_dr_set_control;
   i386_dr_low.set_addr = i386bsd_dr_set_addr;
-  i386_dr_low.reset_addr = i386bsd_dr_reset_addr;
+  i386_dr_low.get_addr = i386bsd_dr_get_addr;
   i386_dr_low.get_status = i386bsd_dr_get_status;
+  i386_dr_low.get_control = i386bsd_dr_get_control;
   i386_set_debug_register_length (4);
 
 #endif /* HAVE_PT_GETDBREGS */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 19b4b57..d524307 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -175,7 +175,10 @@ static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The method to call, if any, when a new thread is attached.  */
-static void (*linux_nat_new_thread) (ptid_t);
+static void (*linux_nat_new_thread) (struct lwp_info *);
+
+/* Hook to call prior to resuming a thread.  */
+static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
 
 /* The method to call, if any, when the siginfo object needs to be
    converted between the layout returned by ptrace, and the layout in
@@ -1073,6 +1076,15 @@ status_to_str (int status)
   return buf;
 }
 
+/* Destroy and free LP.  */
+
+static void
+lwp_free (struct lwp_info *lp)
+{
+  xfree (lp->arch_private);
+  xfree (lp);
+}
+
 /* Remove all LWPs belong to PID from the lwp list.  */
 
 static void
@@ -1093,7 +1105,7 @@ purge_lwp_list (int pid)
 	  else
 	    lpprev->next = lp->next;
 
-	  xfree (lp);
+	  lwp_free (lp);
 	}
       else
 	lpprev = lp;
@@ -1139,8 +1151,8 @@ add_lwp (ptid_t ptid)
   lp->next = lwp_list;
   lwp_list = lp;
 
-  if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
-    linux_nat_new_thread (ptid);
+  if (linux_nat_new_thread != NULL)
+    linux_nat_new_thread (lp);
 
   return lp;
 }
@@ -1166,7 +1178,7 @@ delete_lwp (ptid_t ptid)
   else
     lwp_list = lp->next;
 
-  xfree (lp);
+  lwp_free (lp);
 }
 
 /* Return a pointer to the structure describing the LWP corresponding
@@ -1825,6 +1837,8 @@ resume_lwp (struct lwp_info *lp, int step)
 				"RC:  PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
 				target_pid_to_str (lp->ptid));
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops,
 				pid_to_ptid (GET_LWP (lp->ptid)),
 				step, TARGET_SIGNAL_0);
@@ -1969,6 +1983,8 @@ linux_nat_resume (struct target_ops *ops,
   /* Convert to something the lower layer understands.  */
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
   lp->stopped_by_watchpoint = 0;
@@ -2138,6 +2154,8 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
   /* Note that gdbarch_get_syscall_number may access registers, hence
      fill a regcache.  */
   registers_changed ();
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			lp->step, TARGET_SIGNAL_0);
   return 1;
@@ -2325,6 +2343,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 		    fprintf_unfiltered (gdb_stdlog,
 					"LHEW: resuming new LWP %ld\n",
 					GET_LWP (new_lp->ptid));
+		  if (linux_nat_prepare_to_resume != NULL)
+		    linux_nat_prepare_to_resume (new_lp);
 		  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
 					0, TARGET_SIGNAL_0);
 		  new_lp->stopped = 0;
@@ -2334,6 +2354,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	  if (debug_linux_nat)
 	    fprintf_unfiltered (gdb_stdlog,
 				"LHEW: resuming parent LWP %d\n", pid);
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				0, TARGET_SIGNAL_0);
 
@@ -2597,6 +2619,14 @@ stop_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+/* Request a stop on LWP.  */
+
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+  stop_callback (lwp, NULL);
+}
+
 /* Return non-zero if LWP PID has a pending SIGINT.  */
 
 static int
@@ -3333,6 +3363,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
 
 	  registers_changed ();
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
 	  if (debug_linux_nat)
@@ -3364,6 +3396,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
       lp->ignore_sigint = 0;
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3538,6 +3572,8 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3787,6 +3823,8 @@ retry:
 	     newly attached threads may cause an unwanted delay in
 	     getting them running.  */
 	  registers_changed ();
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				lp->step, signo);
 	  if (debug_linux_nat)
@@ -3943,6 +3981,8 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
 			    lp->step);
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       lp->stopped = 0;
@@ -5840,7 +5880,8 @@ linux_nat_add_target (struct target_ops *t)
 
 /* Register a method to call whenever a new thread is attached.  */
 void
-linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+linux_nat_set_new_thread (struct target_ops *t,
+			  void (*new_thread) (struct lwp_info *))
 {
   /* Save the pointer.  We only support a single registered instance
      of the GNU/Linux native target, so we do not need to map this to
@@ -5861,6 +5902,16 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
   linux_nat_siginfo_fixup = siginfo_fixup;
 }
 
+/* Register a method to call prior to resuming a thread.  */
+
+void
+linux_nat_set_prepare_to_resume (struct target_ops *t,
+				 void (*prepare_to_resume) (struct lwp_info *))
+{
+  /* Save the pointer.  */
+  linux_nat_prepare_to_resume = prepare_to_resume;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 1fa94ce..33727d6 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -22,6 +22,8 @@
 
 #include <signal.h>
 
+struct arch_lwp_info;
+
 /* Ways to "resume" a thread.  */
 
 enum resume_kind
@@ -109,6 +111,9 @@ struct lwp_info
   /* The processor core this LWP was last seen on.  */
   int core;
 
+  /* Arch-specific additions.  */
+  struct arch_lwp_info *arch_private;
+
   /* Next LWP in list.  */
   struct lwp_info *next;
 };
@@ -146,6 +151,8 @@ extern void linux_enable_event_reporting (ptid_t ptid);
 
 extern int lin_lwp_attach_lwp (ptid_t ptid);
 
+extern void linux_stop_lwp (struct lwp_info *lwp);
+
 /* Iterator function for lin-lwp's lwp list.  */
 struct lwp_info *iterate_over_lwps (ptid_t filter,
 				    int (*callback) (struct lwp_info *,
@@ -166,7 +173,7 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int));
 void linux_nat_add_target (struct target_ops *);
 
 /* Register a method to call whenever a new thread is attached.  */
-void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t));
+void linux_nat_set_new_thread (struct target_ops *, void (*) (struct lwp_info *));
 
 /* Register a method that converts a siginfo object between the layout
    that ptrace returns, and the layout in the architecture of the
@@ -176,6 +183,11 @@ void linux_nat_set_siginfo_fixup (struct target_ops *,
 					   gdb_byte *,
 					   int));
 
+/* Register a method to call prior to resuming a thread.  */
+
+void linux_nat_set_prepare_to_resume (struct target_ops *,
+				      void (*) (struct lwp_info *));
+
 /* Update linux-nat internal state when changing from one fork
    to another.  */
 void linux_nat_switch_fork (ptid_t new_ptid);
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index eefe9ec..639da01 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -1743,12 +1743,11 @@ mi_cmd_list_target_features (char *command, char **argv, int argc)
       struct cleanup *cleanup = NULL;
       struct ui_out *uiout = current_uiout;
 
-      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");      
+      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");
       if (target_can_async_p ())
 	ui_out_field_string (uiout, NULL, "async");
       if (target_can_execute_reverse)
 	ui_out_field_string (uiout, NULL, "reverse");
-      
       do_cleanups (cleanup);
       return;
     }
diff --git a/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp b/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
new file mode 100644
index 0000000..b8aa903
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
@@ -0,0 +1,77 @@
+#   Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if [target_info exists gdb,no_hardware_watchpoints] {
+    return -1
+}
+
+if { ![support_displaced_stepping] } { 
+    unsupported "displaced stepping"
+    return -1
+}
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+proc mi_nonstop_resume { command test } {
+    if { [mi_send_resuming_command $command $test] != 0 } {
+	# If a resume fails, assume non-stop is broken or unsupported
+	# for this target.  We have logged a FAIL or UNSUPPORTED; skip
+	# the remaining tests to limit timeouts.
+	return -code continue
+    }
+}
+
+#
+# Start here
+#
+set testfile "watch-nonstop"
+set srcfile "$testfile.c"
+set binfile "$objdir/$subdir/mi-$testfile"
+
+if {[gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable {debug}] != "" } {
+    return -1
+}
+
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load $binfile
+
+mi_gdb_test "-gdb-set non-stop 1" ".*"
+mi_gdb_test "-gdb-set target-async 1" ".*"
+mi_detect_async
+
+if { [mi_run_to_main] < 0 } {
+    continue
+}
+
+# Set a watchpoint.
+mi_gdb_test "111-break-watch global" \
+    "111\\^done,wpt=\{number=\"2\",exp=\"global\"\}" \
+    "break-watch operation"
+
+# Set the target running.
+mi_nonstop_resume "exec-continue" "resume 1"
+
+# Now try deleting the watchpoint.  This would fail with "Couldn't
+# write debug register: No such process."  on GNU/Linux, because we'd
+# try to poke at the debug registers of a running thread.
+mi_gdb_test "777-break-delete 2" \
+    "777\\^done" \
+    "delete watchpoint"
diff --git a/gdb/testsuite/gdb.mi/watch-nonstop.c b/gdb/testsuite/gdb.mi/watch-nonstop.c
new file mode 100644
index 0000000..7222cb6
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/watch-nonstop.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int global;
+
+int main ()
+{
+  sleep (60);
+  return 0;
+}
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 20e3c67..97ed237 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2494,8 +2494,9 @@ init_windows_ops (void)
 
   i386_dr_low.set_control = cygwin_set_dr7;
   i386_dr_low.set_addr = cygwin_set_dr;
-  i386_dr_low.reset_addr = NULL;
+  i386_dr_low.get_addr = cygwin_get_dr;
   i386_dr_low.get_status = cygwin_get_dr6;
+  i386_dr_low.get_control = cygwin_get_dr7;
 
   /* i386_dr_low.debug_register_length field is set by
      calling i386_set_debug_register_length function
@@ -2627,6 +2628,14 @@ cygwin_set_dr7 (unsigned long val)
   debug_registers_used = 1;
 }
 
+/* Get the value of debug register I from the inferior.  */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+  return dr[i];
+}
+
 /* Get the value of the DR6 debug status register from the inferior.
    Here we just return the value stored in dr[6]
    by the last call to thread_rec for current_event.dwThreadId id.  */
@@ -2636,6 +2645,16 @@ cygwin_get_dr6 (void)
   return (unsigned long) dr[6];
 }
 
+/* Get the value of the DR7 debug status register from the inferior.
+   Here we just return the value stored in dr[7] by the last call to
+   thread_rec for current_event.dwThreadId id.  */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+  return (unsigned long) dr[7];
+}
+
 /* Determine if the thread referenced by "ptid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the thread has died.  Otherwise it is assumed to be alive.  */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-09 16:45   ` Pedro Alves
@ 2011-12-09 16:47     ` Tristan Gingold
  2011-12-09 19:23     ` Eli Zaretskii
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 37+ messages in thread
From: Tristan Gingold @ 2011-12-09 16:47 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Jan Kratochvil, gdb-patches


On Dec 9, 2011, at 5:30 PM, Pedro Alves wrote:

[…]
> 
> On Monday 05 December 2011 16:01:02, Pedro Alves wrote:
>> I have tested this on x86_64-linux (-m64|-m32), which showed no
>> regressions.  The patch also adjusts all other users of i396-nat.c:
>> djgpp/go32; i386 BSDs (FreeBSD only it seems); Windows (cygwin/mingw)
>> and macosx (darwin), but I haven't tested those.  I'd appreciate
>> testing or an extra pair of eyes.
>> 
>> Actually darwin has the i386 watchpoint hooks in place, but it doesn't
>> install them:
>> 
>> $ grep i386_darwin_dr_get_status *
>> i386-darwin-nat.c:i386_darwin_dr_get_status (void)
>> $
>> 
>> ??
> 
> Anyone want to comment on those platform bits?
> 
> Tristan, are we just missing a patchlet to glue 
> i386-darwin-nat.c with i386-nat.c.?

Correct.  HW watchpoint are currently not enabled on Darwin, but almost all the code is here.  I will try to fix that soon.

Thanks,
Tristan.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: New tests to watch regions larger than a machine word (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode)
  2011-12-09 16:30   ` New tests to watch regions larger than a machine word (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
@ 2011-12-09 19:11     ` Eli Zaretskii
  2011-12-13 16:12       ` Pedro Alves
  0 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2011-12-09 19:11 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Fri, 9 Dec 2011 16:14:06 +0000
> Cc: gdb-patches@sourceware.org
> 
> > and also with watchpoints that watch regions longer than 4
> > bytes on IA32 (and similarly on 64-bit hosts).
> 
> This however doesn't seem to be tested anywhere.
> 
> Here are a couple new tests to exercise that.  They pass cleanly
> before and after the proposed patch, native and gdbserver linux,
> x86 and x86_64.

Thanks.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-09 16:45   ` Pedro Alves
  2011-12-09 16:47     ` Tristan Gingold
@ 2011-12-09 19:23     ` Eli Zaretskii
  2011-12-13 16:26       ` Pedro Alves
  2011-12-11 23:39     ` Jan Kratochvil
  2011-12-12  0:14     ` Jan Kratochvil
  3 siblings, 1 reply; 37+ messages in thread
From: Eli Zaretskii @ 2011-12-09 19:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: jan.kratochvil, gingold, gdb-patches

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Fri, 9 Dec 2011 16:30:20 +0000
> Cc: gdb-patches@sourceware.org
> 
> On Monday 05 December 2011 16:01:02, Pedro Alves wrote:
> > I have tested this on x86_64-linux (-m64|-m32), which showed no
> > regressions.  The patch also adjusts all other users of i396-nat.c:
> > djgpp/go32; i386 BSDs (FreeBSD only it seems); Windows (cygwin/mingw)
> > and macosx (darwin), but I haven't tested those.  I'd appreciate
> > testing or an extra pair of eyes.
> > 
> > Actually darwin has the i386 watchpoint hooks in place, but it doesn't
> > install them:
> > 
> >  $ grep i386_darwin_dr_get_status *
> >  i386-darwin-nat.c:i386_darwin_dr_get_status (void)
> >  $
> > 
> > ??
> 
> Anyone want to comment on those platform bits?

My extra pair of eyes spotted this:

> --- a/gdb/go32-nat.c
> +++ b/gdb/go32-nat.c
> @@ -801,6 +801,28 @@ go32_get_dr6 (void)
>    return STATUS;
>  }
>  
> +/* Get the value of the DR6 debug status register from the inferior.
> +   Here we just return the value stored in D_REGS, as we've got it
> +   from the last go32_wait call.  */
> +static unsigned long
> +go32_get_dr7 (void)
> +{
> +  return CONTROL;
> +}

The comment says DR6, but the function uses dr7.  I think the comment
is wrong.

No other comments.  Thanks.

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-09 16:45   ` Pedro Alves
  2011-12-09 16:47     ` Tristan Gingold
  2011-12-09 19:23     ` Eli Zaretskii
@ 2011-12-11 23:39     ` Jan Kratochvil
  2011-12-12 11:53       ` Pedro Alves
  2011-12-12  0:14     ` Jan Kratochvil
  3 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-11 23:39 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tristan Gingold, gdb-patches, Yao Qi

On Fri, 09 Dec 2011 17:30:20 +0100, Pedro Alves wrote:
> On Monday 05 December 2011 20:25:13, Jan Kratochvil wrote:
> > The patchset
> > 	[patch 0/4] hw watchpoints across fork() + multi-inf
> > 
> > which I am rebasing now on top of HEAD which already reimplements its part by
> > 	commit 96fd921972966166fda0eb300bfa4e5479f3b31f
> > 	Author: Pedro Alves <pedro@codesourcery.com>
> > 	Date:   Fri Jul 22 16:58:30 2011 +0000
> > 	http://sourceware.org/ml/gdb-patches/2011-07/msg00586.html
> 
> You mean you were already pulling in this non-stop change from
> gdbserver?  :-(

I did not test non-stop but the patch reimplements the amd64_linux_dr
removal contained in the patchset started in 2007:
	http://sourceware.org/ml/gdb-patches/2010-12/msg00041.html

Last time you stopped that patchset due to referenced merging with gdbserver
	http://sourceware.org/ml/gdb-patches/2010-12/msg00348.html
which AFAIK Yao Qi was working on but which has not yet happened, so not sure
how more years it cannot get merged.  It was probably my wrong assumption for
the last year the i386-nat.c merging with gdbserver was being worked on while
in fact you only mentioned it would be good to do.


> --- a/gdb/mi/mi-main.c
> +++ b/gdb/mi/mi-main.c
> @@ -1743,12 +1743,11 @@ mi_cmd_list_target_features (char *command, char **argv, int argc)
>        struct cleanup *cleanup = NULL;
>        struct ui_out *uiout = current_uiout;
>  
> -      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");      
> +      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");
>        if (target_can_async_p ())
>  	ui_out_field_string (uiout, NULL, "async");
>        if (target_can_execute_reverse)
>  	ui_out_field_string (uiout, NULL, "reverse");
> -      
>        do_cleanups (cleanup);
>        return;
>      }

Unrelated whitespace cleanup only.  Not present in the ChangeLog.


Regards,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-09 16:45   ` Pedro Alves
                       ` (2 preceding siblings ...)
  2011-12-11 23:39     ` Jan Kratochvil
@ 2011-12-12  0:14     ` Jan Kratochvil
  2011-12-12 17:23       ` Pedro Alves
  3 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-12  0:14 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tristan Gingold, gdb-patches

Hi Pedro,

on simple non-hit (inferior does not touch "j" at all) watchpoint case:
strace -o 2 -q ./gdb -nx ./36 -ex start -ex 'watch j' -ex stepi -ex 'set confirm no' -ex q
grep 'PTRACE_....USER' 1 >1b; grep 'PTRACE_....USER' 2 >2b

It has performance regression of 15 ptrace syscalls -> 27 ptrace syscalls.


On Fri, 09 Dec 2011 17:30:20 +0100, Pedro Alves wrote:
> @@ -513,22 +499,7 @@ i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state)
>    ALL_DEBUG_REGISTERS (i)
>      {
>        if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (&dr_mirror, i))
> -	{
> -	  if (!I386_DR_VACANT (new_state, i))
> -	    {
> -	      i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
> -


> -	      /* Only a sanity check for leftover bits (set possibly only
> -		 by inferior).  */
> -	      if (i386_dr_low.unset_status)
> -		i386_dr_low.unset_status (I386_DR_WATCH_MASK (i));

Deleting this part is a regression.  Testcase for that part is attached.


> -	    }
> -	  else
> -	    {
> -	      if (i386_dr_low.reset_addr)
> -		i386_dr_low.reset_addr (i);
> -	    }
> -	}
> +	i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
>        else
>  	gdb_assert (new_state->dr_mirror[i] == dr_mirror.dr_mirror[i]);
>      }


> @@ -636,11 +607,12 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
>    int rc = 0;
>    unsigned status;
>    unsigned control;
> -  struct i386_debug_reg_state *state = &dr_mirror;
>  
> -  dr_mirror.dr_status_mirror = i386_dr_low.get_status ();
> -  status = dr_mirror.dr_status_mirror;
> -  control = dr_mirror.dr_control_mirror;
> +  /* Get the current values the inferior has.  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 ();
> +  control = i386_dr_low.get_control ();
>  
>    ALL_DEBUG_REGISTERS(i)
>      {
> @@ -650,12 +622,9 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
>  	     that GDB doesn't call the target_stopped_data_address
>  	     method except for data watchpoints.  In other words, I'm
>  	     being paranoiac.  */
> -	  && I386_DR_GET_RW_LEN (control, i) != 0

> -	  /* This third condition makes sure DRi is not vacant, this
> -	     avoids false positives in windows-nat.c.  */
> -	  && !I386_DR_VACANT (state, i))

This removal is probably safe as everything gets pre-cleared but after you fix
the performance regressions I am not sure if it should not be kept there.


> +	  && I386_DR_GET_RW_LEN (control, i) != 0)
>  	{
> -	  addr = state->dr_mirror[i];
> +	  addr = i386_dr_low.get_addr (i);

Why to do this change?  Why we can no longer trust DR_MIRROR?  This is
a performance regression.


>  	  rc = 1;
>  	  if (maint_show_dr)
>  	    i386_show_dr (&dr_mirror, "watchpoint_hit", addr, -1, hw_write);


gdb/testsuite/
2011-12-11  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.base/watchpoint-hw-pre-set.c: New file.
	* gdb.base/watchpoint-hw-pre-set.exp: New file.

--- /dev/null
+++ b/gdb/testsuite/gdb.base/watchpoint-hw-pre-set.c
@@ -0,0 +1,155 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#define _GNU_SOURCE 1
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/debugreg.h>
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+#define	SET_WATCHPOINT set_watchpoint
+
+static void
+set_watchpoint (pid_t pid, volatile void *addr)
+{
+  unsigned long dr7;
+  long l;
+
+  errno = 0;
+  l = ptrace (PTRACE_POKEUSER, pid,
+	      offsetof (struct user, u_debugreg[0]), (unsigned long) addr);
+  assert_perror (errno);
+  assert (l == 0);
+
+  dr7 = (DR_RW_WRITE << DR_CONTROL_SHIFT);
+  dr7 |= (DR_LEN_4 << DR_CONTROL_SHIFT);
+  dr7 |= (1UL << DR_LOCAL_ENABLE_SHIFT);
+  dr7 |= (1UL << DR_GLOBAL_ENABLE_SHIFT);
+
+  l = ptrace (PTRACE_POKEUSER, pid, offsetof (struct user, u_debugreg[7]), dr7);
+  assert_perror (errno);
+  assert (l == 0);
+}
+
+static pid_t child;
+
+static void
+cleanup (void)
+{
+  if (child > 0)
+    kill (child, SIGKILL);
+  child = 0;
+}
+
+static void
+handler_fail (int signo)
+{
+  cleanup ();
+  signal (signo, SIG_DFL);
+  raise (signo);
+}
+
+static volatile long long check, dummy;
+
+static void
+marker (void)
+{
+  dummy++;
+}
+
+static int resume;
+
+int
+main (void)
+{
+  pid_t got_pid;
+  int i, status, cycles = 0;
+  long l;
+
+  atexit (cleanup);
+  signal (SIGABRT, handler_fail);
+  signal (SIGINT, handler_fail);
+
+  child = fork ();
+  switch (child)
+    {
+    case -1:
+      assert (0);
+    case 0:
+      l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
+      assert (l == 0);
+
+      i = raise (SIGUSR1);
+      assert (i == 0);
+
+      check = 1;
+
+      while (!resume && cycles++ < 600 * 10)
+	usleep (1000000 / 10);
+
+      marker ();
+
+      i = raise (SIGUSR2);
+      assert (i == 0);
+      /* NOTREACHED */
+      assert (0);
+    default:
+      break;
+    }
+
+  got_pid = waitpid (child, &status, 0);
+  assert (got_pid == child);
+  assert (WIFSTOPPED (status));
+  assert (WSTOPSIG (status) == SIGUSR1);
+
+  SET_WATCHPOINT (child, &check);
+
+  errno = 0;
+  l = ptrace (PTRACE_CONT, child, NULL, NULL);
+  assert_perror (errno);
+  assert (l == 0);
+
+  got_pid = waitpid (child, &status, 0);
+  assert (got_pid == child);
+  assert (WIFSTOPPED (status));
+  if (WSTOPSIG (status) == SIGUSR2)
+    {
+      /* We missed the watchpoint - unsupported by hardware?  Found on:
+	 + qemu-system-x86_64 0.9.1-6.fc9.x86_64
+	 + qemu-kvm kvm-65-7.fc9.x86_64 + kernel-2.6.25.9-76.fc9.x86_64.  */
+      return 2;
+    }
+  assert (WSTOPSIG (status) == SIGTRAP);
+
+  errno = 0;
+  l = ptrace (PTRACE_DETACH, child, NULL, NULL);
+  assert_perror (errno);
+  assert (l == 0);
+
+  marker ();
+
+  return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/watchpoint-hw-pre-set.exp
@@ -0,0 +1,62 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test a newly created hardware watchpoint gets cleared its possible pre-set
+# hit in the status register.  Otherwise a false hit may occur.
+
+if {[skip_hw_watchpoint_access_tests]
+    || (![istarget "i?86-*-linux*"] && ![istarget "x86_64-*-linux*"])
+    || [is_remote target]} {
+    return 0
+}
+
+set test watchpoint-hw-pre-set
+set srcfile ${test}.c
+if { [prepare_for_testing ${test}.exp ${test} ${srcfile}] } {
+    return -1
+}
+
+if ![runto "marker"] {
+    return -1
+}
+
+set test "print child"
+gdb_test_multiple $test $test {
+    -re " = (\[0-9\]+)\r\n$gdb_prompt $" {
+	pass $test
+	set child $expect_out(1,string)
+    }
+}
+
+gdb_test "attach $child" "Attaching to program: .*, process $child\r\n.*" \
+	 "attach" \
+	 {A program is being debugged already\.  Kill it\? \(y or n\) } "y"
+
+gdb_test_no_output "set variable resume=1"
+#gdb_test "maintenance set show-debug-regs on"
+gdb_test "awatch check" {Hardware access \(read/write\) watchpoint [0-9]+: check}
+
+set test "stepi"
+gdb_test_multiple $test $test {
+    -re "\r\nHardware access \\(read/write\\) watchpoint \[0-9\]+: check\r\n.*\r\n$gdb_prompt $" {
+	fail $test
+    }
+    -re "\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
+
+gdb_test "kill" "" "kill" \
+	 {Kill the program being debugged\? \(y or n\) } "y"

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-11 23:39     ` Jan Kratochvil
@ 2011-12-12 11:53       ` Pedro Alves
  2011-12-12 14:49         ` Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-12 11:53 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tristan Gingold, gdb-patches, Yao Qi

On Sunday 11 December 2011 20:32:57, Jan Kratochvil wrote:
> On Fri, 09 Dec 2011 17:30:20 +0100, Pedro Alves wrote:
> > On Monday 05 December 2011 20:25:13, Jan Kratochvil wrote:
> > > The patchset
> > > 	[patch 0/4] hw watchpoints across fork() + multi-inf
> > > 
> > > which I am rebasing now on top of HEAD which already reimplements its part by
> > > 	commit 96fd921972966166fda0eb300bfa4e5479f3b31f
> > > 	Author: Pedro Alves <pedro@codesourcery.com>
> > > 	Date:   Fri Jul 22 16:58:30 2011 +0000
> > > 	http://sourceware.org/ml/gdb-patches/2011-07/msg00586.html
> > 
> > You mean you were already pulling in this non-stop change from
> > gdbserver?  :-(
> 
> Last time you stopped that patchset due to referenced merging with gdbserver
> 	http://sourceware.org/ml/gdb-patches/2010-12/msg00348.html

As seen on that email, the main objections were:

" gdbserver already has a per-process structure for the debug registers,
  yet, your implementation is different, which makes it gratuitously harder
  to share and move code between the gdb and gdbserver implementations. "

" gdbserver gets away without the iteration over all threads setting the
  debug registers synchronously, which merged to native gdb, I think
  could get rid of some of the churn in your patches, I think, in addition
  to fixing watchpoints in non-stop mode (PR10729). "

The latter is what my patch now brings to gdb.  In my mind, I was even
helping get those patches closer to being mainlined...

> which AFAIK Yao Qi was working on but which has not yet happened, so not sure
> how more years it cannot get merged.  

The patches I mentioned that would move some shareable bits of
gdb and gdbserver into common/, seeding the way to duplication
removal were Kwok's.  They are in now.  Note, seeding, not getting
rid of the all the duplication.  Yao's common/ work earlier in the year
was a personal effort, AFAIK.

> It was probably my wrong assumption for
> the last year the i386-nat.c merging with gdbserver was being worked on while
> in fact you only mentioned it would be good to do.

Right.  There's chances I may be able to help with the effort of merging
target side code between gdb and gdbserver next year, but no promises.
AFAICS, Ulrich has actually been quietly taking the lead, pushing
to gdbserver features currently only native debugging supports.

> > --- a/gdb/mi/mi-main.c
> > +++ b/gdb/mi/mi-main.c
> > @@ -1743,12 +1743,11 @@ mi_cmd_list_target_features (char *command, char **argv, int argc)
> >        struct cleanup *cleanup = NULL;
> >        struct ui_out *uiout = current_uiout;
> >  
> > -      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");      
> > +      cleanup = make_cleanup_ui_out_list_begin_end (uiout, "features");
> >        if (target_can_async_p ())
> >  	ui_out_field_string (uiout, NULL, "async");
> >        if (target_can_execute_reverse)
> >  	ui_out_field_string (uiout, NULL, "reverse");
> > -      
> >        do_cleanups (cleanup);
> >        return;
> >      }
> 
> Unrelated whitespace cleanup only.  Not present in the ChangeLog.

Whoops.  Not supposed to be there.  Thanks.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 11:53       ` Pedro Alves
@ 2011-12-12 14:49         ` Jan Kratochvil
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-12 14:49 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tristan Gingold, gdb-patches, Yao Qi, Doug Evans

On Mon, 12 Dec 2011 12:20:31 +0100, Pedro Alves wrote:
> " gdbserver already has a per-process structure for the debug registers,
>   yet, your implementation is different, which makes it gratuitously harder
>   to share and move code between the gdb and gdbserver implementations. "

While I agree that current FSF GDB state is what it is and I have to new gdb
patch the same as the checked-in gdbserver patch it was chronologically the
opposite way as I stated in:
	http://sourceware.org/ml/gdb-patches/2011-01/msg00561.html

The Doug's gdbserver patch was posted 18 months after the gdb patch of mine
being ignored.


> " gdbserver gets away without the iteration over all threads setting the
>   debug registers synchronously, which merged to native gdb, I think
>   could get rid of some of the churn in your patches, I think, in addition
>   to fixing watchpoints in non-stop mode (PR10729). "
> 
> The latter is what my patch now brings to gdb.  In my mind, I was even
> helping get those patches closer to being mainlined...

Therefore:

* I will rebase the 2007 patch on this 2011 non-stop patch of yours.

* I will rename structures of the 2007 patch to the 2009 gdbserver one.

  * Depending on how feasible it will be I will then unify the structures into
    gdb/common/ as nobody else is working on this part now.

I hope this plan is OK to get the 2007 patch checked in.

I do not understand why to deal with watchpoints as they still do not work
even for GDB-on-GDB debugging as they stop working already during the
grand-inferior fork.  Moreover the same happens with any desktop apps.


Regards,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12  0:14     ` Jan Kratochvil
@ 2011-12-12 17:23       ` Pedro Alves
  2011-12-12 18:38         ` Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-12 17:23 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tristan Gingold, gdb-patches

On Sunday 11 December 2011 23:38:11, Jan Kratochvil wrote:
> Hi Pedro,
> 
> on simple non-hit (inferior does not touch "j" at all) watchpoint case:
> strace -o 2 -q ./gdb -nx ./36 -ex start -ex 'watch j' -ex stepi -ex 'set confirm no' -ex q
> grep 'PTRACE_....USER' 1 >1b; grep 'PTRACE_....USER' 2 >2b
> 
> It has performance regression of 15 ptrace syscalls -> 27 ptrace syscalls.

Hmm.  Before, a single step (si) (instead of all syscalls fro the
begining) does:

$ tail -f 1 | grep PTRACE_P...USER
ptrace(PTRACE_POKEUSER, 15618, offsetof(struct user, u_debugreg), 0x601028) = 0
ptrace(PTRACE_PEEKUSER, 15618, offsetof(struct user, u_debugreg) + 48, [0x4000]) = 0
ptrace(PTRACE_POKEUSER, 15618, offsetof(struct user, u_debugreg) + 48, 0x4000) = 0
ptrace(PTRACE_POKEUSER, 15618, offsetof(struct user, u_debugreg) + 56, 0xd0101) = 0
ptrace(PTRACE_PEEKUSER, 15618, offsetof(struct user, u_debugreg) + 48, [0x4000]) = 0
ptrace(PTRACE_POKEUSER, 15618, offsetof(struct user, u_debugreg), 0) = 0
ptrace(PTRACE_POKEUSER, 15618, offsetof(struct user, u_debugreg) + 56, 0xd0100) = 0

So, 7 related ptrace calls.

After the patch, just one single-step does:

$ tail -f 2 | grep PTRACE_P...USER

ptrace(PTRACE_POKEUSER, 16139, offsetof(struct user, u_debugreg), 0x601028) = 0
ptrace(PTRACE_POKEUSER, 16139, offsetof(struct user, u_debugreg) + 8, 0) = 0
ptrace(PTRACE_POKEUSER, 16139, offsetof(struct user, u_debugreg) + 16, 0) = 0
ptrace(PTRACE_POKEUSER, 16139, offsetof(struct user, u_debugreg) + 24, 0) = 0
ptrace(PTRACE_POKEUSER, 16139, offsetof(struct user, u_debugreg) + 56, 0xd0101) = 0
ptrace(PTRACE_PEEKUSER, 16139, offsetof(struct user, u_debugreg) + 48, [0x4000]) = 0
ptrace(PTRACE_PEEKUSER, 16139, offsetof(struct user, u_debugreg) + 56, [0xd0101]) = 0

Still 7 related ptrace syscalls.

The 15 -> 27 jump in all PTRACE_P...USER syscalls is because for all stops,
we're now reading both DR_STATUS and DR_CONTROL, while before
we were only reading DR_STATUS.  And there are stops in starting up an inferior
until it reaches main.  That looks easily fixed.

In addition, before, we'd only poke to DR[N] if the register was used,
now (i386|amd64)_linux_prepare_to_resume always writes all of DR0-3,
even when only one DR is used.  That's looks easily fixed too.

I'm trying out this patch:

 gdb/amd64-linux-nat.c |    3 ++-
 gdb/i386-nat.c        |   26 ++++++++++++++++++--------
 2 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index 9699f84..dc6a735 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -390,7 +390,8 @@ amd64_linux_prepare_to_resume (struct lwp_info *lwp)
       struct i386_debug_reg_state *state = i386_debug_reg_state ();
 
       for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-	amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
+	if (state->dr_ref_count[i] > 0)
+	  amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
 
       amd64_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
 
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 94306a1..6d59b14 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -607,22 +607,32 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
   int rc = 0;
   unsigned status;
   unsigned control;
+  unsigned control_p = 0;
 
   /* Get the current values the inferior has.  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 ();
-  control = i386_dr_low.get_control ();
 
   ALL_DEBUG_REGISTERS(i)
     {
-      if (I386_DR_WATCH_HIT (status, i)
-	  /* 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.  */
-	  && I386_DR_GET_RW_LEN (control, i) != 0)
+      if (!I386_DR_WATCH_HIT (status, i))
+	continue;
+
+      /* Fetching DR_CONTROL may require another syscall.  Avoid when
+	 possible.  */
+      if (!control_p)
+	{
+	  control = i386_dr_low.get_control ();
+	  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);
 	  rc = 1;


With those changes, we're actually even better than before.  Your
example when from 15 -> 12.  A single stepi that doesn't trigger a
watchpoint only does:

ptrace(PTRACE_POKEUSER, 23332, offsetof(struct user, u_debugreg), 0x601028) = 0
ptrace(PTRACE_POKEUSER, 23332, offsetof(struct user, u_debugreg) + 56, 0xd0101) = 0
ptrace(PTRACE_PEEKUSER, 23332, offsetof(struct user, u_debugreg) + 48, [0x4000]) = 0

That is, write DR0 and DR_CONTROL on resume, and, read DR_STATUS on stop.

> On Fri, 09 Dec 2011 17:30:20 +0100, Pedro Alves wrote:
> > @@ -513,22 +499,7 @@ i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state)
> >    ALL_DEBUG_REGISTERS (i)
> >      {
> >        if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (&dr_mirror, i))
> > -	{
> > -	  if (!I386_DR_VACANT (new_state, i))
> > -	    {
> > -	      i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
> > -
> 
> 
> > -	      /* Only a sanity check for leftover bits (set possibly only
> > -		 by inferior).  */
> > -	      if (i386_dr_low.unset_status)
> > -		i386_dr_low.unset_status (I386_DR_WATCH_MASK (i));
> 
> Deleting this part is a regression.  Testcase for that part is attached.

Thanks a lot, I'll take a look.  I had assumed this bit:

  if (lwp->stopped_by_watchpoint)
    amd64_linux_dr_set (lwp->ptid, DR_STATUS, 0);

in amd64_linux_prepare_to_resume would fix the issue.

> 
> > +	  && I386_DR_GET_RW_LEN (control, i) != 0)
> >  	{
> > -	  addr = state->dr_mirror[i];
> > +	  addr = i386_dr_low.get_addr (i);
> 
> Why to do this change?  Why we can no longer trust DR_MIRROR?  This is
> a performance regression.

This is non-stop, so threads can be running while we change the
global state->dr_mirror (and friends).  Say, we set a watchpoint,
and let the threads rusume.  Now, say you delete the watchpoint, or
add/remove watchpoints such that state->dr_mirror[*] changes.  Inserting/deleting
watchpoines updates state->dr_mirror[*].  Now threads haven't been updated
with the mirror yet, and say a thread has meanwhile hit an old watchpoint,
but we haven't handled the SIGTRAP yet.  If we trusted state->dr_mirror[*],
we'd mistake the real trapped address to whatever was
currently state->dr_mirror[i].  So state->dr_mirror now represents
intention.  To get at the address that trapped, we need to read the
state the thread had when it trapped.  I'll add some comments to the code.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 17:23       ` Pedro Alves
@ 2011-12-12 18:38         ` Jan Kratochvil
  2011-12-12 20:14           ` Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-12 18:38 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tristan Gingold, gdb-patches

On Mon, 12 Dec 2011 17:56:44 +0100, Pedro Alves wrote:
> I'm trying out this patch:

That's great, thanks.


> > Deleting this part is a regression.  Testcase for that part is attached.

I will yet update the testcase to support gdbserver.


> > > +	  && I386_DR_GET_RW_LEN (control, i) != 0)
> > >  	{
> > > -	  addr = state->dr_mirror[i];
> > > +	  addr = i386_dr_low.get_addr (i);
> > 
> > Why to do this change?  Why we can no longer trust DR_MIRROR?  This is
> > a performance regression.
> 
> This is non-stop, so threads can be running while we change the
> global state->dr_mirror (and friends).  Say, we set a watchpoint,
> and let the threads rusume.  Now, say you delete the watchpoint, or
> add/remove watchpoints such that state->dr_mirror[*] changes.  Inserting/deleting
> watchpoines updates state->dr_mirror[*].  Now threads haven't been updated
> with the mirror yet, and say a thread has meanwhile hit an old watchpoint,
> but we haven't handled the SIGTRAP yet.  If we trusted state->dr_mirror[*],
> we'd mistake the real trapped address to whatever was
> currently state->dr_mirror[i].  So state->dr_mirror now represents
> intention.  To get at the address that trapped, we need to read the
> state the thread had when it trapped.  I'll add some comments to the code.

Thanks for the explanation, yes, comment would be great.

As there is a state for each inferior in the multi-inferior patch of mine it
may be useful to change it to be per-TID so these ptrace reads can be avoided.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 18:38         ` Jan Kratochvil
@ 2011-12-12 20:14           ` Jan Kratochvil
  2011-12-12 20:30             ` Pedro Alves
  2011-12-12 20:34             ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
  0 siblings, 2 replies; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-12 20:14 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tristan Gingold, gdb-patches

On Mon, 12 Dec 2011 18:22:38 +0100, Jan Kratochvil wrote:
> I will yet update the testcase to support gdbserver.

Here you are.

I have deleted now from:
http://sourceware.org/gdb/wiki/TestingGDB#Native_Board_File
	# Can't do hardware watchpoints, in general.
	set_board_info gdb,no_hardware_watchpoints 1

as all the new tests PASS for me on
{x86_64,x86_64-m32,i686}-fedora16-linux-gnu.  There is just:
 Running gdb/testsuite/gdb.base/watchpoint-hw.exp ...
+PASS: gdb.base/watchpoint-hw.exp: watch watchee
+UNTESTED: gdb.base/watchpoint-hw.exp: start

but that was discussed elsewhere that gdb_start_cmd should be rather removed.


Regards,
Jan


gdb/testsuite/
2011-12-12  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.base/watchpoint-hw-pre-hit.c: New file.
	* gdb.base/watchpoint-hw-pre-hit.exp: New file.

--- /dev/null
+++ b/gdb/testsuite/gdb.base/watchpoint-hw-pre-hit.c
@@ -0,0 +1,118 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#define _GNU_SOURCE 1
+#include <sys/ptrace.h>
+#include <linux/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/debugreg.h>
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+
+static pid_t child;
+
+static void
+cleanup (void)
+{
+  if (child > 0)
+    kill (child, SIGKILL);
+  child = 0;
+}
+
+static void
+handler_fail (int signo)
+{
+  cleanup ();
+  signal (signo, SIG_DFL);
+  raise (signo);
+}
+
+static volatile int dummy;
+
+static void
+marker (void)
+{
+  dummy++;
+}
+
+static int check, resume;
+
+int
+main (void)
+{
+  pid_t got_pid;
+  int i, status, cycles = 0;
+  long l;
+
+  /* Unused variable.  */
+  check = 0;
+
+  atexit (cleanup);
+  signal (SIGABRT, handler_fail);
+  signal (SIGINT, handler_fail);
+
+  child = fork ();
+  switch (child)
+    {
+    case -1:
+      assert (0);
+    case 0:
+      l = ptrace (PTRACE_TRACEME, 0, NULL, NULL);
+      assert (l == 0);
+
+      i = raise (SIGUSR1);
+      assert (i == 0);
+
+      while (!resume && cycles++ < 600 * 10)
+	usleep (1000000 / 10);
+
+      marker ();
+
+      assert (0);
+    default:
+      break;
+    }
+
+  got_pid = waitpid (child, &status, 0);
+  assert (got_pid == child);
+  assert (WIFSTOPPED (status));
+  assert (WSTOPSIG (status) == SIGUSR1);
+
+  /* Set all 4 watchpoint registers as hit.  It may remain set this way from
+     a different debugger or internal use of ptrace in the application etc.  */
+  errno = 0;
+  l = ptrace (PTRACE_POKEUSER, child, offsetof (struct user, u_debugreg[6]),
+	      0xFUL);
+  assert_perror (errno);
+  assert (l == 0);
+
+  errno = 0;
+  l = ptrace (PTRACE_DETACH, child, NULL, NULL);
+  assert_perror (errno);
+  assert (l == 0);
+
+  marker ();
+
+  return 0;
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/watchpoint-hw-pre-hit.exp
@@ -0,0 +1,73 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test a newly created hardware watchpoint gets cleared its possible pre-set
+# hit in the status register.  Otherwise a false hit may occur.
+
+load_lib gdbserver-support.exp
+
+if {[skip_hw_watchpoint_access_tests]
+    || (![istarget "i?86-*-linux*"] && ![istarget "x86_64-*-linux*"])
+    || ([is_remote target] && [skip_gdbserver_tests])} {
+    return 0
+}
+
+set test watchpoint-hw-pre-hit
+set srcfile ${test}.c
+if { [prepare_for_testing ${test}.exp ${test} ${srcfile}] } {
+    return -1
+}
+
+if ![runto "marker"] {
+    return -1
+}
+
+set test "print child"
+gdb_test_multiple $test $test {
+    -re " = (\[0-9\]+)\r\n$gdb_prompt $" {
+	pass $test
+	set child $expect_out(1,string)
+    }
+}
+
+gdb_test "kill" "" "kill" \
+	 {Kill the program being debugged\? \(y or n\) } "y"
+
+if [is_remote target] {
+    gdbserver_start_extended
+}
+
+gdb_test "attach $child" "(Attaching to program: .*, process $child|Attached to process $child)\r\n.*" \
+	 "attach"
+
+gdb_test_no_output "set variable resume=1"
+#gdb_test "maintenance set show-debug-regs on"
+gdb_test "awatch check" {Hardware access \(read/write\) watchpoint [0-9]+: check}
+
+if [is_remote target] {
+    setup_kfail remote/13492 "*-*-*"
+}
+set test "stepi"
+gdb_test_multiple $test $test {
+    -re "\r\nHardware access \\(read/write\\) watchpoint \[0-9\]+: check\r\n.*\r\n$gdb_prompt $" {
+	fail $test
+    }
+    -re "\r\n$gdb_prompt $" {
+	pass $test
+    }
+}
+
+gdb_test "kill" "" "kill" \
+	 {Kill the program being debugged\? \(y or n\) } "y"

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 20:14           ` Jan Kratochvil
@ 2011-12-12 20:30             ` Pedro Alves
  2011-12-13 17:24               ` Jan Kratochvil
  2011-12-12 20:34             ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
  1 sibling, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-12 20:30 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Tristan Gingold, gdb-patches

On Monday 12 December 2011 18:37:34, Jan Kratochvil wrote:
> On Mon, 12 Dec 2011 18:22:38 +0100, Jan Kratochvil wrote:
> > I will yet update the testcase to support gdbserver.
> 
> Here you are.
> 
> I have deleted now from:
> http://sourceware.org/gdb/wiki/TestingGDB#Native_Board_File
> 	# Can't do hardware watchpoints, in general.
> 	set_board_info gdb,no_hardware_watchpoints 1
> 
> as all the new tests PASS for me on
> {x86_64,x86_64-m32,i686}-fedora16-linux-gnu.  

Yeah.  

Maybe we should still have something like

if { istarget [ia64*-*-*] || .... } {
  set_board_info gdb,no_hardware_watchpoints 1
}

somewhere gdbserver specific.  Some ports, like ia64 gdbserver
don't support watchpoints.  I think you can test a native
gdbserver with this board on ia64-linux, but this isn't really
native board specific --- a cross test should find watchpoints
support disabled too.  Maybe in gdbserver-support.exp?  WDYT?

> +
> +load_lib gdbserver-support.exp
> +
> +if {[skip_hw_watchpoint_access_tests]
> +    || (![istarget "i?86-*-linux*"] && ![istarget "x86_64-*-linux*"])
> +    || ([is_remote target] && [skip_gdbserver_tests])} {
> +    return 0
> +}


> +
> +if [is_remote target] {
> +    gdbserver_start_extended
> +}

Hmm, I'm not sure if this is really a good idea to spread
gdbserver_start_extended around like this.  I think it would be
better to skip the test if testing against plain "target remote".
I mean, you may be remote testing against qemu, for example.  Having
the test spawn GDBserver and actually run would be misleading.  Once
we have a board that tests the whole testsuite with extended-remote
working, then we'll clearly want the present board to skip tests
it doesn't support.  (the gdb.server/ tests being the exception.)
WDYT?

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 20:14           ` Jan Kratochvil
  2011-12-12 20:30             ` Pedro Alves
@ 2011-12-12 20:34             ` Pedro Alves
  2011-12-12 21:39               ` Jan Kratochvil
  1 sibling, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-12 20:34 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Thanks again for the test.

I'm wondering why bother to mask out DR_STATUS bits instead
of clearing all of it.  I mean, when we set a watchpoint, we're
already clobbering the whole of DR_CONTROL, with

  i386_dr_low.set_control (new_state->dr_control_mirror);

so it seems there's no point in trying to retain all the other
bits of DR_STATUS.  If we set a watchpoint, any change the
inferior had done itself to the debug registers is thrown
out the window.

If I change amd64_linux_prepare_to_resume to look like:

static void
amd64_linux_prepare_to_resume (struct lwp_info *lwp)
{
  int clear_status = 0;

  if (lwp->arch_private->debug_registers_changed)
    {
      struct i386_debug_reg_state *state = i386_debug_reg_state ();
      int i;

      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
	if (state->dr_ref_count[i] > 0)
	  {
	    amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);

	    /* Only a sanity check for leftover bits (set possibly
	       only by inferior).  */
	    clear_status = 1;
	  }

      amd64_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);

      lwp->arch_private->debug_registers_changed = 0;
    }

  if (clear_status || lwp->stopped_by_watchpoint)
    amd64_linux_dr_set (lwp->ptid, DR_STATUS, 0);
}

(the `clear_status' bits are new) then the new test passes.

I'm doing a full run with this now.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 20:34             ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
@ 2011-12-12 21:39               ` Jan Kratochvil
  2011-12-13 16:21                 ` Fix PR remote/13492 (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
  2011-12-13 16:33                 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
  0 siblings, 2 replies; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-12 21:39 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Mon, 12 Dec 2011 21:30:25 +0100, Pedro Alves wrote:
> so it seems there's no point in trying to retain all the other
> bits of DR_STATUS.

I agree and I agree with this patch part.

(I do not agree for example with the lwp->stopped_by_watchpoint part as
multiple watchpoints may get hit on one stop which isn't handled well but that
is out of the scope of this discussion.)


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: New tests to watch regions larger than a machine word (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode)
  2011-12-09 19:11     ` Eli Zaretskii
@ 2011-12-13 16:12       ` Pedro Alves
  0 siblings, 0 replies; 37+ messages in thread
From: Pedro Alves @ 2011-12-13 16:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Friday 09 December 2011 19:05:00, Eli Zaretskii wrote:
> > From: Pedro Alves
> > > and also with watchpoints that watch regions longer than 4
> > > bytes on IA32 (and similarly on 64-bit hosts).
> > 
> > This however doesn't seem to be tested anywhere.
> > 
> > Here are a couple new tests to exercise that.  They pass cleanly
> > before and after the proposed patch, native and gdbserver linux,
> > x86 and x86_64.
> 
> Thanks.

You're welcome.  I've now checked in these new tests.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Fix PR remote/13492 (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode)
  2011-12-12 21:39               ` Jan Kratochvil
@ 2011-12-13 16:21                 ` Pedro Alves
  2011-12-13 17:23                   ` Fix PR remote/13492 Jan Kratochvil
  2011-12-13 16:33                 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
  1 sibling, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-13 16:21 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Monday 12 December 2011 20:34:09, Jan Kratochvil wrote:
> On Mon, 12 Dec 2011 21:30:25 +0100, Pedro Alves wrote:
> > so it seems there's no point in trying to retain all the other
> > bits of DR_STATUS.
> 
> I agree and I agree with this patch part.

Thanks.  I've applied the patch below to gdbserver, which adds these
bits we've discussed, and fixes PR13492.

> (I do not agree for example with the lwp->stopped_by_watchpoint part as
> multiple watchpoints may get hit on one stop which isn't handled well but that
> is out of the scope of this discussion.)

I'm not 100% certain that is possible, but in any case, I think that
even if we handled that, we wouldn't ever get as far as
prepare_to_resume before handling all the multiple watchpoints.

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.
---
 gdb/gdbserver/i386-low.c      |   58 +++++++++++++++++++++++++++++++++--------
 gdb/gdbserver/linux-x86-low.c |   14 ++++++++--
 2 files changed, 59 insertions(+), 13 deletions(-)

Index: src/gdb/gdbserver/i386-low.c
===================================================================
--- src.orig/gdb/gdbserver/i386-low.c	2011-07-25 19:59:47.693736296 +0100
+++ src/gdb/gdbserver/i386-low.c	2011-12-13 16:06:49.422184996 +0000
@@ -559,24 +559,60 @@ i386_low_stopped_data_address (struct i3
   CORE_ADDR addr = 0;
   int i;
   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;
+  /* 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;
 
-  /* Get the current values the inferior has.  If the thread was
-     running when we last changed watchpoints, the mirror no longer
-     represents what was set in this LWP's debug registers.  */
+  /* In non-stop/async, threads can be running while we change the
+     global dr_mirror (and friends).  Say, we set a watchpoint, and
+     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 ();
-  control = i386_dr_low_get_control ();
 
   ALL_DEBUG_REGISTERS (i)
     {
-      if (I386_DR_WATCH_HIT (status, i)
-	  /* 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.  */
-	  && I386_DR_GET_RW_LEN (control, i) != 0)
+      if (!I386_DR_WATCH_HIT (status, i))
+	continue;
+
+      if (!control_p)
+	{
+	  control = i386_dr_low_get_control ();
+	  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);
 	  rc = 1;
Index: src/gdb/gdbserver/linux-x86-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-x86-low.c	2011-11-22 13:39:14.172391873 +0000
+++ src/gdb/gdbserver/linux-x86-low.c	2011-12-13 16:08:11.862184967 +0000
@@ -655,6 +655,7 @@ static void
 x86_linux_prepare_to_resume (struct lwp_info *lwp)
 {
   ptid_t ptid = ptid_of (lwp);
+  int clear_status = 0;
 
   if (lwp->arch_private->debug_registers_changed)
     {
@@ -665,14 +666,23 @@ x86_linux_prepare_to_resume (struct lwp_
 	= &proc->private->arch_private->debug_reg_state;
 
       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);
 
       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);
 }
 \f

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-09 19:23     ` Eli Zaretskii
@ 2011-12-13 16:26       ` Pedro Alves
  0 siblings, 0 replies; 37+ messages in thread
From: Pedro Alves @ 2011-12-13 16:26 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches

On Friday 09 December 2011 19:10:22, Eli Zaretskii wrote:

> My extra pair of eyes spotted this:
> 
> > --- a/gdb/go32-nat.c
> > +++ b/gdb/go32-nat.c
> > @@ -801,6 +801,28 @@ go32_get_dr6 (void)
> >    return STATUS;
> >  }
> >  
> > +/* Get the value of the DR6 debug status register from the inferior.
> > +   Here we just return the value stored in D_REGS, as we've got it
> > +   from the last go32_wait call.  */
> > +static unsigned long
> > +go32_get_dr7 (void)
> > +{
> > +  return CONTROL;
> > +}
> 
> The comment says DR6, but the function uses dr7.  I think the comment
> is wrong.

Indeed.  I copied the comment from go32_get_dr6, and forgot to adjust.
Fixed now.

> No other comments.  Thanks.

Thanks a lot.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 21:39               ` Jan Kratochvil
  2011-12-13 16:21                 ` Fix PR remote/13492 (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
@ 2011-12-13 16:33                 ` Pedro Alves
  2011-12-13 18:57                   ` Jan Kratochvil
  2011-12-13 22:27                   ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil
  1 sibling, 2 replies; 37+ messages in thread
From: Pedro Alves @ 2011-12-13 16:33 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

Here's the current version of the GDB patch.

Anything else I should address?  

Since we just branched, I'm a bit less worried about
breaking things on other platforms.  :-)

gdb/
2011-12-13  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* linux-nat.c (linux_nat_new_thread): Change parameter to an lwp
	pointer.
	(linux_nat_prepare_to_resume): New global.
	(lwp_free): New.
	(purge_lwp_list): Use it.
	(add_lwp): Call linux_nat_new_thread even on the first LWP.
	Adjust to interface change.
	(delete_lwp): Call lwp_free instead of xfree.
	(resume_lwp, linux_nat_resume, linux_handle_syscall_trap)
	(linux_handle_extended_wait, linux_nat_filter_event)
	(linux_nat_filter_event): Call linux_nat_prepare_to_resume before
	resuming.
	(linux_stop_lwp): New.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.
	* linux-nat.h (struct arch_lwp_info): Forward declare.
	(struct lwp_info) <arch_private>: New field.
	(linux_stop_lwp): Declare.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.

	* i386-nat.c (DR_NADDR, DR_STATUS, DR_CONTROL)
	(struct i386_debug_reg_state): Move to i386-nat.h.
	(dr_mirror): Comment.
	(i386_debug_reg_state): New.
	(i386_update_inferior_debug_regs): Simplify.
	(i386_stopped_data_address): Use the debug register state from the
	inferior, not from the local cache.
	* i386-nat.h (struct i386_dr_low_type): Delete reset_addr and
	unset_status fields.  New get_addr and get_control fields.
	(DR_FIRSTADDR, DR_LASTADDR, DR_CONTROL): Moved from i386-nat.c.
	(DR_NADDR, DR_STATUS): New.
	(struct i386_debug_reg_state): Moved from i386-nat.c.

	* amd64-linux-nat.c (struct arch_lwp_info): New.
	(amd64_linux_dr): Delete global.
	(amd64_linux_dr_get_addr): New.
	(amd64_linux_dr_get_control): New.
	(amd64_linux_dr_unset_status): Delete.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_dr_reset_addr): Delete.
	(update_debug_registers_callback): New.
	(amd64_linux_dr_set_control): Reimplement.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_prepare_to_resume): New.
	(amd64_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_amd64_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	amd64_linux_dr_get_control as i386_dr_low.get_control.  Install
	amd64_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	amd64_linux_prepare_to_resume.
	* i386-darwin-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(i386_darwin_dr_reset_addr): Delete.
	(i386_darwin_dr_get_addr): New.
	(i386_darwin_dr_get_control): New.
	* i386-linux-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(struct arch_lwp_info): New.
	(i386_linux_dr): Delete global.
	(i386_linux_dr_set_control): Reimplement.
	(i386_linux_dr_get_addr): New.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_dr_get_control): New.
	(update_debug_registers_callback): New.
	(i386_linux_dr_unset_status): Delete.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_prepare_to_resume): New.
	(i386_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_i386_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386_linux_dr_get_control as i386_dr_low.get_control.  Install
	i386_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	i386_linux_prepare_to_resume.

	* go32-nat.c
	(go32_get_dr7, go32_get_dr): New.
	(init_go32_ops): No longer install i386_dr_low.reset_addr.
	Install go32_get_dr7 as i386_dr_low.get_control.  Install
	go32_get_dr as i386_dr_low.get_addr.
	* i386bsd-nat.c (i386bsd_dr_get): New.
	(i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_status): Use i386bsd_dr_get.
	(i386bsd_dr_get_control): New.
	* i386bsd-nat.h (i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_control): New.
	* i386fbsd-nat.c (_initialize_i386fbsd_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386bsd_dr_get_control as i386_dr_low.get_control.  Install
	i386bsd_dr_get_addr as i386_dr_low.get_addr.
	* windows-nat.c (init_windows_ops): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	cygwin_get_dr7 as i386_dr_low.get_control.  Install cygwin_get_dr
	as i386_dr_low.get_addr.
	(cygwin_get_dr): New.
	(cygwin_get_dr7): New.

gdb/testsuite/
2011-12-07  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* gdb.mi/watch-nonstop.c: New file.
 	* gdb.mi/mi-watch-nonstop.exp: New file.
---

 gdb/amd64-linux-nat.c                     |  130 ++++++++++++++++++--------
 gdb/go32-nat.c                            |   26 +++++
 gdb/i386-darwin-nat.c                     |   31 ++----
 gdb/i386-linux-nat.c                      |  143 ++++++++++++++++++-----------
 gdb/i386-nat.c                            |  111 ++++++++++++-----------
 gdb/i386-nat.h                            |   42 +++++++--
 gdb/i386bsd-nat.c                         |   32 ++++--
 gdb/i386bsd-nat.h                         |    4 +
 gdb/i386fbsd-nat.c                        |    3 -
 gdb/linux-nat.c                           |   63 ++++++++++++-
 gdb/linux-nat.h                           |   14 +++
 gdb/testsuite/gdb.mi/mi-watch-nonstop.exp |   77 ++++++++++++++++
 gdb/testsuite/gdb.mi/watch-nonstop.c      |   24 +++++
 gdb/windows-nat.c                         |   21 ++++
 14 files changed, 521 insertions(+), 200 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
 create mode 100644 gdb/testsuite/gdb.mi/watch-nonstop.c

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index c673965..288160b 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -64,6 +64,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 
@@ -265,8 +273,6 @@ amd64_linux_store_inferior_registers (struct target_ops *ops,
 \f
 /* Support for debug registers.  */
 
-static unsigned long amd64_linux_dr[DR_CONTROL + 1];
-
 static unsigned long
 amd64_linux_dr_get (ptid_t ptid, int regnum)
 {
@@ -304,75 +310,116 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-amd64_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+amd64_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  amd64_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return amd64_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+amd64_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+
+static unsigned long
+amd64_linux_dr_get_status (void)
+{
+  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+}
+
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
+
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
+{
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
 
-  amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+  return 0;
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Set DR_CONTROL to CONTROL in all LWPs of the current inferior.  */
 
 static void
-amd64_linux_dr_reset_addr (int regnum)
+amd64_linux_dr_set_control (unsigned long control)
 {
-  amd64_linux_dr_set_addr (regnum, 0);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
-static unsigned long
-amd64_linux_dr_get_status (void)
+static void
+amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
 
 static void
-amd64_linux_dr_unset_status (unsigned long mask)
+amd64_linux_prepare_to_resume (struct lwp_info *lwp)
 {
-  struct lwp_info *lp;
+  int clear_status = 0;
 
-  ALL_LWPS (lp)
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
-      
-      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+      int i;
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	if (state->dr_ref_count[i] > 0)
+	  {
+	    amd64_linux_dr_set (lwp->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_stopped_data_address can get
+	       confused.  */
+	    clear_status = 1;
+	  }
+
+      amd64_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
-}
 
+  if (clear_status || lwp->stopped_by_watchpoint)
+    amd64_linux_dr_set (lwp->ptid, DR_STATUS, 0);
+}
 
 static void
-amd64_linux_new_thread (ptid_t ptid)
+amd64_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -785,9 +832,9 @@ _initialize_amd64_linux_nat (void)
 
   i386_dr_low.set_control = amd64_linux_dr_set_control;
   i386_dr_low.set_addr = amd64_linux_dr_set_addr;
-  i386_dr_low.reset_addr = amd64_linux_dr_reset_addr;
+  i386_dr_low.get_addr = amd64_linux_dr_get_addr;
   i386_dr_low.get_status = amd64_linux_dr_get_status;
-  i386_dr_low.unset_status = amd64_linux_dr_unset_status;
+  i386_dr_low.get_control = amd64_linux_dr_get_control;
   i386_set_debug_register_length (8);
 
   /* Override the GNU/Linux inferior startup hook.  */
@@ -804,4 +851,5 @@ _initialize_amd64_linux_nat (void)
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, amd64_linux_new_thread);
   linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup);
+  linux_nat_set_prepare_to_resume (t, amd64_linux_prepare_to_resume);
 }
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 8295adf..79618ec 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -801,6 +801,29 @@ go32_get_dr6 (void)
   return STATUS;
 }
 
+/* Get the value of the DR7 debug status register from the inferior.
+   Here we just return the value stored in D_REGS, as we've got it
+   from the last go32_wait call.  */
+
+static unsigned long
+go32_get_dr7 (void)
+{
+  return CONTROL;
+}
+
+/* Get the value of the DR debug register I from the inferior.  Here
+   we just return the value stored in D_REGS, as we've got it from the
+   last go32_wait call.  */
+
+static CORE_ADDR
+go32_get_dr (int i)
+{
+  if (i < 0 || i > 3)
+    internal_error (__FILE__, __LINE__,
+		    _("Invalid register %d in go32_get_dr.\n"), i);
+  return D_REGS[i];
+}
+
 /* Put the device open on handle FD into either raw or cooked
    mode, return 1 if it was in raw mode, zero otherwise.  */
 
@@ -984,8 +1007,9 @@ init_go32_ops (void)
 
   i386_dr_low.set_control = go32_set_dr7;
   i386_dr_low.set_addr = go32_set_dr;
-  i386_dr_low.reset_addr = NULL;
   i386_dr_low.get_status = go32_get_dr6;
+  i386_dr_low.get_control = go32_get_dr7;
+  i386_dr_low.get_addr = go32_get_dr;
   i386_set_debug_register_length (4);
 
   go32_ops.to_magic = OPS_MAGIC;
diff --git a/gdb/i386-darwin-nat.c b/gdb/i386-darwin-nat.c
index 61e2e15..23f6a6d 100644
--- a/gdb/i386-darwin-nat.c
+++ b/gdb/i386-darwin-nat.c
@@ -263,23 +263,6 @@ i386_darwin_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers, boosted mostly from i386-linux-nat.c.  */
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
-
 static void
 i386_darwin_dr_set (int regnum, uint32_t value)
 {
@@ -410,12 +393,10 @@ i386_darwin_dr_set_addr (int regnum, CORE_ADDR addr)
   i386_darwin_dr_set (DR_FIRSTADDR + regnum, addr);
 }
 
-void
-i386_darwin_dr_reset_addr (int regnum)
+CORE_ADDR
+i386_darwin_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
-
-  i386_darwin_dr_set (DR_FIRSTADDR + regnum, 0L);
+  return i386_darwin_dr_get (regnum);
 }
 
 unsigned long
@@ -424,6 +405,12 @@ i386_darwin_dr_get_status (void)
   return i386_darwin_dr_get (DR_STATUS);
 }
 
+unsigned long
+i386_darwin_dr_get_control (void)
+{
+  return i386_darwin_dr_get (DR_CONTROL);
+}
+
 void
 darwin_check_osabi (darwin_inferior *inf, thread_t thread)
 {
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 7eb49ae..190979b 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -47,22 +47,6 @@
 #include <sys/debugreg.h>
 #endif
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
@@ -83,6 +67,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 \f
@@ -651,8 +643,6 @@ i386_linux_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers.  */
 
-static unsigned long i386_linux_dr[DR_CONTROL + 1];
-
 /* Get debug register REGNUM value from only the one LWP of PTID.  */
 
 static unsigned long
@@ -692,74 +682,116 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-i386_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+i386_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  i386_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return i386_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+i386_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return i386_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
 
-  i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+static unsigned long
+i386_linux_dr_get_status (void)
+{
+  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
+
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
+{
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
+}
+
+/* Set DR_CONTROL to ADDR in all LWPs of the current inferior.  */
 
 static void
-i386_linux_dr_reset_addr (int regnum)
+i386_linux_dr_set_control (unsigned long control)
 {
-  i386_linux_dr_set_addr (regnum, 0);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
-static unsigned long
-i386_linux_dr_get_status (void)
+static void
+i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
 
 static void
-i386_linux_dr_unset_status (unsigned long mask)
+i386_linux_prepare_to_resume (struct lwp_info *lwp)
 {
-  struct lwp_info *lp;
+  int clear_status = 0;
 
-  ALL_LWPS (lp)
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+      int i;
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	if (state->dr_ref_count[i] > 0)
+	  {
+	    i386_linux_dr_set (lwp->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_stopped_data_address can get
+	       confused.  */
+	    clear_status = 1;
+	  }
 
-      value = i386_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      i386_linux_dr_set (lp->ptid, DR_STATUS, value);
+      i386_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
+
+  if (clear_status || lwp->stopped_by_watchpoint)
+    i386_linux_dr_set (lwp->ptid, DR_STATUS, 0);
 }
 
 static void
-i386_linux_new_thread (ptid_t ptid)
+i386_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    i386_linux_dr_set (ptid, i, i386_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -978,9 +1010,9 @@ _initialize_i386_linux_nat (void)
 
   i386_dr_low.set_control = i386_linux_dr_set_control;
   i386_dr_low.set_addr = i386_linux_dr_set_addr;
-  i386_dr_low.reset_addr = i386_linux_dr_reset_addr;
+  i386_dr_low.get_addr = i386_linux_dr_get_addr;
   i386_dr_low.get_status = i386_linux_dr_get_status;
-  i386_dr_low.unset_status = i386_linux_dr_unset_status;
+  i386_dr_low.get_control = i386_linux_dr_get_control;
   i386_set_debug_register_length (4);
 
   /* Override the default ptrace resume method.  */
@@ -999,4 +1031,5 @@ _initialize_i386_linux_nat (void)
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, i386_linux_new_thread);
+  linux_nat_set_prepare_to_resume (t, i386_linux_prepare_to_resume);
 }
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 568b79b..cd479b3 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -43,11 +43,6 @@ struct i386_dr_low_type i386_dr_low;
 /* Support for 8-byte wide hw watchpoints.  */
 #define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8)
 
-/* Debug registers' indices.  */
-#define DR_NADDR	4	/* The number of debug address registers.  */
-#define DR_STATUS	6	/* Index of debug status register (DR6).  */
-#define DR_CONTROL	7	/* Index of debug control register (DR7).  */
-
 /* DR7 Debug Control register fields.  */
 
 /* How many bits to skip in DR7 to get to R/W and LEN fields.  */
@@ -158,23 +153,6 @@ struct i386_dr_low_type i386_dr_low;
 /* A macro to loop over all debug registers.  */
 #define ALL_DEBUG_REGISTERS(i)	for (i = 0; i < DR_NADDR; i++)
 
-
-/* Global state needed to track h/w watchpoints.  */
-
-struct i386_debug_reg_state
-{
-  /* Mirror the inferior's DRi registers.  We keep the status and
-     control registers separated because they don't hold addresses.
-     Note that since we can change these mirrors while threads are
-     running, we never trust them to explain a cause of a trap.
-     For that, we need to peek directly in the inferior registers.  */
-  CORE_ADDR dr_mirror[DR_NADDR];
-  unsigned dr_status_mirror, dr_control_mirror;
-
-  /* Reference counts for each debug register.  */
-  int dr_ref_count[DR_NADDR];
-};
-
 /* Clear the reference counts and forget everything we knew about the
    debug registers.  */
 
@@ -192,8 +170,16 @@ i386_init_dregs (struct i386_debug_reg_state *state)
   state->dr_status_mirror  = 0;
 }
 
+/* The local mirror of the inferior's debug registers.  Currently this
+   is a global, but it should really be per-inferior.  */
 static struct i386_debug_reg_state dr_mirror;
 
+struct i386_debug_reg_state *
+i386_debug_reg_state (void)
+{
+  return &dr_mirror;
+}
+
 /* Whether or not to print the mirrored debug registers.  */
 static int maint_show_dr;
 
@@ -513,22 +499,7 @@ i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state)
   ALL_DEBUG_REGISTERS (i)
     {
       if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (&dr_mirror, i))
-	{
-	  if (!I386_DR_VACANT (new_state, i))
-	    {
-	      i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
-
-	      /* Only a sanity check for leftover bits (set possibly only
-		 by inferior).  */
-	      if (i386_dr_low.unset_status)
-		i386_dr_low.unset_status (I386_DR_WATCH_MASK (i));
-	    }
-	  else
-	    {
-	      if (i386_dr_low.reset_addr)
-		i386_dr_low.reset_addr (i);
-	    }
-	}
+	i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
       else
 	gdb_assert (new_state->dr_mirror[i] == dr_mirror.dr_mirror[i]);
     }
@@ -634,28 +605,62 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
   CORE_ADDR addr = 0;
   int i;
   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;
+  /* 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;
-  struct i386_debug_reg_state *state = &dr_mirror;
 
-  dr_mirror.dr_status_mirror = i386_dr_low.get_status ();
-  status = dr_mirror.dr_status_mirror;
-  control = dr_mirror.dr_control_mirror;
+  /* In non-stop/async, threads can be running while we change the
+     global dr_mirror (and friends).  Say, we set a watchpoint, and
+     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 ();
 
   ALL_DEBUG_REGISTERS(i)
     {
-      if (I386_DR_WATCH_HIT (status, i)
-	  /* 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.  */
-	  && I386_DR_GET_RW_LEN (control, i) != 0
-	  /* This third condition makes sure DRi is not vacant, this
-	     avoids false positives in windows-nat.c.  */
-	  && !I386_DR_VACANT (state, i))
+      if (!I386_DR_WATCH_HIT (status, i))
+	continue;
+
+      if (!control_p)
+	{
+	  control = i386_dr_low.get_control ();
+	  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 = state->dr_mirror[i];
+	  addr = i386_dr_low.get_addr (i);
 	  rc = 1;
 	  if (maint_show_dr)
 	    i386_show_dr (&dr_mirror, "watchpoint_hit", addr, -1, hw_write);
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 819c6b8..1a75daa 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -53,31 +53,54 @@ extern void i386_use_watchpoints (struct target_ops *);
       set_addr                 -- put an address into one debug
 				  register for all LWPs
 
-      reset_addr               -- reset the address stored in
-				  one debug register for all LWPs
+      get_addr                 -- return the address in a given debug
+				  register of the current LWP
 
       get_status               -- return the value of the debug
 				  status (DR6) register for current LWP
 
-      unset_status             -- unset the specified bits of the debug
-				  status (DR6) register for all LWPs
+      get_control               -- return the value of the debug
+				  control (DR7) register for current LWP
 
    Additionally, the native file should set the debug_register_length
    field to 4 or 8 depending on the number of bytes used for
    deubg registers.  */
 
-struct i386_dr_low_type 
+struct i386_dr_low_type
   {
     void (*set_control) (unsigned long);
     void (*set_addr) (int, CORE_ADDR);
-    void (*reset_addr) (int);
+    CORE_ADDR (*get_addr) (int);
     unsigned long (*get_status) (void);
-    void (*unset_status) (unsigned long);
+    unsigned long (*get_control) (void);
     int debug_register_length;
   };
 
 extern struct i386_dr_low_type i386_dr_low;
 
+/* Debug registers' indices.  */
+#define DR_FIRSTADDR 0
+#define DR_LASTADDR  3
+#define DR_NADDR     4	/* The number of debug address registers.  */
+#define DR_STATUS    6	/* Index of debug status register (DR6).  */
+#define DR_CONTROL   7	/* Index of debug control register (DR7).  */
+
+/* Global state needed to track h/w watchpoints.  */
+
+struct i386_debug_reg_state
+{
+  /* Mirror the inferior's DRi registers.  We keep the status and
+     control registers separated because they don't hold addresses.
+     Note that since we can change these mirrors while threads are
+     running, we never trust them to explain a cause of a trap.
+     For that, we need to peek directly in the inferior registers.  */
+  CORE_ADDR dr_mirror[DR_NADDR];
+  unsigned dr_status_mirror, dr_control_mirror;
+
+  /* Reference counts for each debug register.  */
+  int dr_ref_count[DR_NADDR];
+};
+
 /* Use this function to set i386_dr_low debug_register_length field
    rather than setting it directly to check that the length is only
    set once.  It also enables the 'maint set/show show-debug-regs' 
@@ -89,4 +112,9 @@ extern void i386_set_debug_register_length (int len);
 
 extern void i386_cleanup_dregs (void);
 
+/* Return a pointer to the the local mirror of the inferior's debug
+   registers.  */
+
+extern struct i386_debug_reg_state *i386_debug_reg_state (void);
+
 #endif /* I386_NAT_H */
diff --git a/gdb/i386bsd-nat.c b/gdb/i386bsd-nat.c
index fcd772f..22c79e2 100644
--- a/gdb/i386bsd-nat.c
+++ b/gdb/i386bsd-nat.c
@@ -264,6 +264,18 @@ i386bsd_target (void)
 #define DBREG_DRX(d, x) ((&d->dr0)[x])
 #endif
 
+static unsigned long
+i386bsd_dr_get (ptid_t ptid, int regnum)
+{
+  struct dbreg dbregs;
+
+  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
+    perror_with_name (_("Couldn't read debug registers"));
+
+  return DBREG_DRX ((&dbregs), regnum);
+}
+
 static void
 i386bsd_dr_set (int regnum, unsigned int value)
 {
@@ -299,24 +311,22 @@ i386bsd_dr_set_addr (int regnum, CORE_ADDR addr)
   i386bsd_dr_set (regnum, addr);
 }
 
-void
-i386bsd_dr_reset_addr (int regnum)
+CORE_ADDR
+i386bsd_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= 4);
-
-  i386bsd_dr_set (regnum, 0);
+  return i386bsd_dr_get (inferior_ptid, regnum);
 }
 
 unsigned long
 i386bsd_dr_get_status (void)
 {
-  struct dbreg dbregs;
-
-  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
-	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't read debug registers"));
+  return i386bsd_dr_get (inferior_ptid, 6);
+}
 
-  return DBREG_DRX ((&dbregs), 6);
+unsigned long
+i386bsd_dr_get_control (void)
+{
+  return i386bsd_dr_get (inferior_ptid, 7);
 }
 
 #endif /* PT_GETDBREGS */
diff --git a/gdb/i386bsd-nat.h b/gdb/i386bsd-nat.h
index 1c27ed5..df0b0f3 100644
--- a/gdb/i386bsd-nat.h
+++ b/gdb/i386bsd-nat.h
@@ -32,8 +32,10 @@ extern void i386bsd_dr_set_control (unsigned long control);
 
 extern void i386bsd_dr_set_addr (int regnum, CORE_ADDR addr);
 
-extern void i386bsd_dr_reset_addr (int regnum);
+extern CORE_ADDR i386bsd_dr_get_addr (int regnum);
 
 extern unsigned long i386bsd_dr_get_status (void);
 
+extern unsigned long i386bsd_dr_get_control (void);
+
 #endif /* i386bsd-nat.h */
diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c
index ecc797e..52ae031 100644
--- a/gdb/i386fbsd-nat.c
+++ b/gdb/i386fbsd-nat.c
@@ -134,8 +134,9 @@ _initialize_i386fbsd_nat (void)
 
   i386_dr_low.set_control = i386bsd_dr_set_control;
   i386_dr_low.set_addr = i386bsd_dr_set_addr;
-  i386_dr_low.reset_addr = i386bsd_dr_reset_addr;
+  i386_dr_low.get_addr = i386bsd_dr_get_addr;
   i386_dr_low.get_status = i386bsd_dr_get_status;
+  i386_dr_low.get_control = i386bsd_dr_get_control;
   i386_set_debug_register_length (4);
 
 #endif /* HAVE_PT_GETDBREGS */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 19b4b57..d524307 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -175,7 +175,10 @@ static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The method to call, if any, when a new thread is attached.  */
-static void (*linux_nat_new_thread) (ptid_t);
+static void (*linux_nat_new_thread) (struct lwp_info *);
+
+/* Hook to call prior to resuming a thread.  */
+static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
 
 /* The method to call, if any, when the siginfo object needs to be
    converted between the layout returned by ptrace, and the layout in
@@ -1073,6 +1076,15 @@ status_to_str (int status)
   return buf;
 }
 
+/* Destroy and free LP.  */
+
+static void
+lwp_free (struct lwp_info *lp)
+{
+  xfree (lp->arch_private);
+  xfree (lp);
+}
+
 /* Remove all LWPs belong to PID from the lwp list.  */
 
 static void
@@ -1093,7 +1105,7 @@ purge_lwp_list (int pid)
 	  else
 	    lpprev->next = lp->next;
 
-	  xfree (lp);
+	  lwp_free (lp);
 	}
       else
 	lpprev = lp;
@@ -1139,8 +1151,8 @@ add_lwp (ptid_t ptid)
   lp->next = lwp_list;
   lwp_list = lp;
 
-  if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
-    linux_nat_new_thread (ptid);
+  if (linux_nat_new_thread != NULL)
+    linux_nat_new_thread (lp);
 
   return lp;
 }
@@ -1166,7 +1178,7 @@ delete_lwp (ptid_t ptid)
   else
     lwp_list = lp->next;
 
-  xfree (lp);
+  lwp_free (lp);
 }
 
 /* Return a pointer to the structure describing the LWP corresponding
@@ -1825,6 +1837,8 @@ resume_lwp (struct lwp_info *lp, int step)
 				"RC:  PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
 				target_pid_to_str (lp->ptid));
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops,
 				pid_to_ptid (GET_LWP (lp->ptid)),
 				step, TARGET_SIGNAL_0);
@@ -1969,6 +1983,8 @@ linux_nat_resume (struct target_ops *ops,
   /* Convert to something the lower layer understands.  */
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
   lp->stopped_by_watchpoint = 0;
@@ -2138,6 +2154,8 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
   /* Note that gdbarch_get_syscall_number may access registers, hence
      fill a regcache.  */
   registers_changed ();
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			lp->step, TARGET_SIGNAL_0);
   return 1;
@@ -2325,6 +2343,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 		    fprintf_unfiltered (gdb_stdlog,
 					"LHEW: resuming new LWP %ld\n",
 					GET_LWP (new_lp->ptid));
+		  if (linux_nat_prepare_to_resume != NULL)
+		    linux_nat_prepare_to_resume (new_lp);
 		  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
 					0, TARGET_SIGNAL_0);
 		  new_lp->stopped = 0;
@@ -2334,6 +2354,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	  if (debug_linux_nat)
 	    fprintf_unfiltered (gdb_stdlog,
 				"LHEW: resuming parent LWP %d\n", pid);
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				0, TARGET_SIGNAL_0);
 
@@ -2597,6 +2619,14 @@ stop_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+/* Request a stop on LWP.  */
+
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+  stop_callback (lwp, NULL);
+}
+
 /* Return non-zero if LWP PID has a pending SIGINT.  */
 
 static int
@@ -3333,6 +3363,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
 
 	  registers_changed ();
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
 	  if (debug_linux_nat)
@@ -3364,6 +3396,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
       lp->ignore_sigint = 0;
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3538,6 +3572,8 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3787,6 +3823,8 @@ retry:
 	     newly attached threads may cause an unwanted delay in
 	     getting them running.  */
 	  registers_changed ();
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				lp->step, signo);
 	  if (debug_linux_nat)
@@ -3943,6 +3981,8 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
 			    lp->step);
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       lp->stopped = 0;
@@ -5840,7 +5880,8 @@ linux_nat_add_target (struct target_ops *t)
 
 /* Register a method to call whenever a new thread is attached.  */
 void
-linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+linux_nat_set_new_thread (struct target_ops *t,
+			  void (*new_thread) (struct lwp_info *))
 {
   /* Save the pointer.  We only support a single registered instance
      of the GNU/Linux native target, so we do not need to map this to
@@ -5861,6 +5902,16 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
   linux_nat_siginfo_fixup = siginfo_fixup;
 }
 
+/* Register a method to call prior to resuming a thread.  */
+
+void
+linux_nat_set_prepare_to_resume (struct target_ops *t,
+				 void (*prepare_to_resume) (struct lwp_info *))
+{
+  /* Save the pointer.  */
+  linux_nat_prepare_to_resume = prepare_to_resume;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 1fa94ce..33727d6 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -22,6 +22,8 @@
 
 #include <signal.h>
 
+struct arch_lwp_info;
+
 /* Ways to "resume" a thread.  */
 
 enum resume_kind
@@ -109,6 +111,9 @@ struct lwp_info
   /* The processor core this LWP was last seen on.  */
   int core;
 
+  /* Arch-specific additions.  */
+  struct arch_lwp_info *arch_private;
+
   /* Next LWP in list.  */
   struct lwp_info *next;
 };
@@ -146,6 +151,8 @@ extern void linux_enable_event_reporting (ptid_t ptid);
 
 extern int lin_lwp_attach_lwp (ptid_t ptid);
 
+extern void linux_stop_lwp (struct lwp_info *lwp);
+
 /* Iterator function for lin-lwp's lwp list.  */
 struct lwp_info *iterate_over_lwps (ptid_t filter,
 				    int (*callback) (struct lwp_info *,
@@ -166,7 +173,7 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int));
 void linux_nat_add_target (struct target_ops *);
 
 /* Register a method to call whenever a new thread is attached.  */
-void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t));
+void linux_nat_set_new_thread (struct target_ops *, void (*) (struct lwp_info *));
 
 /* Register a method that converts a siginfo object between the layout
    that ptrace returns, and the layout in the architecture of the
@@ -176,6 +183,11 @@ void linux_nat_set_siginfo_fixup (struct target_ops *,
 					   gdb_byte *,
 					   int));
 
+/* Register a method to call prior to resuming a thread.  */
+
+void linux_nat_set_prepare_to_resume (struct target_ops *,
+				      void (*) (struct lwp_info *));
+
 /* Update linux-nat internal state when changing from one fork
    to another.  */
 void linux_nat_switch_fork (ptid_t new_ptid);
diff --git a/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp b/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
new file mode 100644
index 0000000..b8aa903
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
@@ -0,0 +1,77 @@
+#   Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if [target_info exists gdb,no_hardware_watchpoints] {
+    return -1
+}
+
+if { ![support_displaced_stepping] } { 
+    unsupported "displaced stepping"
+    return -1
+}
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+proc mi_nonstop_resume { command test } {
+    if { [mi_send_resuming_command $command $test] != 0 } {
+	# If a resume fails, assume non-stop is broken or unsupported
+	# for this target.  We have logged a FAIL or UNSUPPORTED; skip
+	# the remaining tests to limit timeouts.
+	return -code continue
+    }
+}
+
+#
+# Start here
+#
+set testfile "watch-nonstop"
+set srcfile "$testfile.c"
+set binfile "$objdir/$subdir/mi-$testfile"
+
+if {[gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable {debug}] != "" } {
+    return -1
+}
+
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load $binfile
+
+mi_gdb_test "-gdb-set non-stop 1" ".*"
+mi_gdb_test "-gdb-set target-async 1" ".*"
+mi_detect_async
+
+if { [mi_run_to_main] < 0 } {
+    continue
+}
+
+# Set a watchpoint.
+mi_gdb_test "111-break-watch global" \
+    "111\\^done,wpt=\{number=\"2\",exp=\"global\"\}" \
+    "break-watch operation"
+
+# Set the target running.
+mi_nonstop_resume "exec-continue" "resume 1"
+
+# Now try deleting the watchpoint.  This would fail with "Couldn't
+# write debug register: No such process."  on GNU/Linux, because we'd
+# try to poke at the debug registers of a running thread.
+mi_gdb_test "777-break-delete 2" \
+    "777\\^done" \
+    "delete watchpoint"
diff --git a/gdb/testsuite/gdb.mi/watch-nonstop.c b/gdb/testsuite/gdb.mi/watch-nonstop.c
new file mode 100644
index 0000000..7222cb6
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/watch-nonstop.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int global;
+
+int main ()
+{
+  sleep (60);
+  return 0;
+}
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 20e3c67..97ed237 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2494,8 +2494,9 @@ init_windows_ops (void)
 
   i386_dr_low.set_control = cygwin_set_dr7;
   i386_dr_low.set_addr = cygwin_set_dr;
-  i386_dr_low.reset_addr = NULL;
+  i386_dr_low.get_addr = cygwin_get_dr;
   i386_dr_low.get_status = cygwin_get_dr6;
+  i386_dr_low.get_control = cygwin_get_dr7;
 
   /* i386_dr_low.debug_register_length field is set by
      calling i386_set_debug_register_length function
@@ -2627,6 +2628,14 @@ cygwin_set_dr7 (unsigned long val)
   debug_registers_used = 1;
 }
 
+/* Get the value of debug register I from the inferior.  */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+  return dr[i];
+}
+
 /* Get the value of the DR6 debug status register from the inferior.
    Here we just return the value stored in dr[6]
    by the last call to thread_rec for current_event.dwThreadId id.  */
@@ -2636,6 +2645,16 @@ cygwin_get_dr6 (void)
   return (unsigned long) dr[6];
 }
 
+/* Get the value of the DR7 debug status register from the inferior.
+   Here we just return the value stored in dr[7] by the last call to
+   thread_rec for current_event.dwThreadId id.  */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+  return (unsigned long) dr[7];
+}
+
 /* Determine if the thread referenced by "ptid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the thread has died.  Otherwise it is assumed to be alive.  */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: Fix PR remote/13492
  2011-12-13 16:21                 ` Fix PR remote/13492 (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
@ 2011-12-13 17:23                   ` Jan Kratochvil
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-13 17:23 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tue, 13 Dec 2011 17:12:30 +0100, Pedro Alves wrote:
> > (I do not agree for example with the lwp->stopped_by_watchpoint part as
> > multiple watchpoints may get hit on one stop which isn't handled well but that
> > is out of the scope of this discussion.)
> 
> I'm not 100% certain that is possible, but in any case, I think that
> even if we handled that, we wouldn't ever get as far as
> prepare_to_resume before handling all the multiple watchpoints.

True.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-12 20:30             ` Pedro Alves
@ 2011-12-13 17:24               ` Jan Kratochvil
  2011-12-13 18:49                 ` Pedro Alves
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-13 17:24 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Tristan Gingold, gdb-patches

On Mon, 12 Dec 2011 21:13:51 +0100, Pedro Alves wrote:
> Maybe we should still have something like
> 
> if { istarget [ia64*-*-*] || .... } {
>   set_board_info gdb,no_hardware_watchpoints 1
> }
> 
> somewhere gdbserver specific.

The correct would be if gdbserver sends hardware watchpoints support in the
qSupported reply and GDB can print the response in some way.

In reality proposing to add to
	http://sourceware.org/gdb/wiki/TestingGDB#Native_Board_File
your proposed:
	# Some FSF gdbserver targets can't do hardware watchpoints.
	if [istarget "ia64*-*-*"] {
	  set_board_info gdb,no_hardware_watchpoints 1
	}


> Some ports, like ia64 gdbserver
> don't support watchpoints.  I think you can test a native
> gdbserver with this board on ia64-linux, but this isn't really
> native board specific --- a cross test should find watchpoints
> support disabled too.  Maybe in gdbserver-support.exp?  WDYT?

I do not find gdbserver-support.exp appropriate as the problem of missing ia64
watchpoints in FSF gdbserver does not apply to other implementations of
gdbserver while gdbserver-support.exp still gets used for non-FSF gdbservers.

Unless there is qSupported I find the board file appropriate, as it describes
the specific gdb<->gdbserver setup.

But I am far from experienced with advanced gdbserver stuff.


> > +load_lib gdbserver-support.exp
> > +
> > +if {[skip_hw_watchpoint_access_tests]
> > +    || (![istarget "i?86-*-linux*"] && ![istarget "x86_64-*-linux*"])
> > +    || ([is_remote target] && [skip_gdbserver_tests])} {
> > +    return 0
> > +}
> 
> > +
> > +if [is_remote target] {
> > +    gdbserver_start_extended
> > +}
> 
> Hmm, I'm not sure if this is really a good idea to spread
> gdbserver_start_extended around like this.  I think it would be
> better to skip the test if testing against plain "target remote".
> I mean, you may be remote testing against qemu, for example.  Having
> the test spawn GDBserver and actually run would be misleading.  Once
> we have a board that tests the whole testsuite with extended-remote
> working, then we'll clearly want the present board to skip tests
> it doesn't support.  (the gdb.server/ tests being the exception.)
> WDYT?

I have described this in:
	http://sourceware.org/ml/gdb-patches/2011-12/msg00088.html

Personally I would prefer always to follow the rules from there:
   * Some testcases skip themselves if their mode/board is not satisfied.
     --- if [is_remote target] then { return 0 }
 * If a testcase is compatible with any mode/board it uses the mode/board
   specified by user for the testsuite.

Therefore gdb.server/ would get whole skipped during the normal run.
Currently I run the testsuite already in multiple modes and some testcases run
in duplicate configurations that way, costing needless time+power=money.


As a less ambitious change if you do not like gdbserver_start_extended in this
testcase we can change it.  But gdb.server/ext-*.exp do exactly the same so
they have to be changed all together. we can introduce new:
	set_board_info gdb,extended_protocol_supported 1



Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-13 17:24               ` Jan Kratochvil
@ 2011-12-13 18:49                 ` Pedro Alves
  2011-12-13 19:25                   ` Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-13 18:49 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Tuesday 13 December 2011 17:23:18, Jan Kratochvil wrote:
> On Mon, 12 Dec 2011 21:13:51 +0100, Pedro Alves wrote:
> > Maybe we should still have something like
> > 
> > if { istarget [ia64*-*-*] || .... } {
> >   set_board_info gdb,no_hardware_watchpoints 1
> > }
> > 
> > somewhere gdbserver specific.
> 
> The correct would be if gdbserver sends hardware watchpoints support in the
> qSupported reply and GDB can print the response in some way.

We've been avoiding that, as it turns into a rathole fast.
It's not really binary: you have multiple types of watchpoints,
and targets that can do arbitrarily wide watched areas, others
can only watch some ranges, etc.  It related to the desire to
even get rid of watchpoint resource accounting.

> 
> In reality proposing to add to
> 	http://sourceware.org/gdb/wiki/TestingGDB#Native_Board_File
> your proposed:
> 	# Some FSF gdbserver targets can't do hardware watchpoints.
> 	if [istarget "ia64*-*-*"] {
> 	  set_board_info gdb,no_hardware_watchpoints 1
> 	}

That'd obviously work, but that's not what I was proposing,
as I don't think this file is the ideal place.  I mean, if you
do a cross test run from x86-linux x ia64-linux gdbserver, you
won't use that board file.

Anyway, I was just pointing out the existence of other
platforms; this is hardly something to worry much about.

> > Some ports, like ia64 gdbserver
> > don't support watchpoints.  I think you can test a native
> > gdbserver with this board on ia64-linux, but this isn't really
> > native board specific --- a cross test should find watchpoints
> > support disabled too.  Maybe in gdbserver-support.exp?  WDYT?
> 
> I do not find gdbserver-support.exp appropriate as the problem of missing ia64
> watchpoints in FSF gdbserver does not apply to other implementations of
> gdbserver while gdbserver-support.exp still gets used for non-FSF gdbservers.

It does?  I wasn't aware of that.  The file is very GDBserver (our server)
specific.  It expects the command line to be compatible at least.  Do you
know of any such non-FSF project?

(I wish other projects wouldn't call their servers gdbservers)

> Unless there is qSupported I find the board file appropriate, as it describes
> the specific gdb<->gdbserver setup.
> 
> But I am far from experienced with advanced gdbserver stuff.
> 
> 
> > > +load_lib gdbserver-support.exp
> > > +
> > > +if {[skip_hw_watchpoint_access_tests]
> > > +    || (![istarget "i?86-*-linux*"] && ![istarget "x86_64-*-linux*"])
> > > +    || ([is_remote target] && [skip_gdbserver_tests])} {
> > > +    return 0
> > > +}
> > 
> > > +
> > > +if [is_remote target] {
> > > +    gdbserver_start_extended
> > > +}
> > 
> > Hmm, I'm not sure if this is really a good idea to spread
> > gdbserver_start_extended around like this.  I think it would be
> > better to skip the test if testing against plain "target remote".
> > I mean, you may be remote testing against qemu, for example.  Having
> > the test spawn GDBserver and actually run would be misleading.  Once
> > we have a board that tests the whole testsuite with extended-remote
> > working, then we'll clearly want the present board to skip tests
> > it doesn't support.  (the gdb.server/ tests being the exception.)
> > WDYT?
> 
> I have described this in:
> 	http://sourceware.org/ml/gdb-patches/2011-12/msg00088.html
> 
> Personally I would prefer always to follow the rules from there:
>    * Some testcases skip themselves if their mode/board is not satisfied.
>      --- if [is_remote target] then { return 0 }
>  * If a testcase is compatible with any mode/board it uses the mode/board
>    specified by user for the testsuite.
> 
> Therefore gdb.server/ would get whole skipped during the normal run.

The whole point of gdb.server/ is to exercise GDBserver (our server,
not someone else's) specific functionality, and make sure it isn't a
brick (a bit like gdb.gdb/).  E.g., server-mon.exp will almost certainly
fail on other servers.  Another special issue with these tests
is e.g., things like

  gdb_test_no_output "set remote exec-file $target_exec" "set remote exec-file"

hardcoded on the tests.  A board file that always spawned
gdbserver in extended-remote will certainly do "set remote exec-file "
somewhere within gdb_load, behind the test file's back.

That's why these gdb.server/ tests are special.

> Currently I run the testsuite already in multiple modes and some testcases run
> in duplicate configurations that way, costing needless time+power=money.

I'd be fine to restrict them to native runs (that's how Dan originally
designed them), and get back to this once we have better support for
testing everything in extended-remote mode.

> As a less ambitious change if you do not like gdbserver_start_extended in this
> testcase we can change it.

That'd be my preference.

> But gdb.server/ext-*.exp do exactly the same so they have to be
> changed all together. 

I disagree, they don't have to.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-13 16:33                 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
@ 2011-12-13 18:57                   ` Jan Kratochvil
  2011-12-14 17:35                     ` Pedro Alves
  2011-12-13 22:27                   ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil
  1 sibling, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-13 18:57 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tue, 13 Dec 2011 17:26:03 +0100, Pedro Alves wrote:
> Anything else I should address?  

I am fine with this patch, thanks.


> Since we just branched, I'm a bit less worried about
> breaking things on other platforms.  :-)
+
>  /* Register a method to call whenever a new thread is attached.  */
>  void
> -linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
> +linux_nat_set_new_thread (struct target_ops *t,
> +			  void (*new_thread) (struct lwp_info *))

In such case you should change also all the callers on exotic arches:

./arm-linux-nat.c:1274:  linux_nat_set_new_thread (t, arm_linux_new_thread);
./ia64-linux-nat.c:861:  linux_nat_set_new_thread (t, ia64_linux_new_thread);
./mips-linux-nat.c:1088:  linux_nat_set_new_thread (t, mips_linux_new_thread);
./ppc-linux-nat.c:2530:  linux_nat_set_new_thread (t, ppc_linux_new_thread);
./s390-nat.c:698:  linux_nat_set_new_thread (t, s390_fix_watch_points);


> +     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

IMO s/re-resume/their resume/ but I do not master the language.



Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-13 18:49                 ` Pedro Alves
@ 2011-12-13 19:25                   ` Jan Kratochvil
  2011-12-16 16:16                     ` Pedro Alves
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-13 19:25 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tue, 13 Dec 2011 19:01:20 +0100, Pedro Alves wrote:
> > Currently I run the testsuite already in multiple modes and some testcases run
> > in duplicate configurations that way, costing needless time+power=money.
> 
> I'd be fine to restrict them to native runs (that's how Dan originally
> designed them),

If I change something in gdbserver I run just the testsuite in gdbserver mode.
If there is such restriction I would miss such change.

Moreover it seems overcomplicated to me to combine one mode into other modes.
I run FSF GDB HEAD now in 5 modes (default dwarf4-nogdbtypes dwarf4-gdbtypes
gdbindex gdbserver); in fact 15 modes (x86_64/x86_64-m32/i686), I will run it
in more modes soon.  Finding fast what has regressed from which set of tests
has failed is already tricky as the testsuite already runs some tests in
different modes than expected.

According to my various "Regression" mails to gdb-patches you can see it is
already not enough to regression test GDB in a single mode only.  So if one
has to run multiple modes they could be run really purely in their mode.

The same applies to PIE mode, if one debugs PIE code one runs the whole GDB
testsuite in PIE mode (there are still some bugs/incompletenesses in PIE...).


> and get back to this once we have better support for
> testing everything in extended-remote mode.

We will still need to test GDB in legacy mode for compatibility reasons with
non-FSF gdbservers and existing user setups of gdbserver.  I do not see what
will change with adding the new extended-remote mode to the existing set of
modes required to be run.


> > As a less ambitious change if you do not like gdbserver_start_extended in this
> > testcase we can change it.
> 
> That'd be my preference.

AFAIK there currently does not exist any extended-mode board file so there
does not make sense to check in a testcase requiring it.


> > But gdb.server/ext-*.exp do exactly the same so they have to be
> > changed all together. 
> 
> I disagree, they don't have to.

With http://sourceware.org/gdb/wiki/TestingGDB#Native_Board_File they both run
the server in extended mode.

There is a difference in default mode gdb.server/ext-*.exp also run it in
extended mode while this testcases runs in linux-nat mode in such case.

Our opinion probably differs in that I find running GDB testing only in the
default mode as insufficient.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-13 16:33                 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
  2011-12-13 18:57                   ` Jan Kratochvil
@ 2011-12-13 22:27                   ` Jan Kratochvil
  1 sibling, 0 replies; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-13 22:27 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Tue, 13 Dec 2011 17:26:03 +0100, Pedro Alves wrote:
> +amd64_linux_prepare_to_resume (struct lwp_info *lwp)
>  {
> -  struct lwp_info *lp;
> +  int clear_status = 0;
>  
> -  ALL_LWPS (lp)
> +  if (lwp->arch_private->debug_registers_changed)
>      {
> -      unsigned long value;
> -      
> -      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
> -      value &= ~mask;
> -      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
> +      struct i386_debug_reg_state *state = i386_debug_reg_state ();
> +      int i;
> +
> +      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
> +	if (state->dr_ref_count[i] > 0)
> +	  {
> +	    amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);

FYI this way it will leave non-zero DR_FIRSTADDR...DR_LASTADDR after detaching
from the inferior.  This is not a bug, just that it may look as a sort of
regression.  I do not think a fix - clearing them - is required.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-13 18:57                   ` Jan Kratochvil
@ 2011-12-14 17:35                     ` Pedro Alves
  2011-12-14 17:42                       ` Pedro Alves
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-14 17:35 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Tuesday 13 December 2011 18:49:23, Jan Kratochvil wrote:
> On Tue, 13 Dec 2011 17:26:03 +0100, Pedro Alves wrote:
> > Anything else I should address?  
> 
> I am fine with this patch, thanks.

That's great.

> > Since we just branched, I'm a bit less worried about
> > breaking things on other platforms.  :-)
> +
> >  /* Register a method to call whenever a new thread is attached.  */
> >  void
> > -linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
> > +linux_nat_set_new_thread (struct target_ops *t,
> > +			  void (*new_thread) (struct lwp_info *))
> 
> In such case you should change also all the callers on exotic arches:
> 
> ./arm-linux-nat.c:1274:  linux_nat_set_new_thread (t, arm_linux_new_thread);
> ./ia64-linux-nat.c:861:  linux_nat_set_new_thread (t, ia64_linux_new_thread);
> ./mips-linux-nat.c:1088:  linux_nat_set_new_thread (t, mips_linux_new_thread);
> ./ppc-linux-nat.c:2530:  linux_nat_set_new_thread (t, ppc_linux_new_thread);
> ./s390-nat.c:698:  linux_nat_set_new_thread (t, s390_fix_watch_points);
> 

Indeed!  Completely forgot.  Done now.

> > +     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
> 
> IMO s/re-resume/their resume/ but I do not master the language.

Thanks, but it sounds more natural to me how it is.  I really want to
convey the idea of resuming again, and, there's already "they" and
"their" spelled out enforcing the subject.

> On Tue, 13 Dec 2011 17:26:03 +0100, Pedro Alves wrote:
> > +amd64_linux_prepare_to_resume (struct lwp_info *lwp)
> >  {
> > -  struct lwp_info *lp;
> > +  int clear_status = 0;
> >  
> > -  ALL_LWPS (lp)
> > +  if (lwp->arch_private->debug_registers_changed)
> >      {
> > -      unsigned long value;
> > -      
> > -      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
> > -      value &= ~mask;
> > -      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
> > +      struct i386_debug_reg_state *state = i386_debug_reg_state ();
> > +      int i;
> > +
> > +      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
> > +	if (state->dr_ref_count[i] > 0)
> > +	  {
> > +	    amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
> 
> FYI this way it will leave non-zero DR_FIRSTADDR...DR_LASTADDR after detaching
> from the inferior.  This is not a bug, just that it may look as a sort of
> regression.  I do not think a fix - clearing them - is required.

Agreed.  But there's actually a related bug here, that I had thought
of fixing, then forgot.  GDBserver has this bug too; I'll fix it in a bit.
We need to call prepare_to_resume just before detaching, to clear
the previously active debug registers in DR_CONTROL, otherwise, the
inferior dies with SIGTRAP just after detaching.

That is:

(gdb) watch j
or
(gdb) hbreak foo
(gdb) si
*watchpoints inserted*
(gdb) delete
*deletes the watchpoints from global mirror, but doesn't update the threads' copies.*
(gdb) detach
*inferior trips on old watchpoints -> SIGTRAP death *


Retested on x86_64-linux and applied.


gdb/
2011-12-14  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* linux-nat.c (linux_nat_new_thread): Change parameter to an lwp
	pointer.
	(linux_nat_prepare_to_resume): New global.
	(lwp_free): New.
	(purge_lwp_list): Use it.
	(add_lwp): Call linux_nat_new_thread even on the first LWP.
	Adjust to interface change.
	(delete_lwp): Call lwp_free instead of xfree.
	(detach_callback, linux_nat_detach, resume_lwp, linux_nat_resume)
	(linux_handle_syscall_trap, linux_handle_extended_wait)
	(linux_nat_filter_event, resume_stopped_resumed_lwps): Call
	linux_nat_prepare_to_resume before resuming.
	(linux_stop_lwp): New.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.
	* linux-nat.h (struct arch_lwp_info): Forward declare.
	(struct lwp_info) <arch_private>: New field.
	(linux_stop_lwp): Declare.
	(linux_nat_set_new_thread): Adjust.
	(linux_nat_set_prepare_to_resume): New.

	* i386-nat.c (DR_NADDR, DR_STATUS, DR_CONTROL)
	(struct i386_debug_reg_state): Move to i386-nat.h.
	(dr_mirror): Comment.
	(i386_debug_reg_state): New.
	(i386_update_inferior_debug_regs): Simplify.
	(i386_stopped_data_address): Use the debug register state from the
	inferior, not from the local cache.
	* i386-nat.h (struct i386_dr_low_type): Delete reset_addr and
	unset_status fields.  New get_addr and get_control fields.
	(DR_FIRSTADDR, DR_LASTADDR, DR_CONTROL): Moved from i386-nat.c.
	(DR_NADDR, DR_STATUS): New.
	(struct i386_debug_reg_state): Moved from i386-nat.c.

	* amd64-linux-nat.c (struct arch_lwp_info): New.
	(amd64_linux_dr): Delete global.
	(amd64_linux_dr_get_addr): New.
	(amd64_linux_dr_get_control): New.
	(amd64_linux_dr_unset_status): Delete.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_dr_reset_addr): Delete.
	(update_debug_registers_callback): New.
	(amd64_linux_dr_set_control): Reimplement.
	(amd64_linux_dr_set_addr): Reimplement.
	(amd64_linux_prepare_to_resume): New.
	(amd64_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_amd64_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	amd64_linux_dr_get_control as i386_dr_low.get_control.  Install
	amd64_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	amd64_linux_prepare_to_resume.
	* i386-linux-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(struct arch_lwp_info): New.
	(i386_linux_dr): Delete global.
	(i386_linux_dr_set_control): Reimplement.
	(i386_linux_dr_get_addr): New.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_dr_get_control): New.
	(update_debug_registers_callback): New.
	(i386_linux_dr_unset_status): Delete.
	(i386_linux_dr_set_addr): Reimplement.
	(i386_linux_prepare_to_resume): New.
	(i386_linux_new_thread): Change parameter to an lwp pointer.
	Reimplement.
	(_initialize_i386_linux_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386_linux_dr_get_control as i386_dr_low.get_control.  Install
	i386_linux_dr_get_addr as i386_dr_low.get_addr.  Install
	i386_linux_prepare_to_resume.

	* arm-linux-nat.c (arm_linux_new_thread): Change parameter to an
	lwp pointer.  Adjust.
	* ia64-linux-nat.c (ia64_linux_new_thread): Likewise.
	* mips-linux-nat.c (mips_linux_new_thread): Likewise.
	* ppc-linux-nat.c (ppc_linux_new_thread): Likewise.
	* s390-nat.c (s390_fix_watch_points): Likewise.

	* i386-darwin-nat.c (DR_FIRSTADDR, DR_LASTADDR, DR_STATUS)
	(DR_CONTROL): Delete.
	(i386_darwin_dr_reset_addr): Delete.
	(i386_darwin_dr_get_addr): New.
	(i386_darwin_dr_get_control): New.
	* go32-nat.c
	(go32_get_dr7, go32_get_dr): New.
	(init_go32_ops): No longer install i386_dr_low.reset_addr.
	Install go32_get_dr7 as i386_dr_low.get_control.  Install
	go32_get_dr as i386_dr_low.get_addr.
	* i386bsd-nat.c (i386bsd_dr_get): New.
	(i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_status): Use i386bsd_dr_get.
	(i386bsd_dr_get_control): New.
	* i386bsd-nat.h (i386bsd_dr_reset_addr): Delete.
	(i386bsd_dr_get_addr): New.
	(i386bsd_dr_get_control): New.
	* i386fbsd-nat.c (_initialize_i386fbsd_nat): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	i386bsd_dr_get_control as i386_dr_low.get_control.  Install
	i386bsd_dr_get_addr as i386_dr_low.get_addr.
	* windows-nat.c (init_windows_ops): No longer install
	i386_dr_low.reset_addr and i386_dr_low.unset_status.  Install
	cygwin_get_dr7 as i386_dr_low.get_control.  Install cygwin_get_dr
	as i386_dr_low.get_addr.
	(cygwin_get_dr): New.
	(cygwin_get_dr7): New.

gdb/testsuite/
2011-12-14  Pedro Alves  <pedro@codesourcery.com>

	PR threads/10729

	* gdb.mi/watch-nonstop.c: New file.
 	* gdb.mi/mi-watch-nonstop.exp: New file.
---
 gdb/amd64-linux-nat.c                     |  130 ++++++++++++++++++--------
 gdb/arm-linux-nat.c                       |    4 -
 gdb/go32-nat.c                            |   26 +++++
 gdb/i386-darwin-nat.c                     |   31 ++----
 gdb/i386-linux-nat.c                      |  143 ++++++++++++++++++-----------
 gdb/i386-nat.c                            |  111 ++++++++++++-----------
 gdb/i386-nat.h                            |   42 +++++++--
 gdb/i386bsd-nat.c                         |   32 ++++--
 gdb/i386bsd-nat.h                         |    4 +
 gdb/i386fbsd-nat.c                        |    3 -
 gdb/ia64-linux-nat.c                      |    6 +
 gdb/linux-nat.c                           |   67 ++++++++++++--
 gdb/linux-nat.h                           |   14 +++
 gdb/mips-linux-nat.c                      |    4 -
 gdb/ppc-linux-nat.c                       |    4 -
 gdb/s390-nat.c                            |    6 +
 gdb/testsuite/gdb.mi/mi-watch-nonstop.exp |   77 ++++++++++++++++
 gdb/testsuite/gdb.mi/watch-nonstop.c      |   24 +++++
 gdb/windows-nat.c                         |   21 ++++
 19 files changed, 537 insertions(+), 212 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
 create mode 100644 gdb/testsuite/gdb.mi/watch-nonstop.c

diff --git a/gdb/amd64-linux-nat.c b/gdb/amd64-linux-nat.c
index c673965..288160b 100644
--- a/gdb/amd64-linux-nat.c
+++ b/gdb/amd64-linux-nat.c
@@ -64,6 +64,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 
@@ -265,8 +273,6 @@ amd64_linux_store_inferior_registers (struct target_ops *ops,
 \f
 /* Support for debug registers.  */
 
-static unsigned long amd64_linux_dr[DR_CONTROL + 1];
-
 static unsigned long
 amd64_linux_dr_get (ptid_t ptid, int regnum)
 {
@@ -304,75 +310,116 @@ amd64_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-amd64_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+amd64_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  amd64_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return amd64_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+amd64_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return amd64_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+
+static unsigned long
+amd64_linux_dr_get_status (void)
+{
+  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+}
+
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
+
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
+{
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
 
-  amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    amd64_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+  return 0;
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Set DR_CONTROL to CONTROL in all LWPs of the current inferior.  */
 
 static void
-amd64_linux_dr_reset_addr (int regnum)
+amd64_linux_dr_set_control (unsigned long control)
 {
-  amd64_linux_dr_set_addr (regnum, 0);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
-static unsigned long
-amd64_linux_dr_get_status (void)
+static void
+amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  return amd64_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
 
 static void
-amd64_linux_dr_unset_status (unsigned long mask)
+amd64_linux_prepare_to_resume (struct lwp_info *lwp)
 {
-  struct lwp_info *lp;
+  int clear_status = 0;
 
-  ALL_LWPS (lp)
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
-      
-      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+      int i;
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	if (state->dr_ref_count[i] > 0)
+	  {
+	    amd64_linux_dr_set (lwp->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_stopped_data_address can get
+	       confused.  */
+	    clear_status = 1;
+	  }
+
+      amd64_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
-}
 
+  if (clear_status || lwp->stopped_by_watchpoint)
+    amd64_linux_dr_set (lwp->ptid, DR_STATUS, 0);
+}
 
 static void
-amd64_linux_new_thread (ptid_t ptid)
+amd64_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    amd64_linux_dr_set (ptid, i, amd64_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -785,9 +832,9 @@ _initialize_amd64_linux_nat (void)
 
   i386_dr_low.set_control = amd64_linux_dr_set_control;
   i386_dr_low.set_addr = amd64_linux_dr_set_addr;
-  i386_dr_low.reset_addr = amd64_linux_dr_reset_addr;
+  i386_dr_low.get_addr = amd64_linux_dr_get_addr;
   i386_dr_low.get_status = amd64_linux_dr_get_status;
-  i386_dr_low.unset_status = amd64_linux_dr_unset_status;
+  i386_dr_low.get_control = amd64_linux_dr_get_control;
   i386_set_debug_register_length (8);
 
   /* Override the GNU/Linux inferior startup hook.  */
@@ -804,4 +851,5 @@ _initialize_amd64_linux_nat (void)
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, amd64_linux_new_thread);
   linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup);
+  linux_nat_set_prepare_to_resume (t, amd64_linux_prepare_to_resume);
 }
diff --git a/gdb/arm-linux-nat.c b/gdb/arm-linux-nat.c
index 6424dc3..c614f96 100644
--- a/gdb/arm-linux-nat.c
+++ b/gdb/arm-linux-nat.c
@@ -1178,9 +1178,9 @@ arm_linux_watchpoint_addr_within_range (struct target_ops *target,
 /* Handle thread creation.  We need to copy the breakpoints and watchpoints
    in the parent thread to the child thread.  */
 static void
-arm_linux_new_thread (ptid_t ptid)
+arm_linux_new_thread (struct lwp_info *lp)
 {
-  int tid = TIDGET (ptid);
+  int tid = TIDGET (lp->ptid);
   const struct arm_linux_hwbp_cap *info = arm_linux_get_hwbp_cap ();
 
   if (info != NULL)
diff --git a/gdb/go32-nat.c b/gdb/go32-nat.c
index 8295adf..79618ec 100644
--- a/gdb/go32-nat.c
+++ b/gdb/go32-nat.c
@@ -801,6 +801,29 @@ go32_get_dr6 (void)
   return STATUS;
 }
 
+/* Get the value of the DR7 debug status register from the inferior.
+   Here we just return the value stored in D_REGS, as we've got it
+   from the last go32_wait call.  */
+
+static unsigned long
+go32_get_dr7 (void)
+{
+  return CONTROL;
+}
+
+/* Get the value of the DR debug register I from the inferior.  Here
+   we just return the value stored in D_REGS, as we've got it from the
+   last go32_wait call.  */
+
+static CORE_ADDR
+go32_get_dr (int i)
+{
+  if (i < 0 || i > 3)
+    internal_error (__FILE__, __LINE__,
+		    _("Invalid register %d in go32_get_dr.\n"), i);
+  return D_REGS[i];
+}
+
 /* Put the device open on handle FD into either raw or cooked
    mode, return 1 if it was in raw mode, zero otherwise.  */
 
@@ -984,8 +1007,9 @@ init_go32_ops (void)
 
   i386_dr_low.set_control = go32_set_dr7;
   i386_dr_low.set_addr = go32_set_dr;
-  i386_dr_low.reset_addr = NULL;
   i386_dr_low.get_status = go32_get_dr6;
+  i386_dr_low.get_control = go32_get_dr7;
+  i386_dr_low.get_addr = go32_get_dr;
   i386_set_debug_register_length (4);
 
   go32_ops.to_magic = OPS_MAGIC;
diff --git a/gdb/i386-darwin-nat.c b/gdb/i386-darwin-nat.c
index 61e2e15..23f6a6d 100644
--- a/gdb/i386-darwin-nat.c
+++ b/gdb/i386-darwin-nat.c
@@ -263,23 +263,6 @@ i386_darwin_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers, boosted mostly from i386-linux-nat.c.  */
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
-
 static void
 i386_darwin_dr_set (int regnum, uint32_t value)
 {
@@ -410,12 +393,10 @@ i386_darwin_dr_set_addr (int regnum, CORE_ADDR addr)
   i386_darwin_dr_set (DR_FIRSTADDR + regnum, addr);
 }
 
-void
-i386_darwin_dr_reset_addr (int regnum)
+CORE_ADDR
+i386_darwin_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
-
-  i386_darwin_dr_set (DR_FIRSTADDR + regnum, 0L);
+  return i386_darwin_dr_get (regnum);
 }
 
 unsigned long
@@ -424,6 +405,12 @@ i386_darwin_dr_get_status (void)
   return i386_darwin_dr_get (DR_STATUS);
 }
 
+unsigned long
+i386_darwin_dr_get_control (void)
+{
+  return i386_darwin_dr_get (DR_CONTROL);
+}
+
 void
 darwin_check_osabi (darwin_inferior *inf, thread_t thread)
 {
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 7eb49ae..190979b 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -47,22 +47,6 @@
 #include <sys/debugreg.h>
 #endif
 
-#ifndef DR_FIRSTADDR
-#define DR_FIRSTADDR 0
-#endif
-
-#ifndef DR_LASTADDR
-#define DR_LASTADDR 3
-#endif
-
-#ifndef DR_STATUS
-#define DR_STATUS 6
-#endif
-
-#ifndef DR_CONTROL
-#define DR_CONTROL 7
-#endif
-
 /* Prototypes for supply_gregset etc.  */
 #include "gregset.h"
 
@@ -83,6 +67,14 @@
 #define PTRACE_SETREGSET	0x4205
 #endif
 
+/* Per-thread arch-specific data we want to keep.  */
+
+struct arch_lwp_info
+{
+  /* Non-zero if our copy differs from what's recorded in the thread.  */
+  int debug_registers_changed;
+};
+
 /* Does the current host support PTRACE_GETREGSET?  */
 static int have_ptrace_getregset = -1;
 \f
@@ -651,8 +643,6 @@ i386_linux_store_inferior_registers (struct target_ops *ops,
 
 /* Support for debug registers.  */
 
-static unsigned long i386_linux_dr[DR_CONTROL + 1];
-
 /* Get debug register REGNUM value from only the one LWP of PTID.  */
 
 static unsigned long
@@ -692,74 +682,116 @@ i386_linux_dr_set (ptid_t ptid, int regnum, unsigned long value)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Set DR_CONTROL to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's debug register REGNUM.  */
 
-static void
-i386_linux_dr_set_control (unsigned long control)
+static CORE_ADDR
+i386_linux_dr_get_addr (int regnum)
 {
-  struct lwp_info *lp;
+  /* DR6 and DR7 are retrieved with some other way.  */
+  gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
 
-  i386_linux_dr[DR_CONTROL] = control;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_CONTROL, control);
+  return i386_linux_dr_get (inferior_ptid, regnum);
 }
 
-/* Set address REGNUM (zero based) to ADDR in all LWPs of LWP_LIST.  */
+/* Return the inferior's DR7 debug control register.  */
 
-static void
-i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
+static unsigned long
+i386_linux_dr_get_control (void)
 {
-  struct lwp_info *lp;
+  return i386_linux_dr_get (inferior_ptid, DR_CONTROL);
+}
 
-  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
 
-  i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
-  ALL_LWPS (lp)
-    i386_linux_dr_set (lp->ptid, DR_FIRSTADDR + regnum, addr);
+static unsigned long
+i386_linux_dr_get_status (void)
+{
+  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
 }
 
-/* Set address REGNUM (zero based) to zero in all LWPs of LWP_LIST.  */
+/* Callback for iterate_over_lwps.  Update the debug registers of
+   LWP.  */
+
+static int
+update_debug_registers_callback (struct lwp_info *lwp, void *arg)
+{
+  /* The actual update is done later just before resuming the lwp, we
+     just mark that the registers need updating.  */
+  lwp->arch_private->debug_registers_changed = 1;
+
+  /* If the lwp isn't stopped, force it to momentarily pause, so we
+     can update its debug registers.  */
+  if (!lwp->stopped)
+    linux_stop_lwp (lwp);
+
+  return 0;
+}
+
+/* Set DR_CONTROL to ADDR in all LWPs of the current inferior.  */
 
 static void
-i386_linux_dr_reset_addr (int regnum)
+i386_linux_dr_set_control (unsigned long control)
 {
-  i386_linux_dr_set_addr (regnum, 0);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Get DR_STATUS from only the one LWP of INFERIOR_PTID.  */
+/* Set address REGNUM (zero based) to ADDR in all LWPs of the current
+   inferior.  */
 
-static unsigned long
-i386_linux_dr_get_status (void)
+static void
+i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
 {
-  return i386_linux_dr_get (inferior_ptid, DR_STATUS);
+  ptid_t pid_ptid = pid_to_ptid (ptid_get_pid (inferior_ptid));
+
+  gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
+
+  iterate_over_lwps (pid_ptid, update_debug_registers_callback, NULL);
 }
 
-/* Unset MASK bits in DR_STATUS in all LWPs of LWP_LIST.  */
+/* Called when resuming a thread.
+   If the debug regs have changed, update the thread's copies.  */
 
 static void
-i386_linux_dr_unset_status (unsigned long mask)
+i386_linux_prepare_to_resume (struct lwp_info *lwp)
 {
-  struct lwp_info *lp;
+  int clear_status = 0;
 
-  ALL_LWPS (lp)
+  if (lwp->arch_private->debug_registers_changed)
     {
-      unsigned long value;
+      struct i386_debug_reg_state *state = i386_debug_reg_state ();
+      int i;
+
+      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
+	if (state->dr_ref_count[i] > 0)
+	  {
+	    i386_linux_dr_set (lwp->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_stopped_data_address can get
+	       confused.  */
+	    clear_status = 1;
+	  }
 
-      value = i386_linux_dr_get (lp->ptid, DR_STATUS);
-      value &= ~mask;
-      i386_linux_dr_set (lp->ptid, DR_STATUS, value);
+      i386_linux_dr_set (lwp->ptid, DR_CONTROL, state->dr_control_mirror);
+
+      lwp->arch_private->debug_registers_changed = 0;
     }
+
+  if (clear_status || lwp->stopped_by_watchpoint)
+    i386_linux_dr_set (lwp->ptid, DR_STATUS, 0);
 }
 
 static void
-i386_linux_new_thread (ptid_t ptid)
+i386_linux_new_thread (struct lwp_info *lp)
 {
-  int i;
+  struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
 
-  for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
-    i386_linux_dr_set (ptid, i, i386_linux_dr[i]);
+  info->debug_registers_changed = 1;
 
-  i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
+  lp->arch_private = info;
 }
 \f
 
@@ -978,9 +1010,9 @@ _initialize_i386_linux_nat (void)
 
   i386_dr_low.set_control = i386_linux_dr_set_control;
   i386_dr_low.set_addr = i386_linux_dr_set_addr;
-  i386_dr_low.reset_addr = i386_linux_dr_reset_addr;
+  i386_dr_low.get_addr = i386_linux_dr_get_addr;
   i386_dr_low.get_status = i386_linux_dr_get_status;
-  i386_dr_low.unset_status = i386_linux_dr_unset_status;
+  i386_dr_low.get_control = i386_linux_dr_get_control;
   i386_set_debug_register_length (4);
 
   /* Override the default ptrace resume method.  */
@@ -999,4 +1031,5 @@ _initialize_i386_linux_nat (void)
   /* Register the target.  */
   linux_nat_add_target (t);
   linux_nat_set_new_thread (t, i386_linux_new_thread);
+  linux_nat_set_prepare_to_resume (t, i386_linux_prepare_to_resume);
 }
diff --git a/gdb/i386-nat.c b/gdb/i386-nat.c
index 568b79b..cd479b3 100644
--- a/gdb/i386-nat.c
+++ b/gdb/i386-nat.c
@@ -43,11 +43,6 @@ struct i386_dr_low_type i386_dr_low;
 /* Support for 8-byte wide hw watchpoints.  */
 #define TARGET_HAS_DR_LEN_8 (i386_dr_low.debug_register_length == 8)
 
-/* Debug registers' indices.  */
-#define DR_NADDR	4	/* The number of debug address registers.  */
-#define DR_STATUS	6	/* Index of debug status register (DR6).  */
-#define DR_CONTROL	7	/* Index of debug control register (DR7).  */
-
 /* DR7 Debug Control register fields.  */
 
 /* How many bits to skip in DR7 to get to R/W and LEN fields.  */
@@ -158,23 +153,6 @@ struct i386_dr_low_type i386_dr_low;
 /* A macro to loop over all debug registers.  */
 #define ALL_DEBUG_REGISTERS(i)	for (i = 0; i < DR_NADDR; i++)
 
-
-/* Global state needed to track h/w watchpoints.  */
-
-struct i386_debug_reg_state
-{
-  /* Mirror the inferior's DRi registers.  We keep the status and
-     control registers separated because they don't hold addresses.
-     Note that since we can change these mirrors while threads are
-     running, we never trust them to explain a cause of a trap.
-     For that, we need to peek directly in the inferior registers.  */
-  CORE_ADDR dr_mirror[DR_NADDR];
-  unsigned dr_status_mirror, dr_control_mirror;
-
-  /* Reference counts for each debug register.  */
-  int dr_ref_count[DR_NADDR];
-};
-
 /* Clear the reference counts and forget everything we knew about the
    debug registers.  */
 
@@ -192,8 +170,16 @@ i386_init_dregs (struct i386_debug_reg_state *state)
   state->dr_status_mirror  = 0;
 }
 
+/* The local mirror of the inferior's debug registers.  Currently this
+   is a global, but it should really be per-inferior.  */
 static struct i386_debug_reg_state dr_mirror;
 
+struct i386_debug_reg_state *
+i386_debug_reg_state (void)
+{
+  return &dr_mirror;
+}
+
 /* Whether or not to print the mirrored debug registers.  */
 static int maint_show_dr;
 
@@ -513,22 +499,7 @@ i386_update_inferior_debug_regs (struct i386_debug_reg_state *new_state)
   ALL_DEBUG_REGISTERS (i)
     {
       if (I386_DR_VACANT (new_state, i) != I386_DR_VACANT (&dr_mirror, i))
-	{
-	  if (!I386_DR_VACANT (new_state, i))
-	    {
-	      i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
-
-	      /* Only a sanity check for leftover bits (set possibly only
-		 by inferior).  */
-	      if (i386_dr_low.unset_status)
-		i386_dr_low.unset_status (I386_DR_WATCH_MASK (i));
-	    }
-	  else
-	    {
-	      if (i386_dr_low.reset_addr)
-		i386_dr_low.reset_addr (i);
-	    }
-	}
+	i386_dr_low.set_addr (i, new_state->dr_mirror[i]);
       else
 	gdb_assert (new_state->dr_mirror[i] == dr_mirror.dr_mirror[i]);
     }
@@ -634,28 +605,62 @@ i386_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
   CORE_ADDR addr = 0;
   int i;
   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;
+  /* 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;
-  struct i386_debug_reg_state *state = &dr_mirror;
 
-  dr_mirror.dr_status_mirror = i386_dr_low.get_status ();
-  status = dr_mirror.dr_status_mirror;
-  control = dr_mirror.dr_control_mirror;
+  /* In non-stop/async, threads can be running while we change the
+     global dr_mirror (and friends).  Say, we set a watchpoint, and
+     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 ();
 
   ALL_DEBUG_REGISTERS(i)
     {
-      if (I386_DR_WATCH_HIT (status, i)
-	  /* 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.  */
-	  && I386_DR_GET_RW_LEN (control, i) != 0
-	  /* This third condition makes sure DRi is not vacant, this
-	     avoids false positives in windows-nat.c.  */
-	  && !I386_DR_VACANT (state, i))
+      if (!I386_DR_WATCH_HIT (status, i))
+	continue;
+
+      if (!control_p)
+	{
+	  control = i386_dr_low.get_control ();
+	  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 = state->dr_mirror[i];
+	  addr = i386_dr_low.get_addr (i);
 	  rc = 1;
 	  if (maint_show_dr)
 	    i386_show_dr (&dr_mirror, "watchpoint_hit", addr, -1, hw_write);
diff --git a/gdb/i386-nat.h b/gdb/i386-nat.h
index 819c6b8..1a75daa 100644
--- a/gdb/i386-nat.h
+++ b/gdb/i386-nat.h
@@ -53,31 +53,54 @@ extern void i386_use_watchpoints (struct target_ops *);
       set_addr                 -- put an address into one debug
 				  register for all LWPs
 
-      reset_addr               -- reset the address stored in
-				  one debug register for all LWPs
+      get_addr                 -- return the address in a given debug
+				  register of the current LWP
 
       get_status               -- return the value of the debug
 				  status (DR6) register for current LWP
 
-      unset_status             -- unset the specified bits of the debug
-				  status (DR6) register for all LWPs
+      get_control               -- return the value of the debug
+				  control (DR7) register for current LWP
 
    Additionally, the native file should set the debug_register_length
    field to 4 or 8 depending on the number of bytes used for
    deubg registers.  */
 
-struct i386_dr_low_type 
+struct i386_dr_low_type
   {
     void (*set_control) (unsigned long);
     void (*set_addr) (int, CORE_ADDR);
-    void (*reset_addr) (int);
+    CORE_ADDR (*get_addr) (int);
     unsigned long (*get_status) (void);
-    void (*unset_status) (unsigned long);
+    unsigned long (*get_control) (void);
     int debug_register_length;
   };
 
 extern struct i386_dr_low_type i386_dr_low;
 
+/* Debug registers' indices.  */
+#define DR_FIRSTADDR 0
+#define DR_LASTADDR  3
+#define DR_NADDR     4	/* The number of debug address registers.  */
+#define DR_STATUS    6	/* Index of debug status register (DR6).  */
+#define DR_CONTROL   7	/* Index of debug control register (DR7).  */
+
+/* Global state needed to track h/w watchpoints.  */
+
+struct i386_debug_reg_state
+{
+  /* Mirror the inferior's DRi registers.  We keep the status and
+     control registers separated because they don't hold addresses.
+     Note that since we can change these mirrors while threads are
+     running, we never trust them to explain a cause of a trap.
+     For that, we need to peek directly in the inferior registers.  */
+  CORE_ADDR dr_mirror[DR_NADDR];
+  unsigned dr_status_mirror, dr_control_mirror;
+
+  /* Reference counts for each debug register.  */
+  int dr_ref_count[DR_NADDR];
+};
+
 /* Use this function to set i386_dr_low debug_register_length field
    rather than setting it directly to check that the length is only
    set once.  It also enables the 'maint set/show show-debug-regs' 
@@ -89,4 +112,9 @@ extern void i386_set_debug_register_length (int len);
 
 extern void i386_cleanup_dregs (void);
 
+/* Return a pointer to the the local mirror of the inferior's debug
+   registers.  */
+
+extern struct i386_debug_reg_state *i386_debug_reg_state (void);
+
 #endif /* I386_NAT_H */
diff --git a/gdb/i386bsd-nat.c b/gdb/i386bsd-nat.c
index fcd772f..22c79e2 100644
--- a/gdb/i386bsd-nat.c
+++ b/gdb/i386bsd-nat.c
@@ -264,6 +264,18 @@ i386bsd_target (void)
 #define DBREG_DRX(d, x) ((&d->dr0)[x])
 #endif
 
+static unsigned long
+i386bsd_dr_get (ptid_t ptid, int regnum)
+{
+  struct dbreg dbregs;
+
+  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
+    perror_with_name (_("Couldn't read debug registers"));
+
+  return DBREG_DRX ((&dbregs), regnum);
+}
+
 static void
 i386bsd_dr_set (int regnum, unsigned int value)
 {
@@ -299,24 +311,22 @@ i386bsd_dr_set_addr (int regnum, CORE_ADDR addr)
   i386bsd_dr_set (regnum, addr);
 }
 
-void
-i386bsd_dr_reset_addr (int regnum)
+CORE_ADDR
+i386bsd_dr_get_addr (int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum <= 4);
-
-  i386bsd_dr_set (regnum, 0);
+  return i386bsd_dr_get (inferior_ptid, regnum);
 }
 
 unsigned long
 i386bsd_dr_get_status (void)
 {
-  struct dbreg dbregs;
-
-  if (ptrace (PT_GETDBREGS, PIDGET (inferior_ptid),
-	      (PTRACE_TYPE_ARG3) &dbregs, 0) == -1)
-    perror_with_name (_("Couldn't read debug registers"));
+  return i386bsd_dr_get (inferior_ptid, 6);
+}
 
-  return DBREG_DRX ((&dbregs), 6);
+unsigned long
+i386bsd_dr_get_control (void)
+{
+  return i386bsd_dr_get (inferior_ptid, 7);
 }
 
 #endif /* PT_GETDBREGS */
diff --git a/gdb/i386bsd-nat.h b/gdb/i386bsd-nat.h
index 1c27ed5..df0b0f3 100644
--- a/gdb/i386bsd-nat.h
+++ b/gdb/i386bsd-nat.h
@@ -32,8 +32,10 @@ extern void i386bsd_dr_set_control (unsigned long control);
 
 extern void i386bsd_dr_set_addr (int regnum, CORE_ADDR addr);
 
-extern void i386bsd_dr_reset_addr (int regnum);
+extern CORE_ADDR i386bsd_dr_get_addr (int regnum);
 
 extern unsigned long i386bsd_dr_get_status (void);
 
+extern unsigned long i386bsd_dr_get_control (void);
+
 #endif /* i386bsd-nat.h */
diff --git a/gdb/i386fbsd-nat.c b/gdb/i386fbsd-nat.c
index ecc797e..52ae031 100644
--- a/gdb/i386fbsd-nat.c
+++ b/gdb/i386fbsd-nat.c
@@ -134,8 +134,9 @@ _initialize_i386fbsd_nat (void)
 
   i386_dr_low.set_control = i386bsd_dr_set_control;
   i386_dr_low.set_addr = i386bsd_dr_set_addr;
-  i386_dr_low.reset_addr = i386bsd_dr_reset_addr;
+  i386_dr_low.get_addr = i386bsd_dr_get_addr;
   i386_dr_low.get_status = i386bsd_dr_get_status;
+  i386_dr_low.get_control = i386bsd_dr_get_control;
   i386_set_debug_register_length (4);
 
 #endif /* HAVE_PT_GETDBREGS */
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index 65e077b..abe532a 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -618,7 +618,7 @@ ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
 }
 
 static void
-ia64_linux_new_thread (ptid_t ptid)
+ia64_linux_new_thread (struct lwp_info *lp)
 {
   int i, any;
 
@@ -627,11 +627,11 @@ ia64_linux_new_thread (ptid_t ptid)
     {
       if (debug_registers[i] != 0)
 	any = 1;
-      store_debug_register (ptid, i, debug_registers[i]);
+      store_debug_register (lp->ptid, i, debug_registers[i]);
     }
 
   if (any)
-    enable_watchpoints_in_psr (ptid);
+    enable_watchpoints_in_psr (lp->ptid);
 }
 
 static int
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 19b4b57..1cbfc44 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -175,7 +175,10 @@ static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The method to call, if any, when a new thread is attached.  */
-static void (*linux_nat_new_thread) (ptid_t);
+static void (*linux_nat_new_thread) (struct lwp_info *);
+
+/* Hook to call prior to resuming a thread.  */
+static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
 
 /* The method to call, if any, when the siginfo object needs to be
    converted between the layout returned by ptrace, and the layout in
@@ -1073,6 +1076,15 @@ status_to_str (int status)
   return buf;
 }
 
+/* Destroy and free LP.  */
+
+static void
+lwp_free (struct lwp_info *lp)
+{
+  xfree (lp->arch_private);
+  xfree (lp);
+}
+
 /* Remove all LWPs belong to PID from the lwp list.  */
 
 static void
@@ -1093,7 +1105,7 @@ purge_lwp_list (int pid)
 	  else
 	    lpprev->next = lp->next;
 
-	  xfree (lp);
+	  lwp_free (lp);
 	}
       else
 	lpprev = lp;
@@ -1139,8 +1151,8 @@ add_lwp (ptid_t ptid)
   lp->next = lwp_list;
   lwp_list = lp;
 
-  if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
-    linux_nat_new_thread (ptid);
+  if (linux_nat_new_thread != NULL)
+    linux_nat_new_thread (lp);
 
   return lp;
 }
@@ -1166,7 +1178,7 @@ delete_lwp (ptid_t ptid)
   else
     lwp_list = lp->next;
 
-  xfree (lp);
+  lwp_free (lp);
 }
 
 /* Return a pointer to the structure describing the LWP corresponding
@@ -1724,6 +1736,8 @@ detach_callback (struct lwp_info *lp, void *data)
       /* Pass on any pending signal for this LWP.  */
       get_pending_status (lp, &status);
 
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       errno = 0;
       if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
 		  WSTOPSIG (status)) < 0)
@@ -1784,6 +1798,8 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
 			    target_pid_to_str (main_lwp->ptid));
     }
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (main_lwp);
   delete_lwp (main_lwp->ptid);
 
   if (forks_exist_p ())
@@ -1825,6 +1841,8 @@ resume_lwp (struct lwp_info *lp, int step)
 				"RC:  PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
 				target_pid_to_str (lp->ptid));
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops,
 				pid_to_ptid (GET_LWP (lp->ptid)),
 				step, TARGET_SIGNAL_0);
@@ -1969,6 +1987,8 @@ linux_nat_resume (struct target_ops *ops,
   /* Convert to something the lower layer understands.  */
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
   lp->stopped_by_watchpoint = 0;
@@ -2138,6 +2158,8 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
   /* Note that gdbarch_get_syscall_number may access registers, hence
      fill a regcache.  */
   registers_changed ();
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			lp->step, TARGET_SIGNAL_0);
   return 1;
@@ -2325,6 +2347,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 		    fprintf_unfiltered (gdb_stdlog,
 					"LHEW: resuming new LWP %ld\n",
 					GET_LWP (new_lp->ptid));
+		  if (linux_nat_prepare_to_resume != NULL)
+		    linux_nat_prepare_to_resume (new_lp);
 		  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
 					0, TARGET_SIGNAL_0);
 		  new_lp->stopped = 0;
@@ -2334,6 +2358,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 	  if (debug_linux_nat)
 	    fprintf_unfiltered (gdb_stdlog,
 				"LHEW: resuming parent LWP %d\n", pid);
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				0, TARGET_SIGNAL_0);
 
@@ -2597,6 +2623,14 @@ stop_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+/* Request a stop on LWP.  */
+
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+  stop_callback (lwp, NULL);
+}
+
 /* Return non-zero if LWP PID has a pending SIGINT.  */
 
 static int
@@ -3333,6 +3367,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
 
 	  registers_changed ();
 
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
 	  if (debug_linux_nat)
@@ -3364,6 +3400,8 @@ linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
       lp->ignore_sigint = 0;
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3538,6 +3576,8 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3787,6 +3827,8 @@ retry:
 	     newly attached threads may cause an unwanted delay in
 	     getting them running.  */
 	  registers_changed ();
+	  if (linux_nat_prepare_to_resume != NULL)
+	    linux_nat_prepare_to_resume (lp);
 	  linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 				lp->step, signo);
 	  if (debug_linux_nat)
@@ -3943,6 +3985,8 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
 			    lp->step);
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+	linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
 			    lp->step, TARGET_SIGNAL_0);
       lp->stopped = 0;
@@ -5840,7 +5884,8 @@ linux_nat_add_target (struct target_ops *t)
 
 /* Register a method to call whenever a new thread is attached.  */
 void
-linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+linux_nat_set_new_thread (struct target_ops *t,
+			  void (*new_thread) (struct lwp_info *))
 {
   /* Save the pointer.  We only support a single registered instance
      of the GNU/Linux native target, so we do not need to map this to
@@ -5861,6 +5906,16 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
   linux_nat_siginfo_fixup = siginfo_fixup;
 }
 
+/* Register a method to call prior to resuming a thread.  */
+
+void
+linux_nat_set_prepare_to_resume (struct target_ops *t,
+				 void (*prepare_to_resume) (struct lwp_info *))
+{
+  /* Save the pointer.  */
+  linux_nat_prepare_to_resume = prepare_to_resume;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index 1fa94ce..33727d6 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -22,6 +22,8 @@
 
 #include <signal.h>
 
+struct arch_lwp_info;
+
 /* Ways to "resume" a thread.  */
 
 enum resume_kind
@@ -109,6 +111,9 @@ struct lwp_info
   /* The processor core this LWP was last seen on.  */
   int core;
 
+  /* Arch-specific additions.  */
+  struct arch_lwp_info *arch_private;
+
   /* Next LWP in list.  */
   struct lwp_info *next;
 };
@@ -146,6 +151,8 @@ extern void linux_enable_event_reporting (ptid_t ptid);
 
 extern int lin_lwp_attach_lwp (ptid_t ptid);
 
+extern void linux_stop_lwp (struct lwp_info *lwp);
+
 /* Iterator function for lin-lwp's lwp list.  */
 struct lwp_info *iterate_over_lwps (ptid_t filter,
 				    int (*callback) (struct lwp_info *,
@@ -166,7 +173,7 @@ linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int));
 void linux_nat_add_target (struct target_ops *);
 
 /* Register a method to call whenever a new thread is attached.  */
-void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t));
+void linux_nat_set_new_thread (struct target_ops *, void (*) (struct lwp_info *));
 
 /* Register a method that converts a siginfo object between the layout
    that ptrace returns, and the layout in the architecture of the
@@ -176,6 +183,11 @@ void linux_nat_set_siginfo_fixup (struct target_ops *,
 					   gdb_byte *,
 					   int));
 
+/* Register a method to call prior to resuming a thread.  */
+
+void linux_nat_set_prepare_to_resume (struct target_ops *,
+				      void (*) (struct lwp_info *));
+
 /* Update linux-nat internal state when changing from one fork
    to another.  */
 void linux_nat_switch_fork (ptid_t new_ptid);
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index 2602e2d..2cfd156 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -886,14 +886,14 @@ write_watchpoint_regs (void)
  register values for the new thread.  */
 
 static void
-mips_linux_new_thread (ptid_t ptid)
+mips_linux_new_thread (struct lwp_info *lp)
 {
   int tid;
 
   if (!mips_linux_read_watch_registers (0))
     return;
 
-  tid = ptid_get_lwp (ptid);
+  tid = ptid_get_lwp (lp->ptid);
   if (ptrace (PTRACE_SET_WATCH_REGS, tid, &watch_mirror) == -1)
     perror_with_name (_("Couldn't write debug register"));
 }
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 94cfbf8..dc7f152 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -2151,9 +2151,9 @@ ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw,
 }
 
 static void
-ppc_linux_new_thread (ptid_t ptid)
+ppc_linux_new_thread (struct lwp_info *lp)
 {
-  int tid = TIDGET (ptid);
+  int tid = TIDGET (lp->ptid);
 
   if (have_ptrace_booke_interface ())
     {
diff --git a/gdb/s390-nat.c b/gdb/s390-nat.c
index ae3c868..b1c3f11 100644
--- a/gdb/s390-nat.c
+++ b/gdb/s390-nat.c
@@ -472,7 +472,7 @@ s390_stopped_by_watchpoint (void)
 }
 
 static void
-s390_fix_watch_points (ptid_t ptid)
+s390_fix_watch_points (struct lwp_info *lp)
 {
   int tid;
 
@@ -482,9 +482,9 @@ s390_fix_watch_points (ptid_t ptid)
   CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
   struct watch_area *area;
 
-  tid = TIDGET (ptid);
+  tid = TIDGET (lp->ptid);
   if (tid == 0)
-    tid = PIDGET (ptid);
+    tid = PIDGET (lp->ptid);
 
   for (area = watch_base; area; area = area->next)
     {
diff --git a/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp b/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
new file mode 100644
index 0000000..b8aa903
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-watch-nonstop.exp
@@ -0,0 +1,77 @@
+#   Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+if [target_info exists gdb,no_hardware_watchpoints] {
+    return -1
+}
+
+if { ![support_displaced_stepping] } { 
+    unsupported "displaced stepping"
+    return -1
+}
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+proc mi_nonstop_resume { command test } {
+    if { [mi_send_resuming_command $command $test] != 0 } {
+	# If a resume fails, assume non-stop is broken or unsupported
+	# for this target.  We have logged a FAIL or UNSUPPORTED; skip
+	# the remaining tests to limit timeouts.
+	return -code continue
+    }
+}
+
+#
+# Start here
+#
+set testfile "watch-nonstop"
+set srcfile "$testfile.c"
+set binfile "$objdir/$subdir/mi-$testfile"
+
+if {[gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable {debug}] != "" } {
+    return -1
+}
+
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load $binfile
+
+mi_gdb_test "-gdb-set non-stop 1" ".*"
+mi_gdb_test "-gdb-set target-async 1" ".*"
+mi_detect_async
+
+if { [mi_run_to_main] < 0 } {
+    continue
+}
+
+# Set a watchpoint.
+mi_gdb_test "111-break-watch global" \
+    "111\\^done,wpt=\{number=\"2\",exp=\"global\"\}" \
+    "break-watch operation"
+
+# Set the target running.
+mi_nonstop_resume "exec-continue" "resume 1"
+
+# Now try deleting the watchpoint.  This would fail with "Couldn't
+# write debug register: No such process."  on GNU/Linux, because we'd
+# try to poke at the debug registers of a running thread.
+mi_gdb_test "777-break-delete 2" \
+    "777\\^done" \
+    "delete watchpoint"
diff --git a/gdb/testsuite/gdb.mi/watch-nonstop.c b/gdb/testsuite/gdb.mi/watch-nonstop.c
new file mode 100644
index 0000000..7222cb6
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/watch-nonstop.c
@@ -0,0 +1,24 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int global;
+
+int main ()
+{
+  sleep (60);
+  return 0;
+}
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index 20e3c67..97ed237 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -2494,8 +2494,9 @@ init_windows_ops (void)
 
   i386_dr_low.set_control = cygwin_set_dr7;
   i386_dr_low.set_addr = cygwin_set_dr;
-  i386_dr_low.reset_addr = NULL;
+  i386_dr_low.get_addr = cygwin_get_dr;
   i386_dr_low.get_status = cygwin_get_dr6;
+  i386_dr_low.get_control = cygwin_get_dr7;
 
   /* i386_dr_low.debug_register_length field is set by
      calling i386_set_debug_register_length function
@@ -2627,6 +2628,14 @@ cygwin_set_dr7 (unsigned long val)
   debug_registers_used = 1;
 }
 
+/* Get the value of debug register I from the inferior.  */
+
+static CORE_ADDR
+cygwin_get_dr (int i)
+{
+  return dr[i];
+}
+
 /* Get the value of the DR6 debug status register from the inferior.
    Here we just return the value stored in dr[6]
    by the last call to thread_rec for current_event.dwThreadId id.  */
@@ -2636,6 +2645,16 @@ cygwin_get_dr6 (void)
   return (unsigned long) dr[6];
 }
 
+/* Get the value of the DR7 debug status register from the inferior.
+   Here we just return the value stored in dr[7] by the last call to
+   thread_rec for current_event.dwThreadId id.  */
+
+static unsigned long
+cygwin_get_dr7 (void)
+{
+  return (unsigned long) dr[7];
+}
+
 /* Determine if the thread referenced by "ptid" is alive
    by "polling" it.  If WaitForSingleObject returns WAIT_OBJECT_0
    it means that the thread has died.  Otherwise it is assumed to be alive.  */

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-14 17:35                     ` Pedro Alves
@ 2011-12-14 17:42                       ` Pedro Alves
  2011-12-15  8:48                         ` Regression for T (Stopped) processes [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode] Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-14 17:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil

On Wednesday 14 December 2011 17:22:27, Pedro Alves wrote:
> > On Tue, 13 Dec 2011 17:26:03 +0100, Pedro Alves wrote:
> > > +amd64_linux_prepare_to_resume (struct lwp_info *lwp)
> > >  {
> > > -  struct lwp_info *lp;
> > > +  int clear_status = 0;
> > >  
> > > -  ALL_LWPS (lp)
> > > +  if (lwp->arch_private->debug_registers_changed)
> > >      {
> > > -      unsigned long value;
> > > -      
> > > -      value = amd64_linux_dr_get (lp->ptid, DR_STATUS);
> > > -      value &= ~mask;
> > > -      amd64_linux_dr_set (lp->ptid, DR_STATUS, value);
> > > +      struct i386_debug_reg_state *state = i386_debug_reg_state ();
> > > +      int i;
> > > +
> > > +      for (i = DR_FIRSTADDR; i <= DR_LASTADDR; i++)
> > > +   if (state->dr_ref_count[i] > 0)
> > > +     {
> > > +       amd64_linux_dr_set (lwp->ptid, i, state->dr_mirror[i]);
> > 
> > FYI this way it will leave non-zero DR_FIRSTADDR...DR_LASTADDR after detaching
> > from the inferior.  This is not a bug, just that it may look as a sort of
> > regression.  I do not think a fix - clearing them - is required.
> 
> Agreed.  But there's actually a related bug here, that I had thought
> of fixing, then forgot.  GDBserver has this bug too; I'll fix it in a bit.

Like below.  Now applied.

> We need to call prepare_to_resume just before detaching, to clear
> the previously active debug registers in DR_CONTROL, otherwise, the
> inferior dies with SIGTRAP just after detaching.
> 
> That is:
> 
> (gdb) watch j
> or
> (gdb) hbreak foo
> (gdb) si
> watchpoints inserted
> (gdb) delete
> *deletes the watchpoints from global mirror, but doesn't update the threads' copies.*
> (gdb) detach
> *inferior trips on old watchpoints -> SIGTRAP death *
> 

gdb/gdbserver/
2011-12-14  Pedro Alves  <pedro@codesourcery.com>

	* linux-low.c (linux_detach_one_lwp): Call
	the_low_target.prepare_to_resume before detaching.

---
 gdb/gdbserver/linux-low.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 8afbc8b..43d88fa 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -918,6 +918,8 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
 			   get_lwp_thread (lwp));
 
   /* Finally, let it resume.  */
+  if (the_low_target.prepare_to_resume != NULL)
+    the_low_target.prepare_to_resume (lwp);
   ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
 
   delete_lwp (lwp);

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Regression for T (Stopped) processes  [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode]
  2011-12-14 17:42                       ` Pedro Alves
@ 2011-12-15  8:48                         ` Jan Kratochvil
  2011-12-15 12:44                           ` Pedro Alves
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-15  8:48 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Wed, 14 Dec 2011 18:34:43 +0100, Pedro Alves wrote:
> --- a/gdb/gdbserver/linux-low.c
> +++ b/gdb/gdbserver/linux-low.c
> @@ -918,6 +918,8 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
>  			   get_lwp_thread (lwp));
>  
>    /* Finally, let it resume.  */
> +  if (the_low_target.prepare_to_resume != NULL)
> +    the_low_target.prepare_to_resume (lwp);
>    ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
>  
>    delete_lwp (lwp);

If you have T (Stopped) process on Linux kernel 3.1+, you do attach,
bt/gcore/etc., detach, the state of the process must not change.
But the process will now run for a bit.

This is a regression.  Some users really insist the T (Stopped) inferior state
absolutely does not change.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: Regression for T (Stopped) processes  [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode]
  2011-12-15  8:48                         ` Regression for T (Stopped) processes [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode] Jan Kratochvil
@ 2011-12-15 12:44                           ` Pedro Alves
  2011-12-15 15:33                             ` Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-15 12:44 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches

On Thursday 15 December 2011 06:20:13, Jan Kratochvil wrote:
> On Wed, 14 Dec 2011 18:34:43 +0100, Pedro Alves wrote:
> > --- a/gdb/gdbserver/linux-low.c
> > +++ b/gdb/gdbserver/linux-low.c
> > @@ -918,6 +918,8 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
> >  			   get_lwp_thread (lwp));
> >  
> >    /* Finally, let it resume.  */
> > +  if (the_low_target.prepare_to_resume != NULL)
> > +    the_low_target.prepare_to_resume (lwp);
> >    ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
> >  
> >    delete_lwp (lwp);
> 
> If you have T (Stopped) process on Linux kernel 3.1+, you do attach,
> bt/gcore/etc., detach, the state of the process must not change.
> But the process will now run for a bit.

I'm confused.  Why does it run for a bit now?  prepare_to_resume should
not, and AFAICS, does not, actually resume.

> 
> This is a regression.  Some users really insist the T (Stopped) inferior state
> absolutely does not change.
> 
> 
> Thanks,
> Jan
> 

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: Regression for T (Stopped) processes  [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode]
  2011-12-15 12:44                           ` Pedro Alves
@ 2011-12-15 15:33                             ` Jan Kratochvil
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Kratochvil @ 2011-12-15 15:33 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Thu, 15 Dec 2011 09:47:37 +0100, Pedro Alves wrote:
> I'm confused.  Why does it run for a bit now?  prepare_to_resume should
> not, and AFAICS, does not, actually resume.

I agree, my wrong expectation.


Sorry,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode
  2011-12-13 19:25                   ` Jan Kratochvil
@ 2011-12-16 16:16                     ` Pedro Alves
  2012-01-20 19:51                       ` testsuite: native/non-extended/extended modes [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode] Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2011-12-16 16:16 UTC (permalink / raw)
  To: gdb-patches; +Cc: Jan Kratochvil

Hi Jan,

sorry for the delay.

On Tuesday 13 December 2011 19:18:58, Jan Kratochvil wrote:
> On Tue, 13 Dec 2011 19:01:20 +0100, Pedro Alves wrote:
> > and get back to this once we have better support for
> > testing everything in extended-remote mode.
> 
> We will still need to test GDB in legacy mode for compatibility reasons with
> non-FSF gdbservers and existing user setups of gdbserver.  I do not see what
> will change with adding the new extended-remote mode to the existing set of
> modes required to be run.

Currently, because there's no extended-remote board, the only way to
be a bit certain that we aren't making extended-remote "attach"/"run"
support in gdbserver a brick is the gdb.server/ tests.  Let's take a
look at what we're talking about:

$ ls gdb.server/*.exp
gdb.server/ext-attach.exp
gdb.server/ext-run.exp
gdb.server/file-transfer.exp
gdb.server/server-mon.exp
gdb.server/server-run.exp

That's it.  Once we have a board that tests the whole testsuite in
extended-remote mote, the ext-*.exp tests become useless and
redundant, and so all uses of gdbserver_start_extended can be eliminated
-- we have plenty of regular tests that "run" and "attach".  Meanwhile,
we don't such a board, so we live with the exception that the
tests force gdbserver, and extended-remote.  This is what I mean
by revisiting later.  (I don't see a point in adding a board variable
for "supports extended-remote" at this point.)

The other tests don't directly relate to the gdbserver_start_extended
discussion, but let's have a look for completeness.  The file-transfer.exp
test could be adjusted to not require gdbserver, but instead detect the
remote or extended-remote target is being used, and skipped if
not.  E.g., "remote put" fails with "command can only be used with
remote target" if used on any other target.  With that adjustment,
the test could be moved elsewhere.

The gdb.server/server-mon.exp test exercise gdbserver (vs
any other 3rd-party server) specific bits.  We could perhaps
adjust it to try "monitor help" or "monitor version"
(the latter doesn't work today, but it'd be reasonable
to add), and skipping the test if something not gdbserver
comes out.  Such a change assumes PASS->UNSUPPORTED or
PASSes simply disappearing kind of regressions are
detected, but they should anyway.

The server-run.exp test is practically useless
everywhere.  It's a tiny bit useful
on [istarget *-*-linux*], and the bit it tests
can only work as expected on use_gdb_stub boards.  So we
could move it to say, gdb.base/, and adjust it to not
require gdbserver, and skip it if !use_gdb_stub.

> > > As a less ambitious change if you do not like gdbserver_start_extended in this
> > > testcase we can change it.
> > 
> > That'd be my preference.
> 
> AFAIK there currently does not exist any extended-mode board file so there
> does not make sense to check in a testcase requiring it.

The test works with the native target.  It would be skipped for use_gdb_stub
boards, like many tests are.  It looks worth it to check in to me.
What I disagree is spreading gdbserver_start_extended uses outside
of gdb.server/.

Jan, largely, we agree.  Really.

> > > But gdb.server/ext-*.exp do exactly the same so they have to be
> > > changed all together. 
> > 
> > I disagree, they don't have to.
> 
> With http://sourceware.org/gdb/wiki/TestingGDB#Native_Board_File they both run
> the server in extended mode.
> 
> There is a difference in default mode gdb.server/ext-*.exp also run it in
> extended mode while this testcases runs in linux-nat mode in such case.

I was disagreeing in your claim that they have to be changed
all together...  We can just simply put your test case in, without
the gdbserver_start_extended bit, skipped on use_gdb_stub, and leave
the gdb.server/ tests alone for a separate patch/change/discussion/whatever.
They _don't_ have to be changed all together, is what I'm saying.
Maybe I misunderstood you.

> Our opinion probably differs in that I find running GDB testing only in the
> default mode as insufficient.

Of course we agree here.  You were the one complaining that the tests
run in all modes...

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* testsuite: native/non-extended/extended modes  [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode]
  2011-12-16 16:16                     ` Pedro Alves
@ 2012-01-20 19:51                       ` Jan Kratochvil
  2012-01-20 19:53                         ` Pedro Alves
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Kratochvil @ 2012-01-20 19:51 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On Fri, 16 Dec 2011 16:16:56 +0100, Pedro Alves wrote:
> Currently, because there's no extended-remote board, the only way to
> be a bit certain that we aren't making extended-remote "attach"/"run"
> support in gdbserver a brick is the gdb.server/ tests.  Let's take a
> look at what we're talking about:
> 
> $ ls gdb.server/*.exp
> gdb.server/ext-attach.exp
> gdb.server/ext-run.exp
> gdb.server/file-transfer.exp
> gdb.server/server-mon.exp
> gdb.server/server-run.exp
> 
> That's it.  Once we have a board that tests the whole testsuite in
> extended-remote mote, the ext-*.exp tests become useless and
> redundant, and so all uses of gdbserver_start_extended can be eliminated
> -- we have plenty of regular tests that "run" and "attach".  Meanwhile,
> we don't such a board, so we live with the exception that the
> tests force gdbserver, and extended-remote.  This is what I mean
> by revisiting later.  (I don't see a point in adding a board variable
> for "supports extended-remote" at this point.)

As I have another testcase in archer-jankratochvil-watchpoint3
gdb.multi/watchpoint-multi.exp needing extended gdbserver and you are already
working on extended-remote board could you restate what is the recommended way
how to create a testcase which:
 * supports native mode
 * does not support non-extended-remote
 * supports extended-remote
?


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: testsuite: native/non-extended/extended modes  [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode]
  2012-01-20 19:51                       ` testsuite: native/non-extended/extended modes [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode] Jan Kratochvil
@ 2012-01-20 19:53                         ` Pedro Alves
  2012-01-20 19:57                           ` Jan Kratochvil
  0 siblings, 1 reply; 37+ messages in thread
From: Pedro Alves @ 2012-01-20 19:53 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Pedro Alves, gdb-patches

On 01/20/2012 07:45 PM, Jan Kratochvil wrote:

> As I have another testcase in archer-jankratochvil-watchpoint3
> gdb.multi/watchpoint-multi.exp needing extended gdbserver and you are already
> working on extended-remote board could you restate what is the recommended way
> how to create a testcase which:
>  * supports native mode
>  * does not support non-extended-remote
>  * supports extended-remote
> ?

Just skip it if use_gdb_stub is set (meaning, non-extended-remote).
extended-remote behaves like native for the most part, so it doesn't
set use_gdb_stub, and the test will run there as well.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 37+ messages in thread

* Re: testsuite: native/non-extended/extended modes  [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode]
  2012-01-20 19:53                         ` Pedro Alves
@ 2012-01-20 19:57                           ` Jan Kratochvil
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Kratochvil @ 2012-01-20 19:57 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Pedro Alves, gdb-patches

On Fri, 20 Jan 2012 20:51:05 +0100, Pedro Alves wrote:
> Just skip it if use_gdb_stub is set (meaning, non-extended-remote).
> extended-remote behaves like native for the most part, so it doesn't
> set use_gdb_stub, and the test will run there as well.

True, that's simple.


Thanks,
Jan

^ permalink raw reply	[flat|nested] 37+ messages in thread

end of thread, other threads:[~2012-01-20 19:54 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-05 16:46 [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
2011-12-05 17:06 ` Eli Zaretskii
2011-12-09 16:30   ` New tests to watch regions larger than a machine word (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
2011-12-09 19:11     ` Eli Zaretskii
2011-12-13 16:12       ` Pedro Alves
2011-12-05 21:24 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil
2011-12-09 16:45   ` Pedro Alves
2011-12-09 16:47     ` Tristan Gingold
2011-12-09 19:23     ` Eli Zaretskii
2011-12-13 16:26       ` Pedro Alves
2011-12-11 23:39     ` Jan Kratochvil
2011-12-12 11:53       ` Pedro Alves
2011-12-12 14:49         ` Jan Kratochvil
2011-12-12  0:14     ` Jan Kratochvil
2011-12-12 17:23       ` Pedro Alves
2011-12-12 18:38         ` Jan Kratochvil
2011-12-12 20:14           ` Jan Kratochvil
2011-12-12 20:30             ` Pedro Alves
2011-12-13 17:24               ` Jan Kratochvil
2011-12-13 18:49                 ` Pedro Alves
2011-12-13 19:25                   ` Jan Kratochvil
2011-12-16 16:16                     ` Pedro Alves
2012-01-20 19:51                       ` testsuite: native/non-extended/extended modes [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode] Jan Kratochvil
2012-01-20 19:53                         ` Pedro Alves
2012-01-20 19:57                           ` Jan Kratochvil
2011-12-12 20:34             ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
2011-12-12 21:39               ` Jan Kratochvil
2011-12-13 16:21                 ` Fix PR remote/13492 (Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode) Pedro Alves
2011-12-13 17:23                   ` Fix PR remote/13492 Jan Kratochvil
2011-12-13 16:33                 ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Pedro Alves
2011-12-13 18:57                   ` Jan Kratochvil
2011-12-14 17:35                     ` Pedro Alves
2011-12-14 17:42                       ` Pedro Alves
2011-12-15  8:48                         ` Regression for T (Stopped) processes [Re: [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode] Jan Kratochvil
2011-12-15 12:44                           ` Pedro Alves
2011-12-15 15:33                             ` Jan Kratochvil
2011-12-13 22:27                   ` [PATCH] PR threads/10729: x86 hw watchpoints and non-stop mode Jan Kratochvil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).