d945816
http://sourceware.org/ml/gdb-patches/2008-01/msg00042.html
9a1b988
[ Backported for GDB-6.6 (only removed the new file inclusion). ]
9a1b988
d945816
+
d945816
d50521f
2007-09-16  Daniel Jacobowitz  <dan@codesourcery.com>
d50521f
	    Jeff Johnston  <jjohnstn@redhat.com>
d50521f
d50521f
	* gdb.texinfo (Setting Watchpoints): Adjust warning text about
d50521f
	multi-threaded watchpoints.
d50521f
d50521f
2007-12-15  Jan Kratochvil  <jan.kratochvil@redhat.com>
d50521f
d50521f
	* gdb.texinfo (Setting Watchpoints): New paragraph on the software
d50521f
	watchpoints safety wrt `set scheduler-locking'.
d50521f
25ff8a1
2008-03-01  Jan Kratochvil  <jan.kratochvil@redhat.com>
25ff8a1
25ff8a1
	Port to GDB-6.8pre.
25ff8a1
e923707
2008-03-31  Jan Kratochvil  <jan.kratochvil@redhat.com>
e923707
e923707
	* gdb.threads/watchpoint-fork-forkoff.c (forkoff): New delay after the
e923707
	parent/child messages to fix a race.
e923707
2234aa8
2008-05-28  Jan Kratochvil  <jan.kratochvil@redhat.com>
2234aa8
2234aa8
	* s390-nat.c (s390_fix_watch_points): Fix its compilation failure
2234aa8
	- rename it to S390_FIX_WATCH_POINTS_LIST.
2234aa8
81783d0
Index: gdb-6.8.50.20090209/gdb/amd64-linux-nat.c
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/amd64-linux-nat.c	2009-02-09 16:02:27.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/amd64-linux-nat.c	2009-02-09 16:03:30.000000000 +0100
25ff8a1
@@ -408,25 +408,43 @@ amd64_linux_dr_set (ptid_t ptid, int reg
25ff8a1
 void
25ff8a1
 amd64_linux_dr_set_control (unsigned long control)
25ff8a1
 {
25ff8a1
-  struct lwp_info *lp;
25ff8a1
-  ptid_t ptid;
25ff8a1
-
25ff8a1
   amd64_linux_dr[DR_CONTROL] = control;
25ff8a1
-  ALL_LWPS (lp, ptid)
25ff8a1
-    amd64_linux_dr_set (ptid, DR_CONTROL, control);
25ff8a1
+
25ff8a1
+  /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process
25ff8a1
+     not listed for ALL_LWPS.  */
25ff8a1
+
25ff8a1
+  if (ptid_get_lwp (inferior_ptid) == 0)
25ff8a1
+    amd64_linux_dr_set (inferior_ptid, DR_CONTROL, control);
25ff8a1
+  else
25ff8a1
+    {
25ff8a1
+      struct lwp_info *lp;
25ff8a1
+      ptid_t ptid;
25ff8a1
+
25ff8a1
+      ALL_LWPS (lp, ptid)
25ff8a1
+	amd64_linux_dr_set (ptid, DR_CONTROL, control);
25ff8a1
+    }
d945816
 }
9a1b988
 
25ff8a1
 void
25ff8a1
 amd64_linux_dr_set_addr (int regnum, CORE_ADDR addr)
25ff8a1
 {
25ff8a1
-  struct lwp_info *lp;
25ff8a1
-  ptid_t ptid;
25ff8a1
-
25ff8a1
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
25ff8a1
 
25ff8a1
   amd64_linux_dr[DR_FIRSTADDR + regnum] = addr;
25ff8a1
-  ALL_LWPS (lp, ptid)
25ff8a1
-    amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
25ff8a1
+
25ff8a1
+  /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process
25ff8a1
+     not listed for ALL_LWPS.  */
25ff8a1
+
25ff8a1
+  if (ptid_get_lwp (inferior_ptid) == 0)
25ff8a1
+    amd64_linux_dr_set (inferior_ptid, DR_FIRSTADDR + regnum, addr);
25ff8a1
+  else
25ff8a1
+    {
25ff8a1
+      struct lwp_info *lp;
25ff8a1
+      ptid_t ptid;
25ff8a1
+
25ff8a1
+      ALL_LWPS (lp, ptid)
25ff8a1
+	amd64_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
25ff8a1
+    }
25ff8a1
 }
25ff8a1
 
25ff8a1
 void
25ff8a1
@@ -451,6 +469,41 @@ amd64_linux_new_thread (ptid_t ptid)
25ff8a1
 
25ff8a1
   amd64_linux_dr_set (ptid, DR_CONTROL, amd64_linux_dr[DR_CONTROL]);
25ff8a1
 }
25ff8a1
+
d945816
+/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child
d945816
+   process of traced FORK.  We must clear such watchpoints only once during
d945816
+   DETACH_BREAKPOINTS.  */
d945816
+
d945816
+static int amd64_linux_detach_breakpoints_pid;
d945816
+
25ff8a1
+/* Remove a watchpoint that watched the memory region which starts at
25ff8a1
+   address ADDR, whose length is LEN bytes, and for accesses of the
25ff8a1
+   type TYPE.  Return 0 on success, -1 on failure.  */
25ff8a1
+int
25ff8a1
+amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
25ff8a1
+{
d945816
+  if (ptid_get_pid (inferior_ptid) == amd64_linux_detach_breakpoints_pid)
d945816
+    return 0;
d945816
+  /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions.  */
d945816
+  amd64_linux_detach_breakpoints_pid = 0;
d945816
+
25ff8a1
+  return i386_remove_watchpoint (addr, len, type);
25ff8a1
+}
25ff8a1
+
d945816
+static void
d945816
+amd64_linux_detach_breakpoints (int detached_pid)
d945816
+{
d945816
+  struct cleanup *old_chain = save_inferior_ptid ();
d945816
+  int i;
d945816
+
d945816
+  amd64_linux_detach_breakpoints_pid = detached_pid;
d945816
+  /* Depend on `!is_lwp (inferior_ptid)' for the I386_* macros.  */
d945816
+  inferior_ptid = pid_to_ptid (detached_pid);
d945816
+
d945816
+  i386_detach_breakpoints (detached_pid);
d945816
+
d945816
+  do_cleanups (old_chain);
d945816
+}
25ff8a1
 
25ff8a1
 
25ff8a1
 /* This function is called by libthread_db as part of its handling of
81783d0
@@ -755,6 +808,42 @@ amd64_linux_siginfo_fixup (struct siginf
81783d0
     return 0;
d945816
 }
81783d0
 
d945816
+static int (*amd64_linux_super_follow_fork) (struct target_ops *ops,
d945816
+					     int follow_child);
d945816
+
d945816
+/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its
d945816
+   called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror.  */
d945816
+
d945816
+static int
d945816
+amd64_linux_follow_fork (struct target_ops *ops, int follow_child)
d945816
+{
d945816
+  ptid_t last_ptid;
d945816
+  struct target_waitstatus last_status;
d945816
+  int has_vforked;
d945816
+  int parent_pid, child_pid;
d945816
+
d945816
+  get_last_target_status (&last_ptid, &last_status);
d945816
+  has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
d945816
+  parent_pid = ptid_get_lwp (last_ptid);
d945816
+  if (parent_pid == 0)
d945816
+    parent_pid = ptid_get_pid (last_ptid);
407ebe9
+  child_pid = ptid_get_lwp (last_status.value.related_pid);
407ebe9
+  if (child_pid == 0)
407ebe9
+    child_pid = ptid_get_pid (last_status.value.related_pid);
d945816
+
d945816
+  if (! follow_child)
d945816
+    {
d945816
+      amd64_linux_detach_breakpoints (child_pid);
d945816
+    }
d945816
+  else
d945816
+    {
d945816
+      if (! has_vforked)
d945816
+	amd64_linux_detach_breakpoints (child_pid);
d945816
+    }
d945816
+
d945816
+  return (*amd64_linux_super_follow_fork) (ops, follow_child);
d945816
+}
d945816
+
d945816
 /* Provide a prototype to silence -Wmissing-prototypes.  */
81783d0
 void _initialize_amd64_linux_nat (void);
81783d0
 
81783d0
@@ -791,6 +880,9 @@ _initialize_amd64_linux_nat (void)
d945816
   linux_elfcore_write_prstatus = amd64_linux_elfcore_write_prstatus;
d945816
   linux_elfcore_write_prfpreg = amd64_linux_elfcore_write_prfpreg;
d945816
 
d945816
+  amd64_linux_super_follow_fork = t->to_follow_fork;
d945816
+  t->to_follow_fork = amd64_linux_follow_fork;
d945816
+
d945816
   /* Register the target.  */
d945816
   linux_nat_add_target (t);
25ff8a1
   linux_nat_set_new_thread (t, amd64_linux_new_thread);
81783d0
Index: gdb-6.8.50.20090209/gdb/config/i386/nm-i386.h
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/config/i386/nm-i386.h	2009-01-03 06:57:54.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/config/i386/nm-i386.h	2009-02-09 16:02:42.000000000 +0100
407ebe9
@@ -120,6 +120,8 @@ extern int i386_stopped_by_watchpoint (v
407ebe9
 
407ebe9
 #endif /* I386_WATCHPOINTS_IN_TARGET_VECTOR */
d945816
 
d945816
+extern void i386_detach_breakpoints (int detached_pid);
d945816
+
d945816
 #endif /* I386_USE_GENERIC_WATCHPOINTS */
d945816
 
d945816
 #endif /* NM_I386_H */
81783d0
Index: gdb-6.8.50.20090209/gdb/i386-linux-nat.c
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/i386-linux-nat.c	2009-01-03 06:57:51.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/i386-linux-nat.c	2009-02-09 16:02:42.000000000 +0100
407ebe9
@@ -634,21 +634,42 @@ i386_linux_dr_set_control (unsigned long
25ff8a1
   ptid_t ptid;
25ff8a1
 
25ff8a1
   i386_linux_dr[DR_CONTROL] = control;
25ff8a1
-  ALL_LWPS (lp, ptid)
25ff8a1
-    i386_linux_dr_set (ptid, DR_CONTROL, control);
25ff8a1
+
25ff8a1
+  /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process
25ff8a1
+     not listed for ALL_LWPS.  */
25ff8a1
+
25ff8a1
+  if (ptid_get_lwp (inferior_ptid) == 0)
25ff8a1
+    i386_linux_dr_set (inferior_ptid, DR_CONTROL, control);
25ff8a1
+  else
25ff8a1
+    {
25ff8a1
+      struct lwp_info *lp;
25ff8a1
+      ptid_t ptid;
25ff8a1
+
25ff8a1
+      ALL_LWPS (lp, ptid)
25ff8a1
+	i386_linux_dr_set (ptid, DR_CONTROL, control);
25ff8a1
+    }
d945816
 }
d945816
 
25ff8a1
 void
25ff8a1
 i386_linux_dr_set_addr (int regnum, CORE_ADDR addr)
25ff8a1
 {
25ff8a1
-  struct lwp_info *lp;
25ff8a1
-  ptid_t ptid;
25ff8a1
-
25ff8a1
   gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR);
25ff8a1
 
25ff8a1
   i386_linux_dr[DR_FIRSTADDR + regnum] = addr;
25ff8a1
-  ALL_LWPS (lp, ptid)
25ff8a1
-    i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
25ff8a1
+
25ff8a1
+  /* I386_DETACH_BREAKPOINTS may need to reset the registers on single process
25ff8a1
+     not listed for ALL_LWPS.  */
25ff8a1
+
25ff8a1
+  if (ptid_get_lwp (inferior_ptid) == 0)
25ff8a1
+    i386_linux_dr_set (inferior_ptid, DR_FIRSTADDR + regnum, addr);
25ff8a1
+  else
25ff8a1
+    {
25ff8a1
+      struct lwp_info *lp;
25ff8a1
+      ptid_t ptid;
25ff8a1
+
25ff8a1
+      ALL_LWPS (lp, ptid)
25ff8a1
+	i386_linux_dr_set (ptid, DR_FIRSTADDR + regnum, addr);
25ff8a1
+    }
25ff8a1
 }
25ff8a1
 
25ff8a1
 void
407ebe9
@@ -673,6 +694,41 @@ i386_linux_new_thread (ptid_t ptid)
25ff8a1
 
25ff8a1
   i386_linux_dr_set (ptid, DR_CONTROL, i386_linux_dr[DR_CONTROL]);
25ff8a1
 }
25ff8a1
+
d945816
+/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child
d945816
+   process of traced FORK.  We must clear such watchpoints only once during
d945816
+   DETACH_BREAKPOINTS.  */
d945816
+
d945816
+static int i386_linux_detach_breakpoints_pid;
d945816
+
25ff8a1
+/* Remove a watchpoint that watched the memory region which starts at
25ff8a1
+   address ADDR, whose length is LEN bytes, and for accesses of the
25ff8a1
+   type TYPE.  Return 0 on success, -1 on failure.  */
25ff8a1
+int
25ff8a1
+i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
25ff8a1
+{
d945816
+  if (ptid_get_pid (inferior_ptid) == i386_linux_detach_breakpoints_pid)
d945816
+    return 0;
d945816
+  /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions.  */
d945816
+  i386_linux_detach_breakpoints_pid = 0;
d945816
+
25ff8a1
+  return i386_remove_watchpoint (addr, len, type);
25ff8a1
+}
25ff8a1
+
9a1b988
+static void
d945816
+i386_linux_detach_breakpoints (int detached_pid)
9a1b988
+{
d945816
+  struct cleanup *old_chain = save_inferior_ptid ();
9a1b988
+  int i;
9a1b988
+
d945816
+  i386_linux_detach_breakpoints_pid = detached_pid;
d945816
+  /* Depend on `!is_lwp (inferior_ptid)' for the I386_* macros.  */
d945816
+  inferior_ptid = pid_to_ptid (detached_pid);
9a1b988
+
d945816
+  i386_detach_breakpoints (detached_pid);
d945816
+
d945816
+  do_cleanups (old_chain);
d945816
+}
25ff8a1
 
25ff8a1
 
25ff8a1
 /* Called by libthread_db.  Returns a pointer to the thread local
407ebe9
@@ -812,6 +868,40 @@ i386_linux_child_post_startup_inferior (
d945816
   super_post_startup_inferior (ptid);
d945816
 }
d945816
 
d945816
+static int (*i386_linux_super_follow_fork) (struct target_ops *ops,
d945816
+					    int follow_child);
d945816
+
d945816
+/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its
d945816
+   called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror.  */
d945816
+
d945816
+static int
d945816
+i386_linux_follow_fork (struct target_ops *ops, int follow_child)
d945816
+{
d945816
+  ptid_t last_ptid;
d945816
+  struct target_waitstatus last_status;
d945816
+  int has_vforked;
d945816
+  int parent_pid, child_pid;
d945816
+
d945816
+  get_last_target_status (&last_ptid, &last_status);
d945816
+  has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
d945816
+  parent_pid = ptid_get_lwp (last_ptid);
d945816
+  if (parent_pid == 0)
d945816
+    parent_pid = ptid_get_pid (last_ptid);
407ebe9
+  child_pid = ptid_get_pid (last_status.value.related_pid);
d945816
+
d945816
+  if (! follow_child)
9a1b988
+    {
d945816
+      i386_linux_detach_breakpoints (child_pid);
9a1b988
+    }
9a1b988
+  else
9a1b988
+    {
d945816
+      if (! has_vforked)
d945816
+	i386_linux_detach_breakpoints (child_pid);
9a1b988
+    }
9a1b988
+
d945816
+  return (*i386_linux_super_follow_fork) (ops, follow_child);
9a1b988
+}
9a1b988
+
d945816
 void
d945816
 _initialize_i386_linux_nat (void)
9a1b988
 {
407ebe9
@@ -833,6 +923,9 @@ _initialize_i386_linux_nat (void)
d945816
   t->to_fetch_registers = i386_linux_fetch_inferior_registers;
d945816
   t->to_store_registers = i386_linux_store_inferior_registers;
d945816
 
d945816
+  i386_linux_super_follow_fork = t->to_follow_fork;
d945816
+  t->to_follow_fork = i386_linux_follow_fork;
d945816
+
d945816
   /* Register the target.  */
d945816
   linux_nat_add_target (t);
25ff8a1
   linux_nat_set_new_thread (t, i386_linux_new_thread);
81783d0
Index: gdb-6.8.50.20090209/gdb/i386-nat.c
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/i386-nat.c	2009-01-03 06:57:51.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/i386-nat.c	2009-02-09 16:02:42.000000000 +0100
81783d0
@@ -546,6 +546,17 @@ i386_remove_watchpoint (CORE_ADDR addr, 
d945816
   return retval;
d945816
 }
d945816
 
d945816
+void
d945816
+i386_detach_breakpoints (int detached_pid)
d945816
+{
d945816
+  int i;
d945816
+
d945816
+  /* Do not touch any DR_MIRROR or DR_CONTROL_MIRROR mirrors here.  */
d945816
+  I386_DR_LOW_SET_CONTROL (0);
d945816
+  ALL_DEBUG_REGISTERS(i)
d945816
+    I386_DR_LOW_RESET_ADDR (i);
d945816
+}
9a1b988
+
d945816
 /* Return non-zero if we can watch a memory region that starts at
d945816
    address ADDR and whose length is LEN bytes.  */
d945816
 
81783d0
Index: gdb-6.8.50.20090209/gdb/ia64-linux-nat.c
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/ia64-linux-nat.c	2009-02-09 15:48:43.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/ia64-linux-nat.c	2009-02-09 16:02:42.000000000 +0100
25ff8a1
@@ -583,6 +583,12 @@ ia64_linux_insert_watchpoint (CORE_ADDR 
25ff8a1
   return 0;
d945816
 }
d945816
 
d945816
+/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child
d945816
+   process of traced FORK.  We must clear such watchpoints only once during
d945816
+   DETACH_BREAKPOINTS.  */
d945816
+
d945816
+static int ia64_linux_detach_breakpoints_pid;
d945816
+
2a65074
 static int
25ff8a1
 ia64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type)
9a1b988
 {
25ff8a1
@@ -590,6 +596,11 @@ ia64_linux_remove_watchpoint (CORE_ADDR 
25ff8a1
   long dbr_addr, dbr_mask;
25ff8a1
   int max_watchpoints = 4;
d945816
 
d945816
+  if (ptid_get_pid (inferior_ptid) == ia64_linux_detach_breakpoints_pid)
d945816
+    return 0;
d945816
+  /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions.  */
d945816
+  ia64_linux_detach_breakpoints_pid = 0;
d945816
+
25ff8a1
   if (len <= 0 || !is_power_of_2 (len))
25ff8a1
     return -1;
25ff8a1
 
25ff8a1
@@ -617,6 +628,22 @@ ia64_linux_remove_watchpoint (CORE_ADDR 
25ff8a1
 }
9a1b988
 
d945816
 static void
d945816
+ia64_linux_detach_breakpoints (int detached_pid)
d945816
+{
d945816
+  int idx, i;
d945816
+  long dbr_addr, dbr_mask;
d945816
+  int max_watchpoints = 4;
d945816
+
d945816
+  ia64_linux_detach_breakpoints_pid = detached_pid;
9a1b988
+
d945816
+  /* Do not touch any DEBUG_REGISTERS mirrors here.  */
d945816
+  dbr_addr = 0;
d945816
+  dbr_mask = 0;
d945816
+  for (idx = 0; idx < max_watchpoints; idx++)
d945816
+    store_debug_register_pair (ptid_build (detached_pid, 0, 0), idx, &dbr_addr, &dbr_mask);
d945816
+}
d945816
+
d945816
+static void
d945816
 ia64_linux_new_thread (ptid_t ptid)
9a1b988
 {
25ff8a1
   int i, any;
25ff8a1
@@ -805,6 +832,40 @@ ia64_linux_xfer_partial (struct target_o
25ff8a1
 			     offset, len);
d945816
 }
9a1b988
 
d945816
+static int (*ia64_linux_super_follow_fork) (struct target_ops *ops,
d945816
+					    int follow_child);
d945816
+
d945816
+/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its
d945816
+   called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror.  */
9a1b988
+
d945816
+int
d945816
+ia64_linux_follow_fork (struct target_ops *ops, int follow_child)
d945816
+{
d945816
+  ptid_t last_ptid;
d945816
+  struct target_waitstatus last_status;
d945816
+  int has_vforked;
d945816
+  int parent_pid, child_pid;
d945816
+
d945816
+  get_last_target_status (&last_ptid, &last_status);
d945816
+  has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
d945816
+  parent_pid = ptid_get_lwp (last_ptid);
d945816
+  if (parent_pid == 0)
d945816
+    parent_pid = ptid_get_pid (last_ptid);
407ebe9
+  child_pid = ptid_get_pid (last_status.value.related_pid);
d945816
+
d945816
+  if (! follow_child)
d945816
+    {
d945816
+      ia64_linux_detach_breakpoints (child_pid);
d945816
+    }
d945816
+  else
d945816
+    {
d945816
+      if (! has_vforked)
d945816
+	ia64_linux_detach_breakpoints (child_pid);
d945816
+    }
d945816
+
d945816
+  return (*ia64_linux_super_follow_fork) (ops, follow_child);
d945816
+}
d945816
+
d945816
 void _initialize_ia64_linux_nat (void);
d945816
 
d945816
 /*
25ff8a1
@@ -899,6 +960,9 @@ _initialize_ia64_linux_nat (void)
25ff8a1
   t->to_insert_watchpoint = ia64_linux_insert_watchpoint;
25ff8a1
   t->to_remove_watchpoint = ia64_linux_remove_watchpoint;
d945816
 
d945816
+  ia64_linux_super_follow_fork = t->to_follow_fork;
d945816
+  t->to_follow_fork = ia64_linux_follow_fork;
d945816
+
d945816
   /* Register the target.  */
d945816
   linux_nat_add_target (t);
25ff8a1
   linux_nat_set_new_thread (t, ia64_linux_new_thread);
81783d0
Index: gdb-6.8.50.20090209/gdb/ppc-linux-nat.c
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/ppc-linux-nat.c	2009-01-03 06:57:52.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/ppc-linux-nat.c	2009-02-09 16:02:42.000000000 +0100
407ebe9
@@ -1118,6 +1118,12 @@ ppc_linux_insert_watchpoint (CORE_ADDR a
25ff8a1
   return 0;
d945816
 }
d945816
 
d945816
+/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child
d945816
+   process of traced FORK.  We must clear such watchpoints only once during
d945816
+   DETACH_BREAKPOINTS.  */
d945816
+
d945816
+static int ppc_linux_detach_breakpoints_pid;
d945816
+
d945816
 static int
d945816
 ppc_linux_remove_watchpoint (CORE_ADDR addr, int len, int rw)
d945816
 {
407ebe9
@@ -1125,6 +1131,11 @@ ppc_linux_remove_watchpoint (CORE_ADDR a
25ff8a1
   ptid_t ptid;
25ff8a1
   long dabr_value = 0;
d945816
 
d945816
+  if (ptid_get_pid (inferior_ptid) == ppc_linux_detach_breakpoints_pid)
d945816
+    return 0;
d945816
+  /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions.  */
d945816
+  ppc_linux_detach_breakpoints_pid = 0;
d945816
+
25ff8a1
   saved_dabr_value = 0;
25ff8a1
   ALL_LWPS (lp, ptid)
25ff8a1
     if (ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value) < 0)
407ebe9
@@ -1138,6 +1149,15 @@ ppc_linux_new_thread (ptid_t ptid)
25ff8a1
   ptrace (PTRACE_SET_DEBUGREG, TIDGET (ptid), 0, saved_dabr_value);
d945816
 }
d945816
 
d945816
+static void
d945816
+ppc_linux_detach_breakpoints (int detached_pid)
d945816
+{
d945816
+  ppc_linux_detach_breakpoints_pid = detached_pid;
d945816
+
d945816
+  /* Do not touch the SAVED_DABR_VALUE mirror here.  */
d945816
+  ptrace (PTRACE_SET_DEBUGREG, detached_pid, 0, 0);
d945816
+}
d945816
+
d945816
 static int
d945816
 ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
d945816
 {
407ebe9
@@ -1318,6 +1338,40 @@ ppc_linux_read_description (struct targe
407ebe9
   return isa205? tdesc_powerpc_isa205_32l : tdesc_powerpc_32l;
d945816
 }
d945816
 
d945816
+static int (*ppc_linux_super_follow_fork) (struct target_ops *ops,
d945816
+					   int follow_child);
d945816
+
d945816
+/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its
d945816
+   called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror.  */
d945816
+
d945816
+int
d945816
+ppc_linux_follow_fork (struct target_ops *ops, int follow_child)
d945816
+{
d945816
+  ptid_t last_ptid;
d945816
+  struct target_waitstatus last_status;
d945816
+  int has_vforked;
d945816
+  int parent_pid, child_pid;
d945816
+
d945816
+  get_last_target_status (&last_ptid, &last_status);
d945816
+  has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
d945816
+  parent_pid = ptid_get_lwp (last_ptid);
d945816
+  if (parent_pid == 0)
d945816
+    parent_pid = ptid_get_pid (last_ptid);
407ebe9
+  child_pid = ptid_get_pid (last_status.value.related_pid);
d945816
+
d945816
+  if (! follow_child)
d945816
+    {
d945816
+      ppc_linux_detach_breakpoints (child_pid);
d945816
+    }
d945816
+  else
d945816
+    {
d945816
+      if (! has_vforked)
d945816
+	ppc_linux_detach_breakpoints (child_pid);
d945816
+    }
d945816
+
d945816
+  return (*ppc_linux_super_follow_fork) (ops, follow_child);
d945816
+}
d945816
+
d945816
 void _initialize_ppc_linux_nat (void);
d945816
 
d945816
 void
407ebe9
@@ -1343,6 +1397,9 @@ _initialize_ppc_linux_nat (void)
25ff8a1
 
25ff8a1
   t->to_read_description = ppc_linux_read_description;
d945816
 
d945816
+  ppc_linux_super_follow_fork = t->to_follow_fork;
d945816
+  t->to_follow_fork = ppc_linux_follow_fork;
d945816
+
d945816
   /* Register the target.  */
d945816
   linux_nat_add_target (t);
25ff8a1
   linux_nat_set_new_thread (t, ppc_linux_new_thread);
81783d0
Index: gdb-6.8.50.20090209/gdb/s390-nat.c
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/s390-nat.c	2007-11-07 07:36:57.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/s390-nat.c	2009-02-09 16:02:42.000000000 +0100
25ff8a1
@@ -283,21 +283,15 @@ s390_stopped_by_watchpoint (void)
d945816
 }
d945816
 
d945816
 static void
d945816
-s390_fix_watch_points (ptid_t ptid)
2234aa8
+s390_fix_watch_points_list (int tid, struct watch_area *area_list)
d945816
 {
25ff8a1
-  int tid;
d945816
-
d945816
   per_struct per_info;
d945816
   ptrace_area parea;
d945816
 
d945816
   CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0;
d945816
   struct watch_area *area;
d945816
 
25ff8a1
-  tid = TIDGET (ptid);
25ff8a1
-  if (tid == 0)
25ff8a1
-    tid = PIDGET (ptid);
25ff8a1
-
d945816
-  for (area = watch_base; area; area = area->next)
d945816
+  for (area = area_list; area; area = area->next)
9a1b988
     {
d945816
       watch_lo_addr = min (watch_lo_addr, area->lo_addr);
d945816
       watch_hi_addr = max (watch_hi_addr, area->hi_addr);
25ff8a1
@@ -309,7 +303,7 @@ s390_fix_watch_points (ptid_t ptid)
d945816
   if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0)
d945816
     perror_with_name (_("Couldn't retrieve watchpoint status"));
d945816
 
d945816
-  if (watch_base)
d945816
+  if (area_list)
d945816
     {
d945816
       per_info.control_regs.bits.em_storage_alteration = 1;
d945816
       per_info.control_regs.bits.storage_alt_space_ctl = 1;
25ff8a1
@@ -326,6 +320,18 @@ s390_fix_watch_points (ptid_t ptid)
d945816
     perror_with_name (_("Couldn't modify watchpoint status"));
d945816
 }
9a1b988
 
d945816
+static void
d945816
+s390_fix_watch_points (ptid_t ptid)
d945816
+{
25ff8a1
+  int tid;
25ff8a1
+
25ff8a1
+  tid = TIDGET (ptid);
25ff8a1
+  if (tid == 0)
25ff8a1
+    tid = PIDGET (ptid);
25ff8a1
+
25ff8a1
+  s390_fix_watch_points_list (tid, watch_base);
d945816
+}
9a1b988
+
d945816
 static int
25ff8a1
 s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
25ff8a1
 {
25ff8a1
@@ -347,6 +353,12 @@ s390_insert_watchpoint (CORE_ADDR addr, 
d945816
   return 0;
d945816
 }
9a1b988
 
d945816
+/* TO_FOLLOW_FORK stores here the PID under DETACH_BREAKPOINTS for the child
d945816
+   process of traced FORK.  We must clear such watchpoints only once during
d945816
+   DETACH_BREAKPOINTS.  */
d945816
+
d945816
+static int s390_detach_breakpoints_pid;
d945816
+
d945816
 static int
d945816
 s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
9a1b988
 {
25ff8a1
@@ -354,6 +366,11 @@ s390_remove_watchpoint (CORE_ADDR addr, 
25ff8a1
   ptid_t ptid;
d945816
   struct watch_area *area, **parea;
d945816
 
d945816
+  if (ptid_get_pid (inferior_ptid) == s390_detach_breakpoints_pid)
d945816
+    return 0;
d945816
+  /* FOLLOW-FORK-MODE CHILD runs later the CHILD with no restrictions.  */
d945816
+  s390_detach_breakpoints_pid = 0;
d945816
+
d945816
   for (parea = &watch_base; *parea; parea = &(*parea)->next)
d945816
     if ((*parea)->lo_addr == addr
d945816
 	&& (*parea)->hi_addr == addr + len - 1)
407ebe9
@@ -361,8 +378,10 @@ s390_remove_watchpoint (CORE_ADDR addr, 
10f824b
 
10f824b
   if (!*parea)
10f824b
     {
10f824b
+#if 0 /* Red Hat fork/threads watchpoints changes may trigger it.  */
10f824b
       fprintf_unfiltered (gdb_stderr,
10f824b
 			  "Attempt to remove nonexistent watchpoint.\n");
10f824b
+#endif
10f824b
       return -1;
10f824b
     }
10f824b
 
407ebe9
@@ -375,6 +394,15 @@ s390_remove_watchpoint (CORE_ADDR addr, 
d945816
   return 0;
d945816
 }
d945816
 
d945816
+static void
d945816
+s390_detach_breakpoints (int detached_pid)
d945816
+{
d945816
+  s390_detach_breakpoints_pid = detached_pid;
d945816
+
d945816
+  /* Do not touch the WATCH_BASE here.  */
d945816
+  s390_fix_watch_points_list (detached_pid, NULL);
d945816
+}
d945816
+
d945816
 static int
d945816
 s390_can_use_hw_breakpoint (int type, int cnt, int othertype)
d945816
 {
407ebe9
@@ -387,6 +415,39 @@ s390_region_ok_for_hw_watchpoint (CORE_A
25ff8a1
   return 1;
d945816
 }
d945816
 
d945816
+static int (*s390_super_follow_fork) (struct target_ops *ops, int follow_child);
d945816
+
d945816
+/* We need to duplicate the LINUX_CHILD_FOLLOW_FORK behavior here and catch its
d945816
+   called DETACH_BREAKPOINTS to avoid corrupting our local registers mirror.  */
d945816
+
d945816
+int
d945816
+s390_follow_fork (struct target_ops *ops, int follow_child)
d945816
+{
d945816
+  ptid_t last_ptid;
d945816
+  struct target_waitstatus last_status;
d945816
+  int has_vforked;
d945816
+  int parent_pid, child_pid;
d945816
+
d945816
+  get_last_target_status (&last_ptid, &last_status);
d945816
+  has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
d945816
+  parent_pid = ptid_get_lwp (last_ptid);
d945816
+  if (parent_pid == 0)
d945816
+    parent_pid = ptid_get_pid (last_ptid);
407ebe9
+  child_pid = ptid_get_pid (last_status.value.related_pid);
d945816
+
d945816
+  if (! follow_child)
d945816
+    {
d945816
+      s390_detach_breakpoints (child_pid);
d945816
+    }
d945816
+  else
d945816
+    {
d945816
+      if (! has_vforked)
d945816
+	s390_detach_breakpoints (child_pid);
d945816
+    }
d945816
+
d945816
+  return (*s390_super_follow_fork) (ops, follow_child);
d945816
+}
d945816
+
d945816
 
d945816
 void _initialize_s390_nat (void);
d945816
 
407ebe9
@@ -410,6 +471,9 @@ _initialize_s390_nat (void)
d945816
   t->to_insert_watchpoint = s390_insert_watchpoint;
d945816
   t->to_remove_watchpoint = s390_remove_watchpoint;
9a1b988
 
d945816
+  s390_super_follow_fork = t->to_follow_fork;
d945816
+  t->to_follow_fork = s390_follow_fork;
9a1b988
+
d945816
   /* Register the target.  */
d945816
   linux_nat_add_target (t);
25ff8a1
   linux_nat_set_new_thread (t, s390_fix_watch_points);
81783d0
Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c
407ebe9
===================================================================
407ebe9
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
81783d0
+++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-forkoff.c	2009-02-09 16:02:42.000000000 +0100
e923707
@@ -0,0 +1,172 @@
9a1b988
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
9a1b988
+
d945816
+   Copyright 2008
d945816
+   Free Software Foundation, Inc.
d945816
+
d945816
+   This file is part of GDB.
d945816
+
d945816
+   This program is free software; you can redistribute it and/or modify
d945816
+   it under the terms of the GNU General Public License as published by
d945816
+   the Free Software Foundation; either version 2 of the License, or
d945816
+   (at your option) any later version.
d945816
+
d945816
+   This program is distributed in the hope that it will be useful,
d945816
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
d945816
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d945816
+   GNU General Public License for more details.
d945816
+
d945816
+   You should have received a copy of the GNU General Public License
d945816
+   along with this program; if not, write to the Free Software
d945816
+   Foundation, Inc., 59 Temple Place - Suite 330,
d945816
+   Boston, MA 02111-1307, USA.  */
d945816
+
d945816
+#include <string.h>
d945816
+#include <errno.h>
d945816
+
d945816
+static void delay (void)
d945816
+{
d945816
+  int i = usleep (1000000 / 100);
d945816
+  assert (i == 0 || errno == EINTR);
d945816
+}
d945816
+
d945816
+#if defined FOLLOW_PARENT
d945816
+
d945816
+static void forkoff (int nr)
d945816
+{
d945816
+  pid_t child, pid_got;
d945816
+  int exit_code = 42 + nr;
e923707
+  int status, i;
d945816
+
d945816
+  child = fork ();
d945816
+  switch (child)
d945816
+    {
d945816
+    case -1:
d945816
+      assert (0);
d945816
+    case 0:
d945816
+      printf ("child%d: %d\n", nr, (int) getpid ());
e923707
+      /* Delay to get both the "child%d" and "parent%d" message printed without
e923707
+	 a race breaking expect by its endless wait on `$gdb_prompt$':
e923707
+	 Breakpoint 3, breakpoint () at ../../../gdb/testsuite/gdb.threads/watchpoint-fork.c:33
e923707
+	 33      }
e923707
+	 (gdb) parent2: 14223  */
e923707
+      i = sleep (1);
e923707
+      assert (i == 0);
d945816
+
d945816
+      /* We must not get caught here (against a forgotten breakpoint).  */
d945816
+      var++;
d945816
+      breakpoint ();
d945816
+
d945816
+      _exit (exit_code);
d945816
+    default:
d945816
+      printf ("parent%d: %d\n", nr, (int) child);
e923707
+      /* Delay to get both the "child%d" and "parent%d" message printed, see
e923707
+	 above.  */
e923707
+      i = sleep (1);
e923707
+      assert (i == 0);
e923707
+
d945816
+      pid_got = wait (&status);
d945816
+      assert (pid_got == child);
d945816
+      assert (WIFEXITED (status));
d945816
+      assert (WEXITSTATUS (status) == exit_code);
d945816
+
d945816
+      /* We must get caught here (against a false watchpoint removal).  */
d945816
+      breakpoint ();
d945816
+    }
d945816
+}
d945816
+
d945816
+#elif defined FOLLOW_CHILD
d945816
+
d945816
+static volatile int usr1_got;
d945816
+
d945816
+static void handler_usr1 (int signo)
d945816
+{
d945816
+  usr1_got++;
d945816
+}
d945816
+
d945816
+static void forkoff (int nr)
d945816
+{
d945816
+  pid_t child;
d945816
+  int i, loop;
d945816
+  struct sigaction act, oldact;
d945816
+#ifdef THREAD
d945816
+  void *thread_result;
d945816
+#endif
d945816
+
d945816
+  memset (&act, 0, sizeof act);
d945816
+  act.sa_flags = SA_RESTART;
d945816
+  act.sa_handler = handler_usr1;
d945816
+  sigemptyset (&act.sa_mask);
d945816
+  i = sigaction (SIGUSR1, &act, &oldact);
d945816
+  assert (i == 0);
d945816
+
d945816
+  child = fork ();
d945816
+  switch (child)
d945816
+    {
d945816
+    case -1:
d945816
+      assert (0);
d945816
+    default:
d945816
+      printf ("parent%d: %d\n", nr, (int) child);
d945816
+
d945816
+      /* Sleep for a while to possibly get incorrectly ATTACH_THREADed by GDB
d945816
+         tracing the child fork with no longer valid thread/lwp entries of the
d945816
+         parent.  */
d945816
+
d945816
+      i = sleep (2);
d945816
+      assert (i == 0);
d945816
+
d945816
+      /* We must not get caught here (against a forgotten breakpoint).  */
d945816
+
d945816
+      var++;
d945816
+      breakpoint ();
d945816
+
d945816
+#ifdef THREAD
d945816
+      /* And neither got caught our thread.  */
d945816
+
d945816
+      step = 99;
d945816
+      i = pthread_join (thread, &thread_result);
d945816
+      assert (i == 0);
d945816
+      assert (thread_result == (void *) 99UL);
d945816
+#endif
d945816
+
d945816
+      /* Be sure our child knows we did not get caught above.  */
d945816
+
d945816
+      i = kill (child, SIGUSR1);
d945816
+      assert (i == 0);
d945816
+
d945816
+      /* Sleep for a while to check GDB's `info threads' no longer tracks us in
d945816
+         the child fork.  */
d945816
+
d945816
+      i = sleep (2);
d945816
+      assert (i == 0);
d945816
+
d945816
+      _exit (0);
d945816
+    case 0:
d945816
+      printf ("child%d: %d\n", nr, (int) getpid ());
d945816
+
d945816
+      /* Let the parent signal us about its success.  Be careful of races.  */
d945816
+
d945816
+      for (loop = 0; loop < 1000; loop++)
d945816
+        {
d945816
+	  /* Parent either died (and USR1_GOT is zero) or it succeeded.  */
d945816
+	  if (kill (getppid (), 0) != 0)
d945816
+	    break;
d945816
+	  /* Parent succeeded?  */
d945816
+	  if (usr1_got)
d945816
+	    break;
d945816
+
d945816
+	  delay ();
d945816
+	}
d945816
+      assert (usr1_got);
d945816
+
d945816
+      /* We must get caught here (against a false watchpoint removal).  */
d945816
+
d945816
+      breakpoint ();
d945816
+    }
d945816
+
d945816
+  i = sigaction (SIGUSR1, &oldact, NULL);
d945816
+  assert (i == 0);
d945816
+}
d945816
+
d945816
+#else
d945816
+# error "!FOLLOW_PARENT && !FOLLOW_CHILD"
d945816
+#endif
81783d0
Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c
25ff8a1
===================================================================
25ff8a1
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
81783d0
+++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork-mt.c	2009-02-09 16:02:42.000000000 +0100
d945816
@@ -0,0 +1,154 @@
d945816
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
d945816
+
d945816
+   Copyright 2008
9a1b988
+   Free Software Foundation, Inc.
9a1b988
+
9a1b988
+   This file is part of GDB.
9a1b988
+
9a1b988
+   This program is free software; you can redistribute it and/or modify
9a1b988
+   it under the terms of the GNU General Public License as published by
9a1b988
+   the Free Software Foundation; either version 2 of the License, or
9a1b988
+   (at your option) any later version.
9a1b988
+
9a1b988
+   This program is distributed in the hope that it will be useful,
9a1b988
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
9a1b988
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9a1b988
+   GNU General Public License for more details.
9a1b988
+
9a1b988
+   You should have received a copy of the GNU General Public License
9a1b988
+   along with this program; if not, write to the Free Software
9a1b988
+   Foundation, Inc., 59 Temple Place - Suite 330,
9a1b988
+   Boston, MA 02111-1307, USA.  */
9a1b988
+
9a1b988
+#include <assert.h>
9a1b988
+#include <unistd.h>
9a1b988
+#include <sys/wait.h>
9a1b988
+#include <stdio.h>
9a1b988
+#include <stdlib.h>
d945816
+#include <pthread.h>
d945816
+
d945816
+#include <asm/unistd.h>
d945816
+#include <unistd.h>
d945816
+#define gettid() syscall (__NR_gettid)
d945816
+
d945816
+/* Non-atomic `var++' should not hurt as we synchronize the threads by the STEP
d945816
+   variable.  Hit-comments need to be duplicite there to catch both at-stops
d945816
+   and behind-stops, depending on the target.  */
9a1b988
+
9a1b988
+static volatile int var;
9a1b988
+
d945816
+static void dummy (void)
d945816
+{
d945816
+}
d945816
+
9a1b988
+static void breakpoint (void)
9a1b988
+{
9a1b988
+}
9a1b988
+
d945816
+/* Include here the functions:
d945816
+   static void forkoff (int nr);
d945816
+   static void delay (void);  */
d945816
+
d945816
+static pthread_t thread;
d945816
+static volatile int step;
d945816
+#define THREAD
d945816
+
d945816
+#include "watchpoint-fork-forkoff.c"
d945816
+
d945816
+static void *start (void *arg)
9a1b988
+{
d945816
+  if (step >= 3)
d945816
+    goto step_3;
9a1b988
+
d945816
+  while (step != 1)
d945816
+    delay ();
d945816
+
d945816
+  var++;	/* validity-thread-B */
d945816
+  dummy ();	/* validity-thread-B */
d945816
+  step = 2;
d945816
+  while (step != 3)
9a1b988
+    {
d945816
+      if (step == 99)
d945816
+        goto step_99;
d945816
+      delay ();
9a1b988
+    }
d945816
+
d945816
+step_3:
d945816
+  if (step >= 5)
d945816
+    goto step_5;
d945816
+
d945816
+  var++;	/* after-fork1-B */
d945816
+  dummy ();	/* after-fork1-B */
d945816
+  step = 4;
d945816
+  while (step != 5)
d945816
+    {
d945816
+      if (step == 99)
d945816
+        goto step_99;
d945816
+      delay ();
d945816
+    }
d945816
+
d945816
+step_5:
d945816
+  var++;	/* after-fork2-B */
d945816
+  dummy ();	/* after-fork2-B */
d945816
+  return (void *) 5UL;
d945816
+
d945816
+step_99:
d945816
+  /* We must not get caught here (against a forgotten breakpoint).  */
d945816
+  var++;
d945816
+  breakpoint ();
d945816
+  return (void *) 99UL;
9a1b988
+}
9a1b988
+
9a1b988
+int main (void)
25ff8a1
+{
d945816
+  int i;
d945816
+  void *thread_result;
d945816
+
d945816
+  setbuf (stdout, NULL);
d945816
+  printf ("main: %d\n", (int) gettid ());
d945816
+
d945816
+  /* General watchpoints validity.  */
d945816
+  var++;	/* validity-first */
d945816
+  dummy ();	/* validity-first */
d945816
+
d945816
+  i = pthread_create (&thread, NULL, start, NULL);
d945816
+  assert (i == 0);
d945816
+
d945816
+  var++;	/* validity-thread-A */
d945816
+  dummy ();	/* validity-thread-A */
d945816
+  step = 1;
d945816
+  while (step != 2)
d945816
+    delay ();
d945816
+
d945816
+  /* Hardware watchpoints got disarmed here.  */
d945816
+  forkoff (1);
d945816
+
d945816
+  var++;	/* after-fork1-A */
d945816
+  dummy ();	/* after-fork1-A */
d945816
+  step = 3;
d945816
+#ifdef FOLLOW_CHILD
d945816
+  /* Spawn new thread as it was deleted in the child of FORK.  */
d945816
+  i = pthread_create (&thread, NULL, start, NULL);
d945816
+  assert (i == 0);
d945816
+#endif
d945816
+  while (step != 4)
d945816
+    delay ();
d945816
+
d945816
+  /* A sanity check for double hardware watchpoints removal.  */
d945816
+  forkoff (2);
d945816
+
d945816
+  var++;	/* after-fork2-A */
d945816
+  dummy ();	/* after-fork2-A */
d945816
+  step = 5;
d945816
+#ifdef FOLLOW_CHILD
d945816
+  /* Spawn new thread as it was deleted in the child of FORK.  */
d945816
+  i = pthread_create (&thread, NULL, start, NULL);
d945816
+  assert (i == 0);
d945816
+#endif
d945816
+
d945816
+  i = pthread_join (thread, &thread_result);
d945816
+  assert (i == 0);
d945816
+  assert (thread_result == (void *) 5UL);
d945816
+
d945816
+  return 0;
d945816
+}
81783d0
Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.c
25ff8a1
===================================================================
25ff8a1
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
81783d0
+++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.c	2009-02-09 16:02:42.000000000 +0100
d945816
@@ -0,0 +1,56 @@
d945816
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
d945816
+
d945816
+   Copyright 2008
d945816
+   Free Software Foundation, Inc.
d945816
+
d945816
+   This file is part of GDB.
d945816
+
d945816
+   This program is free software; you can redistribute it and/or modify
d945816
+   it under the terms of the GNU General Public License as published by
d945816
+   the Free Software Foundation; either version 2 of the License, or
d945816
+   (at your option) any later version.
d945816
+
d945816
+   This program is distributed in the hope that it will be useful,
d945816
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
d945816
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
d945816
+   GNU General Public License for more details.
d945816
+
d945816
+   You should have received a copy of the GNU General Public License
d945816
+   along with this program; if not, write to the Free Software
d945816
+   Foundation, Inc., 59 Temple Place - Suite 330,
d945816
+   Boston, MA 02111-1307, USA.  */
d945816
+
d945816
+#include <assert.h>
d945816
+#include <unistd.h>
d945816
+#include <sys/wait.h>
d945816
+#include <stdio.h>
d945816
+#include <stdlib.h>
d945816
+
d945816
+static volatile int var;
d945816
+
d945816
+static void breakpoint (void)
d945816
+{
d945816
+}
d945816
+
d945816
+/* Include here the function:
d945816
+   static void forkoff (int nr);  */
d945816
+
d945816
+#include "watchpoint-fork-forkoff.c"
d945816
+
d945816
+int main (void)
9a1b988
+{
9a1b988
+  setbuf (stdout, NULL);
9a1b988
+  printf ("main: %d\n", (int) getpid ());
9a1b988
+
d945816
+  /* General watchpoints validity.  */
d945816
+  var++;
9a1b988
+  /* Hardware watchpoints got disarmed here.  */
9a1b988
+  forkoff (1);
9a1b988
+  /* This watchpoint got lost before.  */
9a1b988
+  var++;
9a1b988
+  /* A sanity check for double hardware watchpoints removal.  */
9a1b988
+  forkoff (2);
9a1b988
+  var++;
9a1b988
+
9a1b988
+  return 0;
9a1b988
+}
81783d0
Index: gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.exp
25ff8a1
===================================================================
25ff8a1
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
81783d0
+++ gdb-6.8.50.20090209/gdb/testsuite/gdb.threads/watchpoint-fork.exp	2009-02-09 16:02:42.000000000 +0100
d945816
@@ -0,0 +1,140 @@
d945816
+# Copyright 2008 Free Software Foundation, Inc.
9a1b988
+
9a1b988
+# This program is free software; you can redistribute it and/or modify
9a1b988
+# it under the terms of the GNU General Public License as published by
9a1b988
+# the Free Software Foundation; either version 3 of the License, or
9a1b988
+# (at your option) any later version.
9a1b988
+#
9a1b988
+# This program is distributed in the hope that it will be useful,
9a1b988
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
9a1b988
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9a1b988
+# GNU General Public License for more details.
9a1b988
+#
9a1b988
+# You should have received a copy of the GNU General Public License
9a1b988
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
9a1b988
+
d945816
+# Test case for forgotten hw-watchpoints after fork()-off of a process.
9a1b988
+
d945816
+proc test {type symbol} {
d945816
+    global objdir subdir srcdir
9a1b988
+
d945816
+    global pf_prefix
d945816
+    set prefix_test $pf_prefix
d945816
+    lappend pf_prefix "$type:"
d945816
+    set prefix_mt $pf_prefix
9a1b988
+
d945816
+    # no threads
9a1b988
+
d945816
+    set pf_prefix $prefix_mt
d945816
+    lappend pf_prefix "singlethreaded:"
9a1b988
+
d945816
+    set testfile watchpoint-fork
d945816
+    set srcfile ${testfile}.c
d945816
+    set binfile ${objdir}/${subdir}/${testfile}
d945816
+
d945816
+    if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug additional_flags=-D$symbol"] != "" } {
d945816
+	untested "Couldn't compile test program"
d945816
+	return -1
d945816
+    }
d50521f
+
d945816
+    gdb_exit
d945816
+    gdb_start
d945816
+    gdb_reinitialize_dir $srcdir/$subdir
d945816
+    gdb_load ${binfile}
d50521f
+
d945816
+    gdb_test "set follow-fork-mode $type"
d945816
+    # Testcase uses it for the `follow-fork-mode child' type.
d945816
+    gdb_test "handle SIGUSR1 nostop noprint pass"
d945816
+
d945816
+    if { ![runto_main] } then {
d945816
+	gdb_suppress_tests
d945816
+	return
d945816
+    }
d50521f
+
d945816
+    # Install the watchpoint only after getting into MAIN - workaround some PPC
d945816
+    # problem.
d945816
+    gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint"
d945816
+
d945816
+    # It is never hit but it should not be left over in the fork()ed-off child.
d945816
+    gdb_breakpoint "breakpoint"
d945816
+
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work"
d945816
+    gdb_test "continue" \
d945816
+	     "reakpoint 3, breakpoint.*" "breakpoint after the first fork"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork"
d945816
+    gdb_test "continue" \
d945816
+	     "reakpoint 3, breakpoint.*" "breakpoint after the second fork"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 2.*New value = 3.*return *0;" "watchpoint after the second fork"
d945816
+    gdb_test "continue" "Continuing..*Program exited normally." "finish"
d945816
+
d945816
+
d945816
+    # threads
d945816
+
d945816
+    set pf_prefix $prefix_mt
d945816
+    lappend pf_prefix "multithreaded:"
d945816
+
d945816
+    set testfile watchpoint-fork-mt
d945816
+    set srcfile ${testfile}.c
d945816
+    set binfile ${objdir}/${subdir}/${testfile}
d945816
+
d945816
+    if  { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug additional_flags=-D$symbol"] != "" } {
d945816
+	untested "Couldn't compile test program"
d945816
+	return -1
d945816
+    }
d945816
+
d945816
+    gdb_exit
d945816
+    gdb_start
d945816
+    gdb_reinitialize_dir $srcdir/$subdir
d945816
+    gdb_load ${binfile}
d945816
+
d945816
+    gdb_test "set follow-fork-mode $type"
d945816
+    # Testcase uses it for the `follow-fork-mode child' type.
d945816
+    gdb_test "handle SIGUSR1 nostop noprint pass"
d945816
+
d945816
+    if { ![runto_main] } then {
d945816
+	gdb_suppress_tests
d945816
+	return
d945816
+    }
d945816
+
d945816
+    # Install the watchpoint only after getting into MAIN - workaround some PPC
d945816
+    # problem.
d945816
+    gdb_test "watch var" "atchpoint 2: var" "Set the watchpoint"
d945816
+
d945816
+    # It is never hit but it should not be left over in the fork()ed-off child.
d945816
+    gdb_breakpoint "breakpoint"
d945816
+
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 0.*New value = 1.*validity-first.*" "singlethread watchpoints work"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 1.*New value = 2.*validity-thread-A.*" "multithreaded watchpoints work at A"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 2.*New value = 3.*validity-thread-B.*" "multithreaded watchpoints work at B"
d945816
+    gdb_test "continue" \
d945816
+	     "reakpoint 3, breakpoint.*" "breakpoint (A) after the first fork"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 3.*New value = 4.*after-fork1-A.*" "watchpoint A after the first fork"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 4.*New value = 5.*after-fork1-B.*" "watchpoint B after the first fork"
d945816
+    gdb_test "continue" \
d945816
+	     "reakpoint 3, breakpoint.*" "breakpoint (A) after the second fork"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 5.*New value = 6.*after-fork2-A.*" "watchpoint A after the second fork"
d945816
+    gdb_test "continue" \
d945816
+	     "atchpoint 2: var.*Old value = 6.*New value = 7.*after-fork2-B.*" "watchpoint B after the second fork"
d945816
+    gdb_test "continue" "Continuing..*Program exited normally." "finish"
d945816
+
d945816
+
d945816
+    # cleanup
d945816
+
d945816
+    set pf_prefix $prefix_test
d945816
+}
d945816
+
d945816
+test parent FOLLOW_PARENT
d945816
+
d945816
+# Only GNU/Linux is known to support `set follow-fork-mode child'.
d945816
+if {[istarget "*-*-linux*"]} {
d945816
+    test child FOLLOW_CHILD
d945816
+}
81783d0
Index: gdb-6.8.50.20090209/gdb/doc/gdb.texinfo
d50521f
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/doc/gdb.texinfo	2009-02-09 16:02:35.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/doc/gdb.texinfo	2009-02-09 16:02:42.000000000 +0100
81783d0
@@ -3588,6 +3588,14 @@ confident that no other thread can becom
d50521f
 software watchpoints as usual.  However, @value{GDBN} may not notice
d50521f
 when a non-current thread's activity changes the expression.  (Hardware
d50521f
 watchpoints, in contrast, watch an expression in all threads.)
d50521f
+
25ff8a1
+Software watchpoints single-step the current thread to track the changes.
d50521f
+Other threads are left freely running on @code{continue}; therefore, their
d50521f
+changes cannot be caught.  To get more reliable software watchpoints, please
d50521f
+use @code{set scheduler-locking on}.  The default for Red Hat/Fedora
d50521f
+@value{GDBN} is @code{set scheduler-locking step}, which makes the software
d50521f
+watchpoints safe for the @code{step} command, but not for the @code{continue}
d50521f
+command.  @xref{Thread Stops}.
d50521f
 @end quotation
d50521f
 
d50521f
 @xref{set remote hardware-watchpoint-limit}.
81783d0
Index: gdb-6.8.50.20090209/gdb/config/i386/nm-linux.h
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/config/i386/nm-linux.h	2009-01-03 06:57:54.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/config/i386/nm-linux.h	2009-02-09 16:02:42.000000000 +0100
81783d0
@@ -46,6 +46,16 @@ extern void i386_linux_dr_reset_addr (in
25ff8a1
 extern unsigned long i386_linux_dr_get_status (void);
25ff8a1
 #define I386_DR_LOW_GET_STATUS() \
25ff8a1
   i386_linux_dr_get_status ()
25ff8a1
+
25ff8a1
+/* Remove a watchpoint that watched the memory region which starts at
25ff8a1
+ *    address ADDR, whose length is LEN bytes, and for accesses of the
25ff8a1
+ *       type TYPE.  Return 0 on success, -1 on failure.  */
25ff8a1
+extern int i386_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
25ff8a1
+
25ff8a1
+/* Override basic i386 macros for watchpoint and hardware breakpoint
25ff8a1
+   insertion/removal to support threads.  */
25ff8a1
+#define target_remove_watchpoint(addr, len, type) \
25ff8a1
+  i386_linux_remove_watchpoint (addr, len, type)
25ff8a1
 
25ff8a1
 
25ff8a1
 #ifdef HAVE_PTRACE_GETFPXREGS
81783d0
Index: gdb-6.8.50.20090209/gdb/config/i386/nm-linux64.h
25ff8a1
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/config/i386/nm-linux64.h	2009-01-03 06:57:54.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/config/i386/nm-linux64.h	2009-02-09 16:02:42.000000000 +0100
407ebe9
@@ -51,4 +51,14 @@ extern unsigned long amd64_linux_dr_get_
25ff8a1
 #define I386_DR_LOW_GET_STATUS() \
25ff8a1
   amd64_linux_dr_get_status ()
25ff8a1
 
25ff8a1
+/* Remove a watchpoint that watched the memory region which starts at
25ff8a1
+ *    address ADDR, whose length is LEN bytes, and for accesses of the
25ff8a1
+ *       type TYPE.  Return 0 on success, -1 on failure.  */
25ff8a1
+extern int amd64_linux_remove_watchpoint (CORE_ADDR addr, int len, int type);
25ff8a1
+
25ff8a1
+/* Override basic amd64 macros for watchpoint and hardware breakpoint
25ff8a1
+   insertion/removal to support threads.  */
25ff8a1
+#define target_remove_watchpoint(addr, len, type) \
25ff8a1
+  amd64_linux_remove_watchpoint (addr, len, type)
25ff8a1
+
25ff8a1
 #endif /* nm-linux64.h */
81783d0
Index: gdb-6.8.50.20090209/gdb/target.h
407ebe9
===================================================================
81783d0
--- gdb-6.8.50.20090209.orig/gdb/target.h	2009-02-09 15:49:25.000000000 +0100
81783d0
+++ gdb-6.8.50.20090209/gdb/target.h	2009-02-09 16:02:42.000000000 +0100
81783d0
@@ -1113,7 +1113,9 @@ extern char *normal_pid_to_str (ptid_t p
407ebe9
 #ifndef target_insert_watchpoint
407ebe9
 #define	target_insert_watchpoint(addr, len, type)	\
407ebe9
      (*current_target.to_insert_watchpoint) (addr, len, type)
407ebe9
+#endif
407ebe9
 
407ebe9
+#ifndef target_remove_watchpoint
407ebe9
 #define	target_remove_watchpoint(addr, len, type)	\
407ebe9
      (*current_target.to_remove_watchpoint) (addr, len, type)
407ebe9
 #endif