Blob Blame History Raw
ia64-linux-nat.c patch is missing here, port it either from RHEL-5 for 6.7.1 or
from the commented-out HEAD patch below.

s390x in RHEL-5 requires a patch but it is no longer required for
gdb-6.7.1-6.fc9 - the patch was not ported.

2007-10-14  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Handle multiple different PIDs for the DR registers.
	* i386-nat.c: Include "inferior.h".
	(struct dr_mirror_status, dr_mirror_active, dr_mirror_fetch): New.
	(dr_mirror, dr_status_mirror, dr_control_mirror, dr_ref_count):
	Redefined using DR_MIRROR_ACTIVE.
	(i386_cleanup_dregs): Clear the DR_MIRROR_ACTIVE content instead.
	(i386_show_dr, i386_insert_aligned_watchpoint)
	(i386_remove_aligned_watchpoint, i386_stopped_data_address)
	(i386_stopped_by_hwbp): Call DR_MIRROR_FETCH.
	* Makefile.in (i386-nat.o): Update dependencies.

2007-12-30  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.base/watchpoint-fork.exp, gdb.base/watchpoint-fork.c: New files.

[ Backported for GDB-6.6 (only removed the new file inclusion). ]

2007-09-16  Daniel Jacobowitz  <dan@codesourcery.com>
	    Jeff Johnston  <jjohnstn@redhat.com>

	* gdb.texinfo (Setting Watchpoints): Adjust warning text about
	multi-threaded watchpoints.

2007-12-15  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.texinfo (Setting Watchpoints): New paragraph on the software
	watchpoints safety wrt `set scheduler-locking'.

#--- ./gdb/ia64-linux-nat.c	13 Oct 2007 00:49:15 -0000	1.43
#+++ ./gdb/ia64-linux-nat.c	29 Dec 2007 23:52:05 -0000
#@@ -493,7 +493,49 @@ enable_watchpoints_in_psr (ptid_t ptid)
#     }
# }
# 
#-static long debug_registers[8];
#+struct dr_mirror_status
#+  {
#+    /* Cyclic list.  */
#+    struct dr_mirror_status *next;
#+    long lwp;
#+    long content[8];
#+  };
#+struct dr_mirror_status *dr_mirror_active;
#+#define debug_registers (dr_mirror_active->content)
#+
#+static void
#+dr_mirror_fetch (void)
#+{
#+  long lwp;
#+  int i;
#+
#+  lwp = ptid_get_lwp (inferior_ptid);
#+  if (lwp == 0)
#+    lwp = ptid_get_pid (inferior_ptid);
#+
#+  if (dr_mirror_active == NULL)
#+    {
#+      dr_mirror_active = xzalloc (sizeof *dr_mirror_active);
#+      dr_mirror_active->next = dr_mirror_active;
#+    }
#+  else
#+    {
#+      struct dr_mirror_status *first = dr_mirror_active;
#+      do
#+	{
#+	  if (dr_mirror_active->lwp == lwp)
#+	    return;
#+	  dr_mirror_active = dr_mirror_active->next;
#+	}
#+      while (dr_mirror_active != first);
#+      dr_mirror_active = xzalloc (sizeof *dr_mirror_active);
#+      dr_mirror_active->next = first->next;
#+      first->next = dr_mirror_active;
#+    }
#+  dr_mirror_active->lwp = lwp;
#+
#+  /* All the registers left 0.  */
#+}
# 
# static void
# store_debug_register (ptid_t ptid, int idx, long val)
#@@ -538,6 +580,8 @@ ia64_linux_insert_watchpoint (CORE_ADDR 
#   long dbr_addr, dbr_mask;
#   int max_watchpoints = 4;
# 
#+  dr_mirror_fetch ();
#+
#   if (len <= 0 || !is_power_of_2 (len))
#     return -1;
# 
#@@ -590,6 +634,8 @@ ia64_linux_remove_watchpoint (CORE_ADDR 
#   long dbr_addr, dbr_mask;
#   int max_watchpoints = 4;
# 
#+  dr_mirror_fetch ();
#+
#   if (len <= 0 || !is_power_of_2 (len))
#     return -1;
# 
#@@ -621,6 +667,8 @@ ia64_linux_new_thread (ptid_t ptid)
# {
#   int i, any;
# 
#+  dr_mirror_fetch ();
#+
#   any = 0;
#   for (i = 0; i < 8; i++)
#     {

--- ./gdb/i386-nat.c	23 Aug 2007 18:08:34 -0000	1.16
+++ ./gdb/i386-nat.c	14 Oct 2007 15:00:31 -0000
@@ -165,11 +166,22 @@
 
 /* Mirror the inferior's DRi registers.  We keep the status and
    control registers separated because they don't hold addresses.  */
-static CORE_ADDR dr_mirror[DR_NADDR];
-static unsigned dr_status_mirror, dr_control_mirror;
+struct dr_mirror_status
+  {
+    /* Cyclic list.  */
+    struct dr_mirror_status *next;
+    long lwp;
+    CORE_ADDR addr[DR_NADDR];
+    unsigned status, control;
+    int ref_count[DR_NADDR];
+  };
+struct dr_mirror_status *dr_mirror_active;
+#define dr_mirror (dr_mirror_active->addr)
+#define dr_status_mirror (dr_mirror_active->status)
+#define dr_control_mirror (dr_mirror_active->control)
 
 /* Reference counts for each debug register.  */
-static int dr_ref_count[DR_NADDR];
+#define dr_ref_count (dr_mirror_active->ref_count)
 
 /* Whether or not to print the mirrored debug registers.  */
 static int maint_show_dr;
@@ -218,15 +230,19 @@ static int i386_handle_nonaligned_watchp
 void
 i386_cleanup_dregs (void)
 {
-  int i;
+  struct dr_mirror_status *first = dr_mirror_active;
 
-  ALL_DEBUG_REGISTERS(i)
+  if (first == NULL)
+    return;
+  do
     {
-      dr_mirror[i] = 0;
-      dr_ref_count[i] = 0;
+      struct dr_mirror_status *next = dr_mirror_active->next;
+
+      xfree (dr_mirror_active);
+      dr_mirror_active = next;
     }
-  dr_control_mirror = 0;
-  dr_status_mirror  = 0;
+  while (dr_mirror_active != first);
+  dr_mirror_active = NULL;
 }
 
 /* Reset all debug registers at each new startup to avoid missing
@@ -238,6 +254,40 @@ child_post_startup_inferior (ptid_t ptid
   i386_cleanup_dregs ();
 }
 
+static void
+dr_mirror_fetch (void)
+{
+  long lwp;
+  int i;
+
+  lwp = ptid_get_lwp (inferior_ptid);
+  if (lwp == 0)
+    lwp = ptid_get_pid (inferior_ptid);
+
+  if (dr_mirror_active == NULL)
+    {
+      dr_mirror_active = xzalloc (sizeof *dr_mirror_active);
+      dr_mirror_active->next = dr_mirror_active;
+    }
+  else
+    {
+      struct dr_mirror_status *first = dr_mirror_active;
+      do
+	{
+	  if (dr_mirror_active->lwp == lwp)
+	    return;
+	  dr_mirror_active = dr_mirror_active->next;
+	}
+      while (dr_mirror_active != first);
+      dr_mirror_active = xzalloc (sizeof *dr_mirror_active);
+      dr_mirror_active->next = first->next;
+      first->next = dr_mirror_active;
+    }
+  dr_mirror_active->lwp = lwp;
+
+  /* All the registers left 0.  */
+}
+
 /* Print the values of the mirrored debug registers.  This is called
    when maint_show_dr is non-zero.  To set that up, type "maint
    show-debug-regs" at GDB's prompt.  */
@@ -248,6 +298,8 @@ i386_show_dr (const char *func, CORE_ADD
 {
   int i;
 
+  dr_mirror_fetch ();
+
   puts_unfiltered (func);
   if (addr || len)
     printf_unfiltered (" (addr=%lx, len=%d, type=%s)",
@@ -337,6 +389,8 @@ i386_insert_aligned_watchpoint (CORE_ADD
 {
   int i;
 
+  dr_mirror_fetch ();
+
   /* First, look for an occupied debug register with the same address
      and the same RW and LEN definitions.  If we find one, we can
      reuse it for this watchpoint as well (and save a register).  */
@@ -397,6 +451,8 @@ i386_remove_aligned_watchpoint (CORE_ADD
 {
   int i, retval = -1;
 
+  dr_mirror_fetch ();
+
   ALL_DEBUG_REGISTERS(i)
     {
       if (!I386_DR_VACANT (i)
@@ -569,6 +625,8 @@ i386_stopped_data_address (CORE_ADDR *ad
   int i;
   int rc = 0;
 
+  dr_mirror_fetch ();
+
   dr_status_mirror = I386_DR_LOW_GET_STATUS ();
 
   ALL_DEBUG_REGISTERS(i)
@@ -610,6 +668,8 @@ i386_stopped_by_hwbp (void)
 {
   int i;
 
+  dr_mirror_fetch ();
+
   dr_status_mirror = I386_DR_LOW_GET_STATUS ();
   if (maint_show_dr)
     i386_show_dr ("stopped_by_hwbp", 0, 0, hw_execute);
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.base/watchpoint-fork.c	14 Oct 2007 15:00:32 -0000
@@ -0,0 +1,73 @@
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
+
+   Copyright 2007
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static volatile int var;
+
+static void breakpoint (void)
+{
+}
+
+static void forkoff (int nr)
+{
+  pid_t child, pid_got;
+  int exit_code = 42 + nr;
+  int status;
+
+  child = fork ();
+  switch (child)
+    {
+      case -1:
+	assert (0);
+      case 0:
+	printf ("child%d: %d\n", nr, (int) getpid ());
+	breakpoint ();
+        exit (exit_code);
+      default:
+	printf ("parent%d: %d\n", nr, (int) child);
+	pid_got = wait (&status);
+	assert (pid_got == child);
+	assert (WIFEXITED (status));
+	assert (WEXITSTATUS (status) == exit_code);
+    }
+}
+
+int main (void)
+{
+  setbuf (stdout, NULL);
+  printf ("main: %d\n", (int) getpid ());
+
+  /* Hardware watchpoints got disarmed here.  */
+  forkoff (1);
+  /* This watchpoint got lost before.  */
+  var++;
+  /* A sanity check for double hardware watchpoints removal.  */
+  forkoff (2);
+  var++;
+
+  return 0;
+}
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ./gdb/testsuite/gdb.base/watchpoint-fork.exp	14 Oct 2007 15:00:32 -0000
@@ -0,0 +1,53 @@
+# Copyright 2007 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 $tracelevel then {
+    strace $tracelevel
+}
+
+set prms_id 0
+set bug_id 0
+
+set testfile watchpoint-fork
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+    untested "Couldn't compile test program"
+    return -1
+}
+
+# Get things started.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { ![runto_main] } then {
+    gdb_suppress_tests;
+}
+
+# Install the watchpoint only after getting into MAIN - workaround some PPC
+# problem.
+gdb_test "watch var" "atchpoint 2: var"
+
+# It is never hit but it should not be left over in the fork()ed-off child.
+gdb_breakpoint "breakpoint"
+
+gdb_test "continue" \
+	 "atchpoint 2: var.*Old value = 0.*New value = 1.*" "watchpoint first hit"
+gdb_test "continue" \
+	 "atchpoint 2: var.*Old value = 1.*New value = 2.*" "watchpoint second hit"
+gdb_test "continue" "Continuing..*Program exited normally." "finish"
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.434
retrieving revision 1.435
diff -u -r1.434 -r1.435
--- src/gdb/doc/gdb.texinfo	2007/09/28 11:09:55	1.434
+++ src/gdb/doc/gdb.texinfo	2007/10/01 00:17:58	1.435
@@ -3346,20 +3346,13 @@
 way of doing that would be to set a code breakpoint at the entry to the
 @code{main} function and when it breaks, set all the watchpoints.
 
-@quotation
 @cindex watchpoints and threads
 @cindex threads and watchpoints
-@emph{Warning:} In multi-thread programs, watchpoints have only limited
-usefulness.  With the current watchpoint implementation, @value{GDBN}
-can only watch the value of an expression @emph{in a single thread}.  If
-you are confident that the expression can only change due to the current
-thread's activity (and if you are also confident that no other thread
-can become current), then you can use watchpoints as usual.  However,
-@value{GDBN} may not notice when a non-current thread's activity changes
-the expression.
+In multi-threaded programs, watchpoints will detect changes to the
+watched expression from every thread.
 
-@c FIXME: this is almost identical to the previous paragraph.
-@emph{HP-UX Warning:} In multi-thread programs, software watchpoints
+@quotation
+@emph{Warning:} In multi-threaded programs, software watchpoints
 have only limited usefulness.  If @value{GDBN} creates a software
 watchpoint, it can only watch the value of an expression @emph{in a
 single thread}.  If you are confident that the expression can only

--- gdb-6.5/gdb/doc/gdb.texinfo-orig	2007-12-15 13:25:14.000000000 +0100
+++ gdb-6.5/gdb/doc/gdb.texinfo	2007-12-15 13:45:25.000000000 +0100
@@ -3261,6 +3261,14 @@
 software watchpoints as usual.  However, @value{GDBN} may not notice
 when a non-current thread's activity changes the expression.  (Hardware
 watchpoints, in contrast, watch an expression in all threads.)
+
+Software watchpoints single-step the current thread to track the changes.  
+Other threads are left freely running on @code{continue}; therefore, their
+changes cannot be caught.  To get more reliable software watchpoints, please
+use @code{set scheduler-locking on}.  The default for Red Hat/Fedora
+@value{GDBN} is @code{set scheduler-locking step}, which makes the software
+watchpoints safe for the @code{step} command, but not for the @code{continue}
+command.  @xref{Thread Stops}.
 @end quotation
 
 @xref{set remote hardware-watchpoint-limit}.