9a1b988
2007-10-14  Jan Kratochvil  <jan.kratochvil@redhat.com>
9a1b988
9a1b988
	Handle multiple different PIDs for the DR registers.
9a1b988
	* i386-nat.c: Include "inferior.h".
9a1b988
	(struct dr_mirror_status, dr_mirror_active, dr_mirror_fetch): New.
9a1b988
	(dr_mirror, dr_status_mirror, dr_control_mirror, dr_ref_count):
9a1b988
	Redefined using DR_MIRROR_ACTIVE.
9a1b988
	(i386_cleanup_dregs): Clear the DR_MIRROR_ACTIVE content instead.
9a1b988
	(i386_show_dr, i386_insert_aligned_watchpoint)
9a1b988
	(i386_remove_aligned_watchpoint, i386_stopped_data_address)
9a1b988
	(i386_stopped_by_hwbp): Call DR_MIRROR_FETCH.
9a1b988
	* Makefile.in (i386-nat.o): Update dependencies.
9a1b988
9a1b988
2007-10-14  Jan Kratochvil  <jan.kratochvil@redhat.com>
9a1b988
9a1b988
	* gdb.base/watchpoint-fork.exp, gdb.base/watchpoint-fork.c: New files.
9a1b988
9a1b988
[ Backported for GDB-6.6 (only removed the new file inclusion). ]
9a1b988
9a1b988
--- ./gdb/i386-nat.c	23 Aug 2007 18:08:34 -0000	1.16
9a1b988
+++ ./gdb/i386-nat.c	14 Oct 2007 15:00:31 -0000
9a1b988
@@ -165,11 +166,22 @@
9a1b988
 
9a1b988
 /* Mirror the inferior's DRi registers.  We keep the status and
9a1b988
    control registers separated because they don't hold addresses.  */
9a1b988
-static CORE_ADDR dr_mirror[DR_NADDR];
9a1b988
-static unsigned dr_status_mirror, dr_control_mirror;
9a1b988
+struct dr_mirror_status
9a1b988
+  {
9a1b988
+    /* Cyclic list.  */
9a1b988
+    struct dr_mirror_status *next;
9a1b988
+    long lwp;
9a1b988
+    CORE_ADDR addr[DR_NADDR];
9a1b988
+    unsigned status, control;
9a1b988
+    int ref_count[DR_NADDR];
9a1b988
+  };
9a1b988
+struct dr_mirror_status *dr_mirror_active;
9a1b988
+#define dr_mirror (dr_mirror_active->addr)
9a1b988
+#define dr_status_mirror (dr_mirror_active->status)
9a1b988
+#define dr_control_mirror (dr_mirror_active->control)
9a1b988
 
9a1b988
 /* Reference counts for each debug register.  */
9a1b988
-static int dr_ref_count[DR_NADDR];
9a1b988
+#define dr_ref_count (dr_mirror_active->ref_count)
9a1b988
 
9a1b988
 /* Whether or not to print the mirrored debug registers.  */
9a1b988
 static int maint_show_dr;
9a1b988
@@ -218,15 +230,19 @@ static int i386_handle_nonaligned_watchp
9a1b988
 void
9a1b988
 i386_cleanup_dregs (void)
9a1b988
 {
9a1b988
-  int i;
9a1b988
+  struct dr_mirror_status *first = dr_mirror_active;
9a1b988
 
9a1b988
-  ALL_DEBUG_REGISTERS(i)
9a1b988
+  if (first == NULL)
9a1b988
+    return;
9a1b988
+  do
9a1b988
     {
9a1b988
-      dr_mirror[i] = 0;
9a1b988
-      dr_ref_count[i] = 0;
9a1b988
+      struct dr_mirror_status *next = dr_mirror_active->next;
9a1b988
+
9a1b988
+      xfree (dr_mirror_active);
9a1b988
+      dr_mirror_active = next;
9a1b988
     }
9a1b988
-  dr_control_mirror = 0;
9a1b988
-  dr_status_mirror  = 0;
9a1b988
+  while (dr_mirror_active != first);
9a1b988
+  dr_mirror_active = NULL;
9a1b988
 }
9a1b988
 
9a1b988
 /* Reset all debug registers at each new startup to avoid missing
9a1b988
@@ -238,6 +254,40 @@ child_post_startup_inferior (ptid_t ptid
9a1b988
   i386_cleanup_dregs ();
9a1b988
 }
9a1b988
 
9a1b988
+static void
9a1b988
+dr_mirror_fetch (void)
9a1b988
+{
9a1b988
+  long lwp;
9a1b988
+  int i;
9a1b988
+
9a1b988
+  lwp = ptid_get_lwp (inferior_ptid);
9a1b988
+  if (lwp == 0)
9a1b988
+    lwp = ptid_get_pid (inferior_ptid);
9a1b988
+
9a1b988
+  if (dr_mirror_active == NULL)
9a1b988
+    {
9a1b988
+      dr_mirror_active = xzalloc (sizeof *dr_mirror_active);
9a1b988
+      dr_mirror_active->next = dr_mirror_active;
9a1b988
+    }
9a1b988
+  else
9a1b988
+    {
9a1b988
+      struct dr_mirror_status *first = dr_mirror_active;
9a1b988
+      do
9a1b988
+	{
9a1b988
+	  if (dr_mirror_active->lwp == lwp)
9a1b988
+	    return;
9a1b988
+	  dr_mirror_active = dr_mirror_active->next;
9a1b988
+	}
9a1b988
+      while (dr_mirror_active != first);
9a1b988
+      dr_mirror_active = xzalloc (sizeof *dr_mirror_active);
9a1b988
+      dr_mirror_active->next = first->next;
9a1b988
+      first->next = dr_mirror_active;
9a1b988
+    }
9a1b988
+  dr_mirror_active->lwp = lwp;
9a1b988
+
9a1b988
+  /* All the registers left 0.  */
9a1b988
+}
9a1b988
+
9a1b988
 /* Print the values of the mirrored debug registers.  This is called
9a1b988
    when maint_show_dr is non-zero.  To set that up, type "maint
9a1b988
    show-debug-regs" at GDB's prompt.  */
9a1b988
@@ -248,6 +298,8 @@ i386_show_dr (const char *func, CORE_ADD
9a1b988
 {
9a1b988
   int i;
9a1b988
 
9a1b988
+  dr_mirror_fetch ();
9a1b988
+
9a1b988
   puts_unfiltered (func);
9a1b988
   if (addr || len)
9a1b988
     printf_unfiltered (" (addr=%lx, len=%d, type=%s)",
9a1b988
@@ -337,6 +389,8 @@ i386_insert_aligned_watchpoint (CORE_ADD
9a1b988
 {
9a1b988
   int i;
9a1b988
 
9a1b988
+  dr_mirror_fetch ();
9a1b988
+
9a1b988
   /* First, look for an occupied debug register with the same address
9a1b988
      and the same RW and LEN definitions.  If we find one, we can
9a1b988
      reuse it for this watchpoint as well (and save a register).  */
9a1b988
@@ -397,6 +451,8 @@ i386_remove_aligned_watchpoint (CORE_ADD
9a1b988
 {
9a1b988
   int i, retval = -1;
9a1b988
 
9a1b988
+  dr_mirror_fetch ();
9a1b988
+
9a1b988
   ALL_DEBUG_REGISTERS(i)
9a1b988
     {
9a1b988
       if (!I386_DR_VACANT (i)
9a1b988
@@ -569,6 +625,8 @@ i386_stopped_data_address (CORE_ADDR *ad
9a1b988
   int i;
9a1b988
   int rc = 0;
9a1b988
 
9a1b988
+  dr_mirror_fetch ();
9a1b988
+
9a1b988
   dr_status_mirror = I386_DR_LOW_GET_STATUS ();
9a1b988
 
9a1b988
   ALL_DEBUG_REGISTERS(i)
9a1b988
@@ -610,6 +668,8 @@ i386_stopped_by_hwbp (void)
9a1b988
 {
9a1b988
   int i;
9a1b988
 
9a1b988
+  dr_mirror_fetch ();
9a1b988
+
9a1b988
   dr_status_mirror = I386_DR_LOW_GET_STATUS ();
9a1b988
   if (maint_show_dr)
9a1b988
     i386_show_dr ("stopped_by_hwbp", 0, 0, hw_execute);
9a1b988
--- /dev/null	1 Jan 1970 00:00:00 -0000
9a1b988
+++ ./gdb/testsuite/gdb.base/watchpoint-fork.c	14 Oct 2007 15:00:32 -0000
9a1b988
@@ -0,0 +1,73 @@
9a1b988
+/* Test case for forgotten hw-watchpoints after fork()-off of a process.
9a1b988
+
9a1b988
+   Copyright 2007
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>
9a1b988
+
9a1b988
+static volatile int var;
9a1b988
+
9a1b988
+static void breakpoint (void)
9a1b988
+{
9a1b988
+}
9a1b988
+
9a1b988
+static void forkoff (int nr)
9a1b988
+{
9a1b988
+  pid_t child, pid_got;
9a1b988
+  int exit_code = 42 + nr;
9a1b988
+  int status;
9a1b988
+
9a1b988
+  child = fork ();
9a1b988
+  switch (child)
9a1b988
+    {
9a1b988
+      case -1:
9a1b988
+	assert (0);
9a1b988
+      case 0:
9a1b988
+	printf ("child%d: %d\n", nr, (int) getpid ());
9a1b988
+	breakpoint ();
9a1b988
+        exit (exit_code);
9a1b988
+      default:
9a1b988
+	printf ("parent%d: %d\n", nr, (int) child);
9a1b988
+	pid_got = wait (&status);
9a1b988
+	assert (pid_got == child);
9a1b988
+	assert (WIFEXITED (status));
9a1b988
+	assert (WEXITSTATUS (status) == exit_code);
9a1b988
+    }
9a1b988
+}
9a1b988
+
9a1b988
+int main (void)
9a1b988
+{
9a1b988
+  setbuf (stdout, NULL);
9a1b988
+  printf ("main: %d\n", (int) getpid ());
9a1b988
+
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
+}
9a1b988
--- /dev/null	1 Jan 1970 00:00:00 -0000
9a1b988
+++ ./gdb/testsuite/gdb.base/watchpoint-fork.exp	14 Oct 2007 15:00:32 -0000
9a1b988
@@ -0,0 +1,46 @@
9a1b988
+# Copyright 2007 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
+
9a1b988
+if $tracelevel then {
9a1b988
+    strace $tracelevel
9a1b988
+}
9a1b988
+
9a1b988
+set prms_id 0
9a1b988
+set bug_id 0
9a1b988
+
9a1b988
+set testfile watchpoint-fork
9a1b988
+set srcfile ${testfile}.c
9a1b988
+set binfile ${objdir}/${subdir}/${testfile}
9a1b988
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
9a1b988
+    untested "Couldn't compile test program"
9a1b988
+    return -1
9a1b988
+}
9a1b988
+
9a1b988
+# Get things started.
9a1b988
+
9a1b988
+gdb_exit
9a1b988
+gdb_start
9a1b988
+gdb_reinitialize_dir $srcdir/$subdir
9a1b988
+gdb_load ${binfile}
9a1b988
+
9a1b988
+gdb_test "watch var" "atchpoint 1: var"
9a1b988
+# It is never hit but it should not be left over in the fork()ed-off child.
9a1b988
+gdb_breakpoint "breakpoint"
9a1b988
+gdb_run_cmd
9a1b988
+gdb_test "" \
9a1b988
+	 "atchpoint 1: var.*Old value = 0.*New value = 1.*" "watchpoint first hit"
9a1b988
+gdb_test "continue" \
9a1b988
+	 "atchpoint 1: var.*Old value = 1.*New value = 2.*" "watchpoint second hit"
9a1b988
+gdb_test "continue" "Continuing..*Program exited normally." "finish"