Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
  2013-05-30  2:44 ` [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
  2013-05-30  2:44 ` [PATCH 3/3] MIPS h/w watchpoint in GDBserver Yao Qi
@ 2013-05-30  2:44 ` Yao Qi
  2013-06-13  4:12   ` Yao Qi
  2013-05-30 12:29 ` [PATCH 0/3] mips hardware watchpoint support in gdbserver Maciej W. Rozycki
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-05-30  2:44 UTC (permalink / raw)
  To: gdb-patches

This patch moves the mips-linux hardware watchpoint registers manipulation to
common/mips-linux-watch.[c,h], so that GDBserver can make use of them to avoid
duplication.  Some external functions are moved and renamed with prefix
'mips_linux_watch_'.

gdb:

2013-05-30  Yao Qi  <yao@codesourcery.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
	(mips-linux-watch.o): New rule.
	* common/mips-linux-watch.c, common/mips-linux-watch.h: New.
	* config/mips/linux.mh (NAT_FILE): Add mips-linux-watch.o.
	* mips-linux-nat.c: Include mips-linux-watch.h.
	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
	to common/mips-linux-watch.h.
	(MAX_DEBUG_REGISTER): Likewise.
	(struct mips_watchpoint): Likewise.
	(get_irw_mask, get_reg_mask, get_num_valid, get_watchlo): Move to
	to common/mips-linux-watch.c and add name prefix 'mips_linux_watch_'.
	(set_watchlo, get_watchhi, set_watchhi, type_to_irw): Likewise.
	(populate_regs_from_watches): Likewise.
	(mips_linux_read_watch_registers):  Move to common/mips-linux-watch.c.
	(fill_mask, try_one_watch): Likewise.
	(mips_linux_can_use_hw_breakpoint): Caller update.
	(mips_linux_stopped_by_watchpoint): Likewise.
	(mips_linux_stopped_data_address): Likewise.
	(mips_linux_region_ok_for_hw_watchpoint): Likewise.
	(mips_linux_new_thread): Likewise.
	(mips_linux_insert_watchpoint): Likewise.
	(mips_linux_remove_watchpoint): Likewise.
---
 gdb/Makefile.in               |    6 +-
 gdb/common/mips-linux-watch.c |  358 ++++++++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h |   76 ++++++++
 gdb/config/mips/linux.mh      |    2 +-
 gdb/mips-linux-nat.c          |  386 ++++-------------------------------------
 5 files changed, 473 insertions(+), 355 deletions(-)
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a6336a2..5fc93e7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -783,7 +783,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 HFILES_NO_SRCDIR = \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-ptrace.h common/mips-linux-watch.h \
 proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
 ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -2009,6 +2009,10 @@ linux-btrace.o: ${srcdir}/common/linux-btrace.c
 	$(COMPILE) $(srcdir)/common/linux-btrace.c
 	$(POSTCOMPILE)
 
+mips-linux-watch.o: ${srcdir}/common/mips-linux-watch.c
+	$(COMPILE) $(srcdir)/common/mips-linux-watch.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
new file mode 100644
index 0000000..c42e6ef
--- /dev/null
+++ b/gdb/common/mips-linux-watch.c
@@ -0,0 +1,358 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#include <sys/ptrace.h>
+#include "mips-linux-watch.h"
+#include "gdb_assert.h"
+
+#ifdef GDBSERVER
+#define hw_write '2'
+#define hw_read '3'
+#define hw_access '4'
+#else
+#include "breakpoint.h"
+#endif
+
+/* Assuming usable watch registers REGS, return the num_valid.  */
+
+uint32_t
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.num_valid;
+    case pt_watch_style_mips64:
+      return regs->mips64.num_valid;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
+
+CORE_ADDR
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchlo[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchlo[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchlo VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      /*  The cast will never throw away bits as 64 bit addresses can
+	  never be used on a 32 bit kernel.  */
+      regs->mips32.watchlo[n] = (uint32_t)value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchlo[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchhi[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchhi[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchhi VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      regs->mips32.watchhi[n] = value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchhi[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Set any low order bits in MASK that are not set.  */
+
+static CORE_ADDR
+fill_mask (CORE_ADDR mask)
+{
+  CORE_ADDR f = 1;
+  while (f && f < mask)
+    {
+      mask |= f;
+      f <<= 1;
+    }
+  return mask;
+}
+
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
+
+static uint32_t
+get_reg_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
+
+int
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, unsigned irw)
+{
+  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
+  CORE_ADDR mask_bits, t_low;
+  uint16_t t_hi;
+  int i, free_watches;
+  struct pt_watch_regs regs_copy;
+
+  if (len <= 0)
+    return 0;
+
+  last_byte = addr + len - 1;
+  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
+  base_addr = addr & ~mask_bits;
+
+  /* Check to see if it is covered by current registers.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((unsigned) t_low & irw))
+	{
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
+	  if (addr >= t_low && last_byte <= (t_low + t_hi))
+	    return 1;
+	}
+    }
+  /* Try to find an empty register.  */
+  free_watches = 0;
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
+	{
+	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
+	    {
+	      /* It fits, we'll take it.  */
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i,
+					    mask_bits & ~IRW_MASK);
+	      return 1;
+	    }
+	  else
+	    {
+	      /* It doesn't fit, but has the proper IRW capabilities.  */
+	      free_watches++;
+	    }
+	}
+    }
+  if (free_watches > 1)
+    {
+      /* Try to split it across several registers.  */
+      regs_copy = *regs;
+      for (i = 0;
+	   i < mips_linux_watch_get_num_valid (&regs_copy);
+	   i++)
+	{
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
+	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
+	  if (t_low == 0 && irw == (t_hi & irw))
+	    {
+	      t_low = addr & ~(CORE_ADDR) t_hi;
+	      break_addr = t_low + t_hi + 1;
+	      if (break_addr >= addr + len)
+		segment_len = len;
+	      else
+		segment_len = break_addr - addr;
+	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
+	      if (break_addr >= addr + len)
+		{
+		  *regs = regs_copy;
+		  return 1;
+		}
+	      len = addr + len - break_addr;
+	      addr = break_addr;
+	    }
+	}
+    }
+  /* It didn't fit anywhere, we failed.  */
+  return 0;
+}
+
+/* Convert GDB's TYPE to an IRW mask.  */
+
+unsigned
+mips_linux_watch_type_to_irw (int type)
+{
+  switch (type)
+    {
+    case hw_write:
+      return W_MASK;
+    case hw_read:
+      return R_MASK;
+    case hw_access:
+      return (W_MASK | R_MASK);
+    default:
+      return 0;
+    }
+}
+
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
+
+void
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
+{
+  struct mips_watchpoint *w;
+  int i;
+
+  /* Clear them out.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
+    }
+
+  w = current_watches;
+  while (w)
+    {
+      unsigned irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
+      /* They must all fit, because we previously calculated that they
+	 would.  */
+      gdb_assert (i);
+      w = w->next;
+    }
+}
+
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
+
+int
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
+{
+  if (force || *watch_readback_valid == 0)
+    {
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
+	{
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      switch (watch_readback->style)
+	{
+	case pt_watch_style_mips32:
+	  if (watch_readback->mips32.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	case pt_watch_style_mips64:
+	  if (watch_readback->mips64.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	default:
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      /* Watch registers appear to be usable.  */
+      *watch_readback_valid = 1;
+    }
+  return (*watch_readback_valid == 1) ? 1 : 0;
+}
diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
new file mode 100644
index 0000000..5d4fa00
--- /dev/null
+++ b/gdb/common/mips-linux-watch.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#ifndef MIPS_LINUX_WATCH_H
+#define MIPS_LINUX_WATCH_H 1
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#endif
+
+#include <asm/ptrace.h>
+#include <stdint.h>
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
+#define MAX_DEBUG_REGISTER 8
+
+/* We keep list of all watchpoints we should install and calculate the
+   watch register values each time the list changes.  This allows for
+   easy sharing of watch registers for more than one watchpoint.  */
+
+struct mips_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
+  struct mips_watchpoint *next;
+};
+
+uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs,
+					int set);
+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs,
+					int set);
+void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs,
+				   int set, CORE_ADDR value);
+uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs,
+				       int n);
+void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+				   uint16_t value);
+int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				    CORE_ADDR addr, int len,
+				    unsigned irw);
+void mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				     struct pt_watch_regs *regs);
+unsigned mips_linux_watch_type_to_irw (int type);
+
+int mips_linux_read_watch_registers (long lwpid,
+				     struct pt_watch_regs *watch_readback,
+				     int *watch_readback_valid,
+				     int force);
+#endif
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index 2f8e5dd..a4f23e3 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
-	linux-procfs.o linux-ptrace.o
+	linux-procfs.o linux-ptrace.o mips-linux-watch.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
 LOADLIBES = -ldl $(RDYNAMIC)
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index d8b4d29..b782657 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -34,6 +34,7 @@
 
 #include <sgidefs.h>
 #include <sys/ptrace.h>
+#include "mips-linux-watch.h"
 #include <asm/ptrace.h>
 
 #include "features/mips-linux.c"
@@ -469,18 +470,6 @@ mips_linux_read_description (struct target_ops *ops)
 #  define PTRACE_SET_WATCH_REGS	0xd1
 #endif
 
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
-
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
-
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
-
-#define MAX_DEBUG_REGISTER 8
-
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
@@ -492,18 +481,6 @@ static int watch_readback_valid;
 
 static struct pt_watch_regs watch_readback;
 
-/* We keep list of all watchpoints we should install and calculate the
-   watch register values each time the list changes.  This allows for
-   easy sharing of watch registers for more than one watchpoint.  */
-
-struct mips_watchpoint
-{
-  CORE_ADDR addr;
-  int len;
-  int type;
-  struct mips_watchpoint *next;
-};
-
 static struct mips_watchpoint *current_watches;
 
 /*  The current set of watch register values for writing the
@@ -511,131 +488,6 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers, return the irw_mask.  */
-
-static uint32_t
-get_irw_mask (struct pt_watch_regs *regs, int set)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the reg_mask.  */
-
-static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int set)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & ~IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & ~IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the num_valid.  */
-
-static uint32_t
-get_num_valid (struct pt_watch_regs *regs)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.num_valid;
-    case pt_watch_style_mips64:
-      return regs->mips64.num_valid;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the watchlo.  */
-
-static CORE_ADDR
-get_watchlo (struct pt_watch_regs *regs, int set)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchlo[set];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchlo[set];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, set a watchlo value.  */
-
-static void
-set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      /*  The cast will never throw away bits as 64 bit addresses can
-	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[set] = (uint32_t)value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchlo[set] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the watchhi.  */
-
-static uint32_t
-get_watchhi (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchhi[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchhi[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, set a watchhi value.  */
-
-static void
-set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      regs->mips32.watchhi[n] = value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchhi[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
 static void
 mips_show_dr (const char *func, CORE_ADDR addr,
 	      int len, enum target_hw_bp_type type)
@@ -656,69 +508,11 @@ mips_show_dr (const char *func, CORE_ADDR addr,
   for (i = 0; i < MAX_DEBUG_REGISTER; i++)
     printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
 		       paddress (target_gdbarch (),
-				 get_watchlo (&watch_mirror, i)),
+				 mips_linux_watch_get_watchlo (&watch_mirror,
+							       i)),
 		       paddress (target_gdbarch (),
-				 get_watchhi (&watch_mirror, i)));
-}
-
-/* Return 1 if watch registers are usable.  Cached information is used
-   unless force is true.  */
-
-static int
-mips_linux_read_watch_registers (int force)
-{
-  int tid;
-
-  if (force || watch_readback_valid == 0)
-    {
-      tid = ptid_get_lwp (inferior_ptid);
-      if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
-	{
-	  watch_readback_valid = -1;
-	  return 0;
-	}
-      switch (watch_readback.style)
-	{
-	case pt_watch_style_mips32:
-	  if (watch_readback.mips32.num_valid == 0)
-	    {
-	      watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	case pt_watch_style_mips64:
-	  if (watch_readback.mips64.num_valid == 0)
-	    {
-	      watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	default:
-	  watch_readback_valid = -1;
-	  return 0;
-	}
-      /* Watch registers appear to be usable.  */
-      watch_readback_valid = 1;
-    }
-  return (watch_readback_valid == 1) ? 1 : 0;
-}
-
-/* Convert GDB's type to an IRW mask.  */
-
-static unsigned
-type_to_irw (int type)
-{
-  switch (type)
-    {
-    case hw_write:
-      return W_MASK;
-    case hw_read:
-      return R_MASK;
-    case hw_access:
-      return (W_MASK | R_MASK);
-    default:
-      return 0;
-    }
+				 mips_linux_watch_get_watchhi (&watch_mirror,
+							       i)));
 }
 
 /* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
@@ -730,7 +524,9 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
   int i;
   uint32_t wanted_mask, irw_mask;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
    switch (type)
@@ -748,9 +544,11 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
       return 0;
     }
  
-  for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
+  for (i = 0;
+       i < mips_linux_watch_get_num_valid (&watch_readback) && cnt;
+       i++)
     {
-      irw_mask = get_irw_mask (&watch_readback, i);
+      irw_mask = mips_linux_watch_get_irw_mask (&watch_readback, i);
       if ((irw_mask & wanted_mask) == wanted_mask)
 	cnt--;
     }
@@ -767,13 +565,15 @@ mips_linux_stopped_by_watchpoint (void)
   int n;
   int num_valid;
 
-  if (!mips_linux_read_watch_registers (1))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 1))
     return 0;
 
-  num_valid = get_num_valid (&watch_readback);
+  num_valid = mips_linux_watch_get_num_valid (&watch_readback);
 
   for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
-    if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
+    if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
       return 1;
 
   return 0;
@@ -791,106 +591,6 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in mask that are not set.  */
-
-static CORE_ADDR
-fill_mask (CORE_ADDR mask)
-{
-  CORE_ADDR f = 1;
-  while (f && f < mask)
-    {
-      mask |= f;
-      f <<= 1;
-    }
-  return mask;
-}
-
-/* Try to add a single watch to the specified registers.  Return 1 on
-   success, 0 on failure.  */
-
-static int
-try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
-	       int len, unsigned irw)
-{
-  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low, t_low_end;
-  uint16_t t_hi;
-  int i, free_watches;
-  struct pt_watch_regs regs_copy;
-
-  if (len <= 0)
-    return 0;
-
-  last_byte = addr + len - 1;
-  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
-  base_addr = addr & ~mask_bits;
-
-  /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < get_num_valid (regs); i++)
-    {
-      t_low = get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((unsigned)t_low & irw))
-	{
-	  t_hi = get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR)t_hi;
-	  if (addr >= t_low && last_byte <= (t_low + t_hi))
-	    return 1;
-	}
-    }
-  /* Try to find an empty register.  */
-  free_watches = 0;
-  for (i = 0; i < get_num_valid (regs); i++)
-    {
-      t_low = get_watchlo (regs, i);
-      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
-	{
-	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
-	    {
-	      /* It fits, we'll take it.  */
-	      set_watchlo (regs, i, base_addr | irw);
-	      set_watchhi (regs, i, mask_bits & ~IRW_MASK);
-	      return 1;
-	    }
-	  else
-	    {
-	      /* It doesn't fit, but has the proper IRW capabilities.  */
-	      free_watches++;
-	    }
-	}
-    }
-  if (free_watches > 1)
-    {
-      /* Try to split it across several registers.  */
-      regs_copy = *regs;
-      for (i = 0; i < get_num_valid (&regs_copy); i++)
-	{
-	  t_low = get_watchlo (&regs_copy, i);
-	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
-	  if (t_low == 0 && irw == (t_hi & irw))
-	    {
-	      t_low = addr & ~(CORE_ADDR)t_hi;
-	      break_addr = t_low + t_hi + 1;
-	      if (break_addr >= addr + len)
-		segment_len = len;
-	      else
-		segment_len = break_addr - addr;
-	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      set_watchlo (&regs_copy, i, (addr & ~mask_bits) | irw);
-	      set_watchhi (&regs_copy, i, mask_bits & ~IRW_MASK);
-	      if (break_addr >= addr + len)
-		{
-		  *regs = regs_copy;
-		  return 1;
-		}
-	      len = addr + len - break_addr;
-	      addr = break_addr;
-	    }
-	}
-    }
-  /* It didn't fit anywhere, we failed.  */
-  return 0;
-}
-
 /* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
    the specified region can be covered by the watch registers.  */
 
@@ -900,17 +600,18 @@ mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
   struct pt_watch_regs dummy_regs;
   int i;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
   dummy_regs = watch_readback;
   /* Clear them out.  */
-  for (i = 0; i < get_num_valid (&dummy_regs); i++)
-    set_watchlo (&dummy_regs, i, 0);
-  return try_one_watch (&dummy_regs, addr, len, 0);
+  for (i = 0; i < mips_linux_watch_get_num_valid (&dummy_regs); i++)
+    mips_linux_watch_set_watchlo (&dummy_regs, i, 0);
+  return mips_linux_watch_try_one_watch (&dummy_regs, addr, len, 0);
 }
 
-
 /* Write the mirrored watch register values for each thread.  */
 
 static int
@@ -936,7 +637,9 @@ mips_linux_new_thread (struct lwp_info *lp)
 {
   int tid;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return;
 
   tid = ptid_get_lwp (lp->ptid);
@@ -944,32 +647,6 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers with the currently cached watches.  */
-
-static void
-populate_regs_from_watches (struct pt_watch_regs *regs)
-{
-  struct mips_watchpoint *w;
-  int i;
-
-  /* Clear them out.  */
-  for (i = 0; i < get_num_valid (regs); i++)
-    {
-      set_watchlo (regs, i, 0);
-      set_watchhi (regs, i, 0);
-    }
-
-  w = current_watches;
-  while (w)
-    {
-      i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
-      /* They must all fit, because we previously calculated that they
-	 would.  */
-      gdb_assert (i);
-      w = w->next;
-    }
-}
-
 /* Target to_insert_watchpoint implementation.  Try to insert a new
    watch.  Return zero on success.  */
 
@@ -984,7 +661,9 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
   int i;
   int retval;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return -1;
 
   if (len <= 0)
@@ -992,10 +671,11 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
 
   regs = watch_readback;
   /* Add the current watches.  */
-  populate_regs_from_watches (&regs);
+  mips_linux_watch_populate_regs (current_watches, &regs);
 
   /* Now try to add the new watch.  */
-  if (!try_one_watch (&regs, addr, len, type_to_irw (type)))
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
+				       mips_linux_watch_type_to_irw (type)))
     return -1;
 
   /* It fit.  Stick it on the end of the list.  */
@@ -1057,7 +737,7 @@ mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
   gdb_assert (watch_readback_valid == 1);
 
   watch_mirror = watch_readback;
-  populate_regs_from_watches (&watch_mirror);
+  mips_linux_watch_populate_regs (current_watches, &watch_mirror);
 
   retval = write_watchpoint_regs ();
 
-- 
1.7.7.6


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

* [PATCH 0/3] mips hardware watchpoint support in gdbserver
@ 2013-05-30  2:44 Yao Qi
  2013-05-30  2:44 ` [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
                   ` (5 more replies)
  0 siblings, 6 replies; 52+ messages in thread
From: Yao Qi @ 2013-05-30  2:44 UTC (permalink / raw)
  To: gdb-patches

Hi,
This patch series is to post Jie and Dan's work to support mips hardware
watchpoint in gdbserver.  The patch exists in the codesourcery tree for a
while, when I rebase the patch for on top of FSF GDB trunk, I find
that kernel header structs are defined in gdb while they are not defined
in gdbserver because it includes asm/ptrace.h.  After some thought, it
should be safe to include asm/ptrace.h in gdb to get rid of these local
structs, so this is what patch 1/3 does.  It is a cleanup one.  See more
explanations in the patch itself.

Then, I find there are some duplications between gdb and gdbserver on
manipulating h/w watchpoints, so I merge the common part to
common/mips-linux-watch.[h,c].  gdb and gdbserver supports h/w watchpoints
for some targets, such as i386 and arm, but no one shares common code in
common/ directory before.  Ulrich Weigand expressed the intention for
sharing for arm h/w watchpoint support in gdbserver
<http://sourceware.org/ml/gdb-patches/2011-09/msg00200.html>
I am not sure upstream maintainers' opinion on this.  That is what
patch 2/3 does.

Finally, patch 3/3 is about the rest of gdbserver stuff for h/w watchpoint.

The patch series are tested on some mips boards with gdbserver, with a
hack that force proc skip_hw_watchpoint_tests return false.
Many fails are fixed and no regressions (note that there is a regression
in gdb.base/watchpoint.exp, but it is caused by a previous internal
error).  I also mange to run testsuite native mips gdb on a mips board,
watchpoint related tests seem OK.  The whole testsuite is not run because
of the very slow speed.  Is It OK?

*** BLURB HERE ***

Yao Qi (3):
  Include asm/ptrace.h in mips-linux-nat.c
  Move mips hardware watchpoint stuff to common/
  MIPS GDBserver watchpoint

 gdb/Makefile.in                |    6 +-
 gdb/common/mips-linux-watch.c  |  358 +++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h  |   76 +++++++
 gdb/config/mips/linux.mh       |    2 +-
 gdb/gdbserver/Makefile.in      |    5 +-
 gdb/gdbserver/configure.srv    |    2 +-
 gdb/gdbserver/linux-mips-low.c |  330 ++++++++++++++++++++++++++++++
 gdb/mips-linux-nat.c           |  431 +++------------------------------------
 8 files changed, 809 insertions(+), 401 deletions(-)
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

-- 
1.7.7.6


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

* [PATCH 3/3] MIPS h/w watchpoint in GDBserver
  2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
  2013-05-30  2:44 ` [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
@ 2013-05-30  2:44 ` Yao Qi
  2013-06-13  8:20   ` Yao Qi
  2013-05-30  2:44 ` [PATCH 2/3] Move mips hardware watchpoint stuff to common/ Yao Qi
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-05-30  2:44 UTC (permalink / raw)
  To: gdb-patches

Hi,
This patch adds the mips hardware watchpoint support in GDBserver.

gdb/gdbserver:

2013-05-30  Jie Zhang  <jie@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>
	    Yao Qi  <yao@codesourcery.com>

	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
	(mips-linux-watch.o): New rule.
	* configure.srv (srv_tgtobj): Add mips-linux-watch.o
	* linux-mips-low.c: Include mips-linux-watch.h.
	(struct arch_process_info, struct arch_lwp_info): New.
	(update_debug_registers_callback): New.
	(mips_linux_new_process, mips_linux_new_thread) New.
	(mips_linux_prepare_to_resume, mips_insert_point): New.
	(mips_remove_point, mips_stopped_by_watchpoint): New.
	(mips_stopped_data_address): New.
	(the_low_target): Add watchpoint support functions.
---
 gdb/gdbserver/Makefile.in      |    5 +-
 gdb/gdbserver/configure.srv    |    2 +-
 gdb/gdbserver/linux-mips-low.c |  341 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 346 insertions(+), 2 deletions(-)

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 9b1771f..f105e28 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -157,7 +157,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
 	$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
 	$(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \
-	$(srcdir)/common/filestuff.c
+	$(srcdir)/common/filestuff.c $(srcdir)/common/mips-linux-watch.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -553,6 +553,9 @@ agent.o: ../common/agent.c
 linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
 
+mips-linux-watch.o: ../common/mips-linux-watch.c ../common/mips-linux-watch.h $(server_h)
+	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+
 # We build vasprintf with -DHAVE_CONFIG_H because we want that unit to
 # include our config.h file.  Otherwise, some system headers do not get
 # included, and the compiler emits a warning about implicitly defined
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 9344b17..b024dd3 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -184,7 +184,7 @@ case "${target}" in
 			srv_regobj="${srv_regobj} mips64-linux.o"
 			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
 			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
-			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+			srv_tgtobj="${srv_tgtobj} linux-ptrace.o mips-linux-watch.o"
 			srv_xmlfiles="mips-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml"
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 0cf83be..1eb83eb 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -20,6 +20,7 @@
 #include "linux-low.h"
 
 #include <sys/ptrace.h>
+#include "mips-linux-watch.h"
 #include <endian.h>
 
 #include "gdb_proc_service.h"
@@ -145,6 +146,39 @@ mips_arch_setup (void)
   init_registers ();
 }
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  /* -1 if the kernel and/or CPU do not support watch registers.
+      1 if watch_readback is valid and we can read style, num_valid
+	and the masks.
+      0 if we need to read the watch_readback.  */
+
+  int watch_readback_valid;
+
+  /* Cached watch register read values.  */
+
+  struct pt_watch_regs watch_readback;
+
+  /* Current watchpoint requests for this process.  */
+
+  struct mips_watchpoint *current_watches;
+
+  /*  The current set of watch register values for writing the
+      registers.  */
+
+  struct pt_watch_regs watch_mirror;
+};
+
+/* 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;
+};
+
 /* From mips-linux-nat.c.  */
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
@@ -235,6 +269,303 @@ mips_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Mark the debug registers of lwp, represented by ENTRY, is changed,
+   if the lwp's process id is *PID_P.  */
+
+static int
+update_debug_registers_callback (struct inferior_list_entry *entry,
+				 void *pid_p)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  int pid = *(int *) pid_p;
+
+  /* Only update the threads of this process.  */
+  if (pid_of (lwp) == pid)
+    {
+      /* 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;
+}
+
+/* This is the implementation of linux_target_ops method
+   new_process.  */
+
+static struct arch_process_info *
+mips_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method new_thread.
+   Mark the debug registers are changed, so the threads' copies will
+   be updated.  */
+
+static struct arch_lwp_info *
+mips_linux_new_thread (void)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->debug_registers_changed = 1;
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method
+   prepare_to_resume.  If the debug regs have changed, update the
+   thread's copies.  */
+
+static void
+mips_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  ptid_t ptid = ptid_of (lwp);
+  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
+  struct arch_process_info *private = proc->private->arch_private;
+
+  if (lwp->arch_private->debug_registers_changed)
+    {
+      /* Only update the debug registers if we have set or unset a
+	 watchpoint already.  */
+      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
+	{
+	  /* Write the mirrored watch register values.  */
+	  int tid = ptid_get_lwp (ptid);
+
+	  if (ptrace (PTRACE_SET_WATCH_REGS, tid, &private->watch_mirror) == -1)
+	    perror_with_name ("Couldn't write debug register");
+	}
+
+      lwp->arch_private->debug_registers_changed = 0;
+    }
+}
+
+/* This is the implementation of linux_target_ops method
+   insert_point.  */
+
+static int
+mips_insert_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  struct pt_watch_regs regs;
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+  int pid;
+  long lwpid;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  lwpid = lwpid_of (get_thread_lwp (current_inferior));
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = private->watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (private->current_watches, &regs);
+
+  /* Now try to add the new watch.  */
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
+				       mips_linux_watch_type_to_irw (type)))
+    return -1;
+
+  /* It fit.  Stick it on the end of the list.  */
+  new_watch = (struct mips_watchpoint *)
+    xmalloc (sizeof (struct mips_watchpoint));
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = type;
+  new_watch->next = NULL;
+
+  pw = &private->current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+
+  private->watch_mirror = regs;
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_debug_registers_callback, &pid);
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   remove_point.  */
+
+static int
+mips_remove_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+
+  int deleted_one;
+  int pid;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  /* Search for a known watch that matches.  Then unlink and free
+     it.  */
+  deleted_one = 0;
+  pw = &private->current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == type)
+	{
+	  *pw = w->next;
+	  free (w);
+	  deleted_one = 1;
+	  break;
+	}
+      pw = &(w->next);
+    }
+
+  if (!deleted_one)
+    return -1;  /* We don't know about it, fail doing nothing.  */
+
+  /* At this point watch_readback is known to be valid because we
+     could not have added the watch without reading it.  */
+  gdb_assert (private->watch_readback_valid == 1);
+
+  private->watch_mirror = private->watch_readback;
+  mips_linux_watch_populate_regs (private->current_watches,
+				  &private->watch_mirror);
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_debug_registers_callback, &pid);
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_by_watchpoint.  The watchhi R and W bits indicate
+   the watch register triggered. */
+
+static int
+mips_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					1))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      return 1;
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_data_address.  */
+
+static CORE_ADDR
+mips_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  /* On mips we don't know the low order 3 bits of the data address.
+     GDB does not support remote targets that can't report the
+     watchpoint address.  So, make our best guess; return the starting
+     address of a watchpoint request which overlaps the one that
+     triggered.  */
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      {
+	CORE_ADDR t_low, t_hi;
+	int t_irw;
+	struct mips_watchpoint *watch;
+
+	t_low = mips_linux_watch_get_watchlo (&private->watch_readback, n);
+	t_irw = t_low & IRW_MASK;
+	t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+		| IRW_MASK);
+	t_low &= ~(CORE_ADDR)t_hi;
+
+	for (watch = private->current_watches;
+	     watch != NULL;
+	     watch = watch->next)
+	  {
+	    CORE_ADDR addr = watch->addr;
+	    CORE_ADDR last_byte = addr + watch->len - 1;
+	    if ((t_irw & mips_linux_watch_type_to_irw (watch->type))
+		== 0)
+	      /* Different type.  */
+	      continue;
+	    /* Check for overlap of even a single byte.  */
+	    if (last_byte >= t_low && addr <= t_low + t_hi)
+	      return addr;
+	  }
+      }
+
+  /* Shouldn't happen.  */
+  return 0;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -437,4 +768,14 @@ struct linux_target_ops the_low_target = {
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
+  mips_insert_point,
+  mips_remove_point,
+  mips_stopped_by_watchpoint,
+  mips_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, /* siginfo_fixup */
+  mips_linux_new_process,
+  mips_linux_new_thread,
+  mips_linux_prepare_to_resume
 };
-- 
1.7.7.6


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

* [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
@ 2013-05-30  2:44 ` Yao Qi
  2013-06-13 17:49   ` Maciej W. Rozycki
  2013-05-30  2:44 ` [PATCH 3/3] MIPS h/w watchpoint in GDBserver Yao Qi
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-05-30  2:44 UTC (permalink / raw)
  To: gdb-patches

Hi,
This patch is to include asm/ptrace.h in mips-linux-nat.c and remove
some duplicated structs already defined in asm/ptrace.h.

The ptrace support for hardware support was added into kernel in Sep.
2008 and the mips hardware watchpoint for native GDB was committed
on April 2009.  Considering the time order, GDB doesn't have to carry
these local definitions, and should include asm/ptrace.h instead.

gdb:

2013-05-30  Yao Qi  <yao@codesourcery.com>

	* mips-linux-nat.c: Include asm/ptrace.h.
	(enum pt_watch_style): Remove.
	(struct mips32_watch_regs): Remove.
	(struct mips64_watch_regs): Remove.
	(struct pt_watch_regs): Remove.
---
 gdb/mips-linux-nat.c |   45 +--------------------------------------------
 1 files changed, 1 insertions(+), 44 deletions(-)

diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index d323a82..d8b4d29 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -34,6 +34,7 @@
 
 #include <sgidefs.h>
 #include <sys/ptrace.h>
+#include <asm/ptrace.h>
 
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
@@ -478,52 +479,8 @@ mips_linux_read_description (struct target_ops *ops)
 
 #define IRW_MASK (I_MASK | R_MASK | W_MASK)
 
-enum pt_watch_style {
-  pt_watch_style_mips32,
-  pt_watch_style_mips64
-};
-
 #define MAX_DEBUG_REGISTER 8
 
-/* A value of zero in a watchlo indicates that it is available.  */
-
-struct mips32_watch_regs
-{
-  uint32_t watchlo[MAX_DEBUG_REGISTER];
-  /* Lower 16 bits of watchhi.  */
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  /* Valid mask and I R W bits.
-   * bit 0 -- 1 if W bit is usable.
-   * bit 1 -- 1 if R bit is usable.
-   * bit 2 -- 1 if I bit is usable.
-   * bits 3 - 11 -- Valid watchhi mask bits.
-   */
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  /* The number of valid watch register pairs.  */
-  uint32_t num_valid;
-  /* There is confusion across gcc versions about structure alignment,
-     so we force 8 byte alignment for these structures so they match
-     the kernel even if it was build with a different gcc version.  */
-} __attribute__ ((aligned (8)));
-
-struct mips64_watch_regs
-{
-  uint64_t watchlo[MAX_DEBUG_REGISTER];
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  uint32_t num_valid;
-} __attribute__ ((aligned (8)));
-
-struct pt_watch_regs
-{
-  enum pt_watch_style style;
-  union
-  {
-    struct mips32_watch_regs mips32;
-    struct mips64_watch_regs mips64;
-  };
-};
-
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
-- 
1.7.7.6


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

* Re: [PATCH 0/3] mips hardware watchpoint support in gdbserver
  2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
                   ` (2 preceding siblings ...)
  2013-05-30  2:44 ` [PATCH 2/3] Move mips hardware watchpoint stuff to common/ Yao Qi
@ 2013-05-30 12:29 ` Maciej W. Rozycki
  2013-05-30 18:06 ` Pedro Alves
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
  5 siblings, 0 replies; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-05-30 12:29 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

Yao,

> The patch series are tested on some mips boards with gdbserver, with a
> hack that force proc skip_hw_watchpoint_tests return false.
> Many fails are fixed and no regressions (note that there is a regression
> in gdb.base/watchpoint.exp, but it is caused by a previous internal
> error).  I also mange to run testsuite native mips gdb on a mips board,
> watchpoint related tests seem OK.  The whole testsuite is not run because
> of the very slow speed.  Is It OK?

 Thanks for this work, I'll have a look through it soon.  I'll see if I 
can run full native testing on a reasonably fast system next week (I'm not 
sure if the processor it has implements watch registers, hopefully it 
does).

  Maciej


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

* Re: [PATCH 0/3] mips hardware watchpoint support in gdbserver
  2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
                   ` (3 preceding siblings ...)
  2013-05-30 12:29 ` [PATCH 0/3] mips hardware watchpoint support in gdbserver Maciej W. Rozycki
@ 2013-05-30 18:06 ` Pedro Alves
  2013-05-30 18:08   ` Pedro Alves
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
  5 siblings, 1 reply; 52+ messages in thread
From: Pedro Alves @ 2013-05-30 18:06 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 05/30/2013 03:44 AM, Yao Qi wrote:
> Hi,
> This patch series is to post Jie and Dan's work to support mips hardware
> watchpoint in gdbserver.  The patch exists in the codesourcery tree for a
> while, when I rebase the patch for on top of FSF GDB trunk, I find
> that kernel header structs are defined in gdb while they are not defined
> in gdbserver because it includes asm/ptrace.h.  After some thought, it
> should be safe to include asm/ptrace.h in gdb to get rid of these local
> structs, so this is what patch 1/3 does.  It is a cleanup one.  See more
> explanations in the patch itself.
> 
> Then, I find there are some duplications between gdb and gdbserver on
> manipulating h/w watchpoints, so I merge the common part to
> common/mips-linux-watch.[h,c].  gdb and gdbserver supports h/w watchpoints
> for some targets, such as i386 and arm, but no one shares common code in
> common/ directory before.  Ulrich Weigand expressed the intention for
> sharing for arm h/w watchpoint support in gdbserver
> <http://sourceware.org/ml/gdb-patches/2011-09/msg00200.html>
> I am not sure upstream maintainers' opinion on this.  That is what
> patch 2/3 does.

I'd prefer we shared the whole target backend, but while that
doesn't happen, I'll take pieces.  :-)

> Finally, patch 3/3 is about the rest of gdbserver stuff for h/w watchpoint.
> 
> The patch series are tested on some mips boards with gdbserver, with a
> hack that force proc skip_hw_watchpoint_tests return false.
> Many fails are fixed and no regressions (note that there is a regression
> in gdb.base/watchpoint.exp, but it is caused by a previous internal
> error).  I also mange to run testsuite native mips gdb on a mips board,
> watchpoint related tests seem OK.  The whole testsuite is not run because
> of the very slow speed.  Is It OK?

I've skimmed the whole series, and it looked reasonable to me.
Specifically, it uses the modern update-registers-on-resume
watchpoint mechanisms in GDBserver, which is nice.

I'd be nice if mips_show_dr was shared too, and on GDBserver hooked
with the existing debug_hw_points / "monitor set debug-hw-points 1",
currently only used by x86.

I've noticed a couple unexplained odd placements for includes, like

>  #include <sgidefs.h>
>  #include <sys/ptrace.h>
> +#include "mips-linux-watch.h"
>  #include <asm/ptrace.h>

(there's another in GDBserver) and a couple formatting
violations (e.g., missing space after cast, spurious space in
ChangeLog).

Please consider the "generic" parts of the change approved.

I'll defer review/approval to Maciej.

-- 
Pedro Alves


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

* Re: [PATCH 0/3] mips hardware watchpoint support in gdbserver
  2013-05-30 18:06 ` Pedro Alves
@ 2013-05-30 18:08   ` Pedro Alves
  0 siblings, 0 replies; 52+ messages in thread
From: Pedro Alves @ 2013-05-30 18:08 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

Bonkers, I meant to say, but forgot.

The new hardware watchpoints support for MIPS GDBserver
should get a NEWS entry, under:

* New features in the GDB remote stub, GDBserver

IMO.

-- 
Pedro Alves


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-05-30  2:44 ` [PATCH 2/3] Move mips hardware watchpoint stuff to common/ Yao Qi
@ 2013-06-13  4:12   ` Yao Qi
  2013-06-19 22:05     ` Maciej W. Rozycki
  0 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-13  4:12 UTC (permalink / raw)
  To: gdb-patches

On 05/30/2013 10:44 AM, Yao Qi wrote:
> 2013-05-30  Yao Qi<yao@codesourcery.com>
> 
> 	* Makefile.in (HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
> 	(mips-linux-watch.o): New rule.
> 	* common/mips-linux-watch.c, common/mips-linux-watch.h: New.
> 	* config/mips/linux.mh (NAT_FILE): Add mips-linux-watch.o.
> 	* mips-linux-nat.c: Include mips-linux-watch.h.
> 	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
> 	to common/mips-linux-watch.h.
> 	(MAX_DEBUG_REGISTER): Likewise.
> 	(struct mips_watchpoint): Likewise.
> 	(get_irw_mask, get_reg_mask, get_num_valid, get_watchlo): Move to
> 	to common/mips-linux-watch.c and add name prefix 'mips_linux_watch_'.
> 	(set_watchlo, get_watchhi, set_watchhi, type_to_irw): Likewise.
> 	(populate_regs_from_watches): Likewise.
> 	(mips_linux_read_watch_registers):  Move to common/mips-linux-watch.c.
                                          ^^ One redundant space.

> +
> +/* Set any low order bits in MASK that are not set.  */
> +
> +static CORE_ADDR
> +fill_mask (CORE_ADDR mask)
> +{
> +  CORE_ADDR f = 1;

Add a blank line here.

> +  while (f && f < mask)
> +    {
> +      mask |= f;
> +      f <<= 1;
> +    }
> +  return mask;
> +}
> +

> diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
> index d8b4d29..b782657 100644
> --- a/gdb/mips-linux-nat.c
> +++ b/gdb/mips-linux-nat.c
> @@ -34,6 +34,7 @@
>  
>  #include <sgidefs.h>
>  #include <sys/ptrace.h>
> +#include "mips-linux-watch.h"
>  #include <asm/ptrace.h>

Remove the include to asm/ptrace.h, as it has been included in
mips-linux-watch.h.

-- 
Yao (齐尧)

gdb:

2013-06-13  Yao Qi  <yao@codesourcery.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
	(mips-linux-watch.o): New rule.
	* common/mips-linux-watch.c, common/mips-linux-watch.h: New.
	* config/mips/linux.mh (NAT_FILE): Add mips-linux-watch.o.
	* mips-linux-nat.c: Include mips-linux-watch.h.
	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
	to common/mips-linux-watch.h.
	(MAX_DEBUG_REGISTER): Likewise.
	(struct mips_watchpoint): Likewise.
	(get_irw_mask, get_reg_mask, get_num_valid, get_watchlo): Move to
	to common/mips-linux-watch.c and add name prefix 'mips_linux_watch_'.
	(set_watchlo, get_watchhi, set_watchhi, type_to_irw): Likewise.
	(populate_regs_from_watches): Likewise.
	(mips_linux_read_watch_registers): Move to common/mips-linux-watch.c.
	(fill_mask, try_one_watch): Likewise.
	(mips_linux_can_use_hw_breakpoint): Caller update.
	(mips_linux_stopped_by_watchpoint): Likewise.
	(mips_linux_stopped_data_address): Likewise.
	(mips_linux_region_ok_for_hw_watchpoint): Likewise.
	(mips_linux_new_thread): Likewise.
	(mips_linux_insert_watchpoint): Likewise.
	(mips_linux_remove_watchpoint): Likewise.
---
 gdb/Makefile.in               |    6 +-
 gdb/common/mips-linux-watch.c |  359 ++++++++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h |   76 ++++++++
 gdb/config/mips/linux.mh      |    2 +-
 gdb/mips-linux-nat.c          |  387 ++++-------------------------------------
 5 files changed, 474 insertions(+), 356 deletions(-)
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a6336a2..5fc93e7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -783,7 +783,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 HFILES_NO_SRCDIR = \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-ptrace.h common/mips-linux-watch.h \
 proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
 ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -2009,6 +2009,10 @@ linux-btrace.o: ${srcdir}/common/linux-btrace.c
 	$(COMPILE) $(srcdir)/common/linux-btrace.c
 	$(POSTCOMPILE)
 
+mips-linux-watch.o: ${srcdir}/common/mips-linux-watch.c
+	$(COMPILE) $(srcdir)/common/mips-linux-watch.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
new file mode 100644
index 0000000..eeac2f8
--- /dev/null
+++ b/gdb/common/mips-linux-watch.c
@@ -0,0 +1,359 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#include <sys/ptrace.h>
+#include "mips-linux-watch.h"
+#include "gdb_assert.h"
+
+#ifdef GDBSERVER
+#define hw_write '2'
+#define hw_read '3'
+#define hw_access '4'
+#else
+#include "breakpoint.h"
+#endif
+
+/* Assuming usable watch registers REGS, return the num_valid.  */
+
+uint32_t
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.num_valid;
+    case pt_watch_style_mips64:
+      return regs->mips64.num_valid;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
+
+CORE_ADDR
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchlo[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchlo[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchlo VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      /*  The cast will never throw away bits as 64 bit addresses can
+	  never be used on a 32 bit kernel.  */
+      regs->mips32.watchlo[n] = (uint32_t)value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchlo[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchhi[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchhi[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchhi VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      regs->mips32.watchhi[n] = value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchhi[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Set any low order bits in MASK that are not set.  */
+
+static CORE_ADDR
+fill_mask (CORE_ADDR mask)
+{
+  CORE_ADDR f = 1;
+
+  while (f && f < mask)
+    {
+      mask |= f;
+      f <<= 1;
+    }
+  return mask;
+}
+
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
+
+static uint32_t
+get_reg_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
+
+int
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, unsigned irw)
+{
+  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
+  CORE_ADDR mask_bits, t_low;
+  uint16_t t_hi;
+  int i, free_watches;
+  struct pt_watch_regs regs_copy;
+
+  if (len <= 0)
+    return 0;
+
+  last_byte = addr + len - 1;
+  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
+  base_addr = addr & ~mask_bits;
+
+  /* Check to see if it is covered by current registers.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((unsigned) t_low & irw))
+	{
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
+	  if (addr >= t_low && last_byte <= (t_low + t_hi))
+	    return 1;
+	}
+    }
+  /* Try to find an empty register.  */
+  free_watches = 0;
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
+	{
+	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
+	    {
+	      /* It fits, we'll take it.  */
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i,
+					    mask_bits & ~IRW_MASK);
+	      return 1;
+	    }
+	  else
+	    {
+	      /* It doesn't fit, but has the proper IRW capabilities.  */
+	      free_watches++;
+	    }
+	}
+    }
+  if (free_watches > 1)
+    {
+      /* Try to split it across several registers.  */
+      regs_copy = *regs;
+      for (i = 0;
+	   i < mips_linux_watch_get_num_valid (&regs_copy);
+	   i++)
+	{
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
+	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
+	  if (t_low == 0 && irw == (t_hi & irw))
+	    {
+	      t_low = addr & ~(CORE_ADDR) t_hi;
+	      break_addr = t_low + t_hi + 1;
+	      if (break_addr >= addr + len)
+		segment_len = len;
+	      else
+		segment_len = break_addr - addr;
+	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
+	      if (break_addr >= addr + len)
+		{
+		  *regs = regs_copy;
+		  return 1;
+		}
+	      len = addr + len - break_addr;
+	      addr = break_addr;
+	    }
+	}
+    }
+  /* It didn't fit anywhere, we failed.  */
+  return 0;
+}
+
+/* Convert GDB's TYPE to an IRW mask.  */
+
+unsigned
+mips_linux_watch_type_to_irw (int type)
+{
+  switch (type)
+    {
+    case hw_write:
+      return W_MASK;
+    case hw_read:
+      return R_MASK;
+    case hw_access:
+      return (W_MASK | R_MASK);
+    default:
+      return 0;
+    }
+}
+
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
+
+void
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
+{
+  struct mips_watchpoint *w;
+  int i;
+
+  /* Clear them out.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
+    }
+
+  w = current_watches;
+  while (w)
+    {
+      unsigned irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
+      /* They must all fit, because we previously calculated that they
+	 would.  */
+      gdb_assert (i);
+      w = w->next;
+    }
+}
+
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
+
+int
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
+{
+  if (force || *watch_readback_valid == 0)
+    {
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
+	{
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      switch (watch_readback->style)
+	{
+	case pt_watch_style_mips32:
+	  if (watch_readback->mips32.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	case pt_watch_style_mips64:
+	  if (watch_readback->mips64.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	default:
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      /* Watch registers appear to be usable.  */
+      *watch_readback_valid = 1;
+    }
+  return (*watch_readback_valid == 1) ? 1 : 0;
+}
diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
new file mode 100644
index 0000000..5d4fa00
--- /dev/null
+++ b/gdb/common/mips-linux-watch.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#ifndef MIPS_LINUX_WATCH_H
+#define MIPS_LINUX_WATCH_H 1
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#endif
+
+#include <asm/ptrace.h>
+#include <stdint.h>
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
+#define MAX_DEBUG_REGISTER 8
+
+/* We keep list of all watchpoints we should install and calculate the
+   watch register values each time the list changes.  This allows for
+   easy sharing of watch registers for more than one watchpoint.  */
+
+struct mips_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
+  struct mips_watchpoint *next;
+};
+
+uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs,
+					int set);
+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs,
+					int set);
+void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs,
+				   int set, CORE_ADDR value);
+uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs,
+				       int n);
+void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+				   uint16_t value);
+int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				    CORE_ADDR addr, int len,
+				    unsigned irw);
+void mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				     struct pt_watch_regs *regs);
+unsigned mips_linux_watch_type_to_irw (int type);
+
+int mips_linux_read_watch_registers (long lwpid,
+				     struct pt_watch_regs *watch_readback,
+				     int *watch_readback_valid,
+				     int force);
+#endif
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index 2f8e5dd..a4f23e3 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
-	linux-procfs.o linux-ptrace.o
+	linux-procfs.o linux-ptrace.o mips-linux-watch.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
 LOADLIBES = -ldl $(RDYNAMIC)
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index d8b4d29..8861dc8 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -34,7 +34,7 @@
 
 #include <sgidefs.h>
 #include <sys/ptrace.h>
-#include <asm/ptrace.h>
+#include "mips-linux-watch.h"
 
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
@@ -469,18 +469,6 @@ mips_linux_read_description (struct target_ops *ops)
 #  define PTRACE_SET_WATCH_REGS	0xd1
 #endif
 
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
-
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
-
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
-
-#define MAX_DEBUG_REGISTER 8
-
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
@@ -492,18 +480,6 @@ static int watch_readback_valid;
 
 static struct pt_watch_regs watch_readback;
 
-/* We keep list of all watchpoints we should install and calculate the
-   watch register values each time the list changes.  This allows for
-   easy sharing of watch registers for more than one watchpoint.  */
-
-struct mips_watchpoint
-{
-  CORE_ADDR addr;
-  int len;
-  int type;
-  struct mips_watchpoint *next;
-};
-
 static struct mips_watchpoint *current_watches;
 
 /*  The current set of watch register values for writing the
@@ -511,131 +487,6 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers, return the irw_mask.  */
-
-static uint32_t
-get_irw_mask (struct pt_watch_regs *regs, int set)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the reg_mask.  */
-
-static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int set)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & ~IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & ~IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the num_valid.  */
-
-static uint32_t
-get_num_valid (struct pt_watch_regs *regs)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.num_valid;
-    case pt_watch_style_mips64:
-      return regs->mips64.num_valid;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the watchlo.  */
-
-static CORE_ADDR
-get_watchlo (struct pt_watch_regs *regs, int set)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchlo[set];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchlo[set];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, set a watchlo value.  */
-
-static void
-set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      /*  The cast will never throw away bits as 64 bit addresses can
-	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[set] = (uint32_t)value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchlo[set] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, return the watchhi.  */
-
-static uint32_t
-get_watchhi (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchhi[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchhi[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers, set a watchhi value.  */
-
-static void
-set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      regs->mips32.watchhi[n] = value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchhi[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
 static void
 mips_show_dr (const char *func, CORE_ADDR addr,
 	      int len, enum target_hw_bp_type type)
@@ -656,69 +507,11 @@ mips_show_dr (const char *func, CORE_ADDR addr,
   for (i = 0; i < MAX_DEBUG_REGISTER; i++)
     printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
 		       paddress (target_gdbarch (),
-				 get_watchlo (&watch_mirror, i)),
+				 mips_linux_watch_get_watchlo (&watch_mirror,
+							       i)),
 		       paddress (target_gdbarch (),
-				 get_watchhi (&watch_mirror, i)));
-}
-
-/* Return 1 if watch registers are usable.  Cached information is used
-   unless force is true.  */
-
-static int
-mips_linux_read_watch_registers (int force)
-{
-  int tid;
-
-  if (force || watch_readback_valid == 0)
-    {
-      tid = ptid_get_lwp (inferior_ptid);
-      if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
-	{
-	  watch_readback_valid = -1;
-	  return 0;
-	}
-      switch (watch_readback.style)
-	{
-	case pt_watch_style_mips32:
-	  if (watch_readback.mips32.num_valid == 0)
-	    {
-	      watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	case pt_watch_style_mips64:
-	  if (watch_readback.mips64.num_valid == 0)
-	    {
-	      watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	default:
-	  watch_readback_valid = -1;
-	  return 0;
-	}
-      /* Watch registers appear to be usable.  */
-      watch_readback_valid = 1;
-    }
-  return (watch_readback_valid == 1) ? 1 : 0;
-}
-
-/* Convert GDB's type to an IRW mask.  */
-
-static unsigned
-type_to_irw (int type)
-{
-  switch (type)
-    {
-    case hw_write:
-      return W_MASK;
-    case hw_read:
-      return R_MASK;
-    case hw_access:
-      return (W_MASK | R_MASK);
-    default:
-      return 0;
-    }
+				 mips_linux_watch_get_watchhi (&watch_mirror,
+							       i)));
 }
 
 /* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
@@ -730,7 +523,9 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
   int i;
   uint32_t wanted_mask, irw_mask;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
    switch (type)
@@ -748,9 +543,11 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
       return 0;
     }
  
-  for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
+  for (i = 0;
+       i < mips_linux_watch_get_num_valid (&watch_readback) && cnt;
+       i++)
     {
-      irw_mask = get_irw_mask (&watch_readback, i);
+      irw_mask = mips_linux_watch_get_irw_mask (&watch_readback, i);
       if ((irw_mask & wanted_mask) == wanted_mask)
 	cnt--;
     }
@@ -767,13 +564,15 @@ mips_linux_stopped_by_watchpoint (void)
   int n;
   int num_valid;
 
-  if (!mips_linux_read_watch_registers (1))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 1))
     return 0;
 
-  num_valid = get_num_valid (&watch_readback);
+  num_valid = mips_linux_watch_get_num_valid (&watch_readback);
 
   for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
-    if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
+    if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
       return 1;
 
   return 0;
@@ -791,106 +590,6 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in mask that are not set.  */
-
-static CORE_ADDR
-fill_mask (CORE_ADDR mask)
-{
-  CORE_ADDR f = 1;
-  while (f && f < mask)
-    {
-      mask |= f;
-      f <<= 1;
-    }
-  return mask;
-}
-
-/* Try to add a single watch to the specified registers.  Return 1 on
-   success, 0 on failure.  */
-
-static int
-try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
-	       int len, unsigned irw)
-{
-  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low, t_low_end;
-  uint16_t t_hi;
-  int i, free_watches;
-  struct pt_watch_regs regs_copy;
-
-  if (len <= 0)
-    return 0;
-
-  last_byte = addr + len - 1;
-  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
-  base_addr = addr & ~mask_bits;
-
-  /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < get_num_valid (regs); i++)
-    {
-      t_low = get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((unsigned)t_low & irw))
-	{
-	  t_hi = get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR)t_hi;
-	  if (addr >= t_low && last_byte <= (t_low + t_hi))
-	    return 1;
-	}
-    }
-  /* Try to find an empty register.  */
-  free_watches = 0;
-  for (i = 0; i < get_num_valid (regs); i++)
-    {
-      t_low = get_watchlo (regs, i);
-      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
-	{
-	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
-	    {
-	      /* It fits, we'll take it.  */
-	      set_watchlo (regs, i, base_addr | irw);
-	      set_watchhi (regs, i, mask_bits & ~IRW_MASK);
-	      return 1;
-	    }
-	  else
-	    {
-	      /* It doesn't fit, but has the proper IRW capabilities.  */
-	      free_watches++;
-	    }
-	}
-    }
-  if (free_watches > 1)
-    {
-      /* Try to split it across several registers.  */
-      regs_copy = *regs;
-      for (i = 0; i < get_num_valid (&regs_copy); i++)
-	{
-	  t_low = get_watchlo (&regs_copy, i);
-	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
-	  if (t_low == 0 && irw == (t_hi & irw))
-	    {
-	      t_low = addr & ~(CORE_ADDR)t_hi;
-	      break_addr = t_low + t_hi + 1;
-	      if (break_addr >= addr + len)
-		segment_len = len;
-	      else
-		segment_len = break_addr - addr;
-	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      set_watchlo (&regs_copy, i, (addr & ~mask_bits) | irw);
-	      set_watchhi (&regs_copy, i, mask_bits & ~IRW_MASK);
-	      if (break_addr >= addr + len)
-		{
-		  *regs = regs_copy;
-		  return 1;
-		}
-	      len = addr + len - break_addr;
-	      addr = break_addr;
-	    }
-	}
-    }
-  /* It didn't fit anywhere, we failed.  */
-  return 0;
-}
-
 /* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
    the specified region can be covered by the watch registers.  */
 
@@ -900,17 +599,18 @@ mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
   struct pt_watch_regs dummy_regs;
   int i;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
   dummy_regs = watch_readback;
   /* Clear them out.  */
-  for (i = 0; i < get_num_valid (&dummy_regs); i++)
-    set_watchlo (&dummy_regs, i, 0);
-  return try_one_watch (&dummy_regs, addr, len, 0);
+  for (i = 0; i < mips_linux_watch_get_num_valid (&dummy_regs); i++)
+    mips_linux_watch_set_watchlo (&dummy_regs, i, 0);
+  return mips_linux_watch_try_one_watch (&dummy_regs, addr, len, 0);
 }
 
-
 /* Write the mirrored watch register values for each thread.  */
 
 static int
@@ -936,7 +636,9 @@ mips_linux_new_thread (struct lwp_info *lp)
 {
   int tid;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return;
 
   tid = ptid_get_lwp (lp->ptid);
@@ -944,32 +646,6 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers with the currently cached watches.  */
-
-static void
-populate_regs_from_watches (struct pt_watch_regs *regs)
-{
-  struct mips_watchpoint *w;
-  int i;
-
-  /* Clear them out.  */
-  for (i = 0; i < get_num_valid (regs); i++)
-    {
-      set_watchlo (regs, i, 0);
-      set_watchhi (regs, i, 0);
-    }
-
-  w = current_watches;
-  while (w)
-    {
-      i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
-      /* They must all fit, because we previously calculated that they
-	 would.  */
-      gdb_assert (i);
-      w = w->next;
-    }
-}
-
 /* Target to_insert_watchpoint implementation.  Try to insert a new
    watch.  Return zero on success.  */
 
@@ -984,7 +660,9 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
   int i;
   int retval;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return -1;
 
   if (len <= 0)
@@ -992,10 +670,11 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
 
   regs = watch_readback;
   /* Add the current watches.  */
-  populate_regs_from_watches (&regs);
+  mips_linux_watch_populate_regs (current_watches, &regs);
 
   /* Now try to add the new watch.  */
-  if (!try_one_watch (&regs, addr, len, type_to_irw (type)))
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
+				       mips_linux_watch_type_to_irw (type)))
     return -1;
 
   /* It fit.  Stick it on the end of the list.  */
@@ -1057,7 +736,7 @@ mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
   gdb_assert (watch_readback_valid == 1);
 
   watch_mirror = watch_readback;
-  populate_regs_from_watches (&watch_mirror);
+  mips_linux_watch_populate_regs (current_watches, &watch_mirror);
 
   retval = write_watchpoint_regs ();
 
-- 
1.7.7.6


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

* Re: [PATCH 3/3] MIPS h/w watchpoint in GDBserver
  2013-05-30  2:44 ` [PATCH 3/3] MIPS h/w watchpoint in GDBserver Yao Qi
@ 2013-06-13  8:20   ` Yao Qi
  2013-06-13 13:09     ` Eli Zaretskii
                       ` (2 more replies)
  0 siblings, 3 replies; 52+ messages in thread
From: Yao Qi @ 2013-06-13  8:20 UTC (permalink / raw)
  To: gdb-patches

On 05/30/2013 10:44 AM, Yao Qi wrote:
> @@ -20,6 +20,7 @@
>   #include "linux-low.h"
>   
>   #include <sys/ptrace.h>
> +#include "mips-linux-watch.h"
>   #include <endian.h>
>   
>   #include "gdb_proc_service.h"

Pedro mentioned that there are "unexplained odd placements for
includes", however, the only 'oddity' I can see is the order of include
mips-linux-watch.h and endian.h.  In this version, I exchange the order
of them.  I also add a news entry for it.

-- 
Yao (齐尧)

gdb/gdbserver:

2013-06-13  Jie Zhang  <jie@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>
	    Yao Qi  <yao@codesourcery.com>

	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
	(mips-linux-watch.o): New rule.
	* configure.srv (srv_tgtobj): Add mips-linux-watch.o
	* linux-mips-low.c: Include mips-linux-watch.h.
	(struct arch_process_info, struct arch_lwp_info): New.
	(update_debug_registers_callback): New.
	(mips_linux_new_process, mips_linux_new_thread) New.
	(mips_linux_prepare_to_resume, mips_insert_point): New.
	(mips_remove_point, mips_stopped_by_watchpoint): New.
	(mips_stopped_data_address): New.
	(the_low_target): Add watchpoint support functions.

gdb:

2013-06-13  Yao Qi  <yao@codesourcery.com>

	* NEWS: Mention it.
---
 gdb/NEWS                       |    2 +
 gdb/gdbserver/Makefile.in      |    5 +-
 gdb/gdbserver/configure.srv    |    2 +-
 gdb/gdbserver/linux-mips-low.c |  341 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 348 insertions(+), 2 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index eea9917..d56e18a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -108,6 +108,8 @@ qXfer:libraries-svr4:read's annex
   ** GDBserver now supports target-assisted range stepping.  Currently
      enabled on x86/x86_64 GNU/Linux targets.
 
+  ** GDBserver now supports hardware watchpoint on mips GNU/Linux target.
+
 *** Changes in GDB 7.6
 
 * Target record has been renamed to record-full.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index e8470a8..08a475f 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -157,7 +157,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
 	$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
 	$(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \
-	$(srcdir)/common/filestuff.c
+	$(srcdir)/common/filestuff.c $(srcdir)/common/mips-linux-watch.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -556,6 +556,9 @@ agent.o: ../common/agent.c
 linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
 
+mips-linux-watch.o: ../common/mips-linux-watch.c ../common/mips-linux-watch.h $(server_h)
+	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+
 # We build vasprintf with -DHAVE_CONFIG_H because we want that unit to
 # include our config.h file.  Otherwise, some system headers do not get
 # included, and the compiler emits a warning about implicitly defined
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 879d0de..8dee65b 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -183,7 +183,7 @@ case "${target}" in
 			srv_regobj="${srv_regobj} mips64-linux.o"
 			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
 			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
-			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+			srv_tgtobj="${srv_tgtobj} linux-ptrace.o mips-linux-watch.o"
 			srv_xmlfiles="mips-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml"
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 1010528..5ff9974 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -22,6 +22,7 @@
 #include <sys/ptrace.h>
 #include <endian.h>
 
+#include "mips-linux-watch.h"
 #include "gdb_proc_service.h"
 
 /* Defined in auto-generated file mips-linux.c.  */
@@ -159,6 +160,39 @@ get_usrregs_info (void)
   return regs_info->usrregs;
 }
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  /* -1 if the kernel and/or CPU do not support watch registers.
+      1 if watch_readback is valid and we can read style, num_valid
+	and the masks.
+      0 if we need to read the watch_readback.  */
+
+  int watch_readback_valid;
+
+  /* Cached watch register read values.  */
+
+  struct pt_watch_regs watch_readback;
+
+  /* Current watchpoint requests for this process.  */
+
+  struct mips_watchpoint *current_watches;
+
+  /*  The current set of watch register values for writing the
+      registers.  */
+
+  struct pt_watch_regs watch_mirror;
+};
+
+/* 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;
+};
+
 /* From mips-linux-nat.c.  */
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
@@ -257,6 +291,303 @@ mips_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Mark the debug registers of lwp, represented by ENTRY, is changed,
+   if the lwp's process id is *PID_P.  */
+
+static int
+update_debug_registers_callback (struct inferior_list_entry *entry,
+				 void *pid_p)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  int pid = *(int *) pid_p;
+
+  /* Only update the threads of this process.  */
+  if (pid_of (lwp) == pid)
+    {
+      /* 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;
+}
+
+/* This is the implementation of linux_target_ops method
+   new_process.  */
+
+static struct arch_process_info *
+mips_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method new_thread.
+   Mark the debug registers are changed, so the threads' copies will
+   be updated.  */
+
+static struct arch_lwp_info *
+mips_linux_new_thread (void)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->debug_registers_changed = 1;
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method
+   prepare_to_resume.  If the debug regs have changed, update the
+   thread's copies.  */
+
+static void
+mips_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  ptid_t ptid = ptid_of (lwp);
+  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
+  struct arch_process_info *private = proc->private->arch_private;
+
+  if (lwp->arch_private->debug_registers_changed)
+    {
+      /* Only update the debug registers if we have set or unset a
+	 watchpoint already.  */
+      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
+	{
+	  /* Write the mirrored watch register values.  */
+	  int tid = ptid_get_lwp (ptid);
+
+	  if (ptrace (PTRACE_SET_WATCH_REGS, tid, &private->watch_mirror) == -1)
+	    perror_with_name ("Couldn't write debug register");
+	}
+
+      lwp->arch_private->debug_registers_changed = 0;
+    }
+}
+
+/* This is the implementation of linux_target_ops method
+   insert_point.  */
+
+static int
+mips_insert_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  struct pt_watch_regs regs;
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+  int pid;
+  long lwpid;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  lwpid = lwpid_of (get_thread_lwp (current_inferior));
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = private->watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (private->current_watches, &regs);
+
+  /* Now try to add the new watch.  */
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
+				       mips_linux_watch_type_to_irw (type)))
+    return -1;
+
+  /* It fit.  Stick it on the end of the list.  */
+  new_watch = (struct mips_watchpoint *)
+    xmalloc (sizeof (struct mips_watchpoint));
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = type;
+  new_watch->next = NULL;
+
+  pw = &private->current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+
+  private->watch_mirror = regs;
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_debug_registers_callback, &pid);
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   remove_point.  */
+
+static int
+mips_remove_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+
+  int deleted_one;
+  int pid;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  /* Search for a known watch that matches.  Then unlink and free
+     it.  */
+  deleted_one = 0;
+  pw = &private->current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == type)
+	{
+	  *pw = w->next;
+	  free (w);
+	  deleted_one = 1;
+	  break;
+	}
+      pw = &(w->next);
+    }
+
+  if (!deleted_one)
+    return -1;  /* We don't know about it, fail doing nothing.  */
+
+  /* At this point watch_readback is known to be valid because we
+     could not have added the watch without reading it.  */
+  gdb_assert (private->watch_readback_valid == 1);
+
+  private->watch_mirror = private->watch_readback;
+  mips_linux_watch_populate_regs (private->current_watches,
+				  &private->watch_mirror);
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_debug_registers_callback, &pid);
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_by_watchpoint.  The watchhi R and W bits indicate
+   the watch register triggered. */
+
+static int
+mips_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					1))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      return 1;
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_data_address.  */
+
+static CORE_ADDR
+mips_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  /* On mips we don't know the low order 3 bits of the data address.
+     GDB does not support remote targets that can't report the
+     watchpoint address.  So, make our best guess; return the starting
+     address of a watchpoint request which overlaps the one that
+     triggered.  */
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      {
+	CORE_ADDR t_low, t_hi;
+	int t_irw;
+	struct mips_watchpoint *watch;
+
+	t_low = mips_linux_watch_get_watchlo (&private->watch_readback, n);
+	t_irw = t_low & IRW_MASK;
+	t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+		| IRW_MASK);
+	t_low &= ~(CORE_ADDR)t_hi;
+
+	for (watch = private->current_watches;
+	     watch != NULL;
+	     watch = watch->next)
+	  {
+	    CORE_ADDR addr = watch->addr;
+	    CORE_ADDR last_byte = addr + watch->len - 1;
+	    if ((t_irw & mips_linux_watch_type_to_irw (watch->type))
+		== 0)
+	      /* Different type.  */
+	      continue;
+	    /* Check for overlap of even a single byte.  */
+	    if (last_byte >= t_low && addr <= t_low + t_hi)
+	      return addr;
+	  }
+      }
+
+  /* Shouldn't happen.  */
+  return 0;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -506,6 +837,16 @@ struct linux_target_ops the_low_target = {
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
+  mips_insert_point,
+  mips_remove_point,
+  mips_stopped_by_watchpoint,
+  mips_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, /* siginfo_fixup */
+  mips_linux_new_process,
+  mips_linux_new_thread,
+  mips_linux_prepare_to_resume
 };
 
 void
-- 
1.7.7.6


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

* Re: [PATCH 3/3] MIPS h/w watchpoint in GDBserver
  2013-06-13  8:20   ` Yao Qi
@ 2013-06-13 13:09     ` Eli Zaretskii
  2013-06-13 16:56     ` Pedro Alves
  2013-06-19 22:22     ` Maciej W. Rozycki
  2 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2013-06-13 13:09 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

> Date: Thu, 13 Jun 2013 12:11:54 +0800
> From: Yao Qi <yao@codesourcery.com>
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index eea9917..d56e18a 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -108,6 +108,8 @@ qXfer:libraries-svr4:read's annex
>    ** GDBserver now supports target-assisted range stepping.  Currently
>       enabled on x86/x86_64 GNU/Linux targets.
>  
> +  ** GDBserver now supports hardware watchpoint on mips GNU/Linux target.
> +
>  *** Changes in GDB 7.6
>  
>  * Target record has been renamed to record-full.

OK for this part.

Thanks.


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

* Re: [PATCH 3/3] MIPS h/w watchpoint in GDBserver
  2013-06-13  8:20   ` Yao Qi
  2013-06-13 13:09     ` Eli Zaretskii
@ 2013-06-13 16:56     ` Pedro Alves
  2013-06-19 22:22     ` Maciej W. Rozycki
  2 siblings, 0 replies; 52+ messages in thread
From: Pedro Alves @ 2013-06-13 16:56 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 06/13/2013 05:11 AM, Yao Qi wrote:
> On 05/30/2013 10:44 AM, Yao Qi wrote:
>> @@ -20,6 +20,7 @@
>>   #include "linux-low.h"
>>   
>>   #include <sys/ptrace.h>
>> +#include "mips-linux-watch.h"
>>   #include <endian.h>
>>   
>>   #include "gdb_proc_service.h"
> 
> Pedro mentioned that there are "unexplained odd placements for
> includes", however, the only 'oddity' I can see is the order of include
> mips-linux-watch.h and endian.h.  In this version, I exchange the order
> of them.

Thanks.  Yes, that's the oddity I was referring to, specifically:

 #include <system header>
 #include "local header"
 #include <system header>
 #include "local header"

IMO, it's better to keep system header includes all together, and
local includes all together (though we're not that good at doing that).
With that in mind, given the odd placement for "mips-linux-watch.h" between
two system headers, I wondered whether there was something
in "mips-linux-watch.h" or <endian.h> that made that particular placement
necessary, and if so, that should be explained, hence my "unexplained".

(IMO2, I'd go as far as saying that it's better to put system includes
after local includes, in order to prevent hidden dependencies in our
headers, following the principle that headers should be self contained,
but pull in the least dependencies possible with forward declarations
for opaque types, etc., and compileable on their own.)

-- 
Pedro Alves


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-05-30  2:44 ` [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
@ 2013-06-13 17:49   ` Maciej W. Rozycki
  2013-06-14  6:53     ` Yao Qi
  2013-06-17 16:04     ` Maciej W. Rozycki
  0 siblings, 2 replies; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-13 17:49 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 30 May 2013, Yao Qi wrote:

> This patch is to include asm/ptrace.h in mips-linux-nat.c and remove
> some duplicated structs already defined in asm/ptrace.h.

 You missed the local definitions of the PTRACE_GET_WATCH_REGS and 
PTRACE_SET_WATCH_REGS macros that could also be removed, however...

> The ptrace support for hardware support was added into kernel in Sep.
> 2008 and the mips hardware watchpoint for native GDB was committed
> on April 2009.  Considering the time order, GDB doesn't have to carry
> these local definitions, and should include asm/ptrace.h instead.

 ... this change actually resulted in a graceless build failure for me:

../../src/gdb/mips-linux-nat.c:599: error: storage size of 'dummy_regs' isn't known

etc. for the very reason the system I used for testing has old kernel 
headers installed (2.6.19 it would seem, according to <linux/version.h>).  

 Such a failure is not acceptable from the user's point of view; I think 
there are three ways to deal with this:

1. Add an autoconf test that checks for the presence of a key 
   <asm/ptrace.h> definition; I think 'struct pt_watch_regs' is a good 
   candidate.  If that test does not succeed, then the configure process 
   fails gracefully stating the minimum released version of kernel headers 
   required.

2. Add the same test, except in the failure case fall back to the internal 
   definitions we already have, wrapped into #ifndef 
   HAVE_STRUCT_PT_WATCH_REGS.

3. Add the same test and disable hardware watchpoint support in the 
   failure case.

 The user ABI of the Linux kernel has a stability guarantee and your 
change makes GDB stop building on this otherwise fine system, so I'd lean 
towards the second choice, moving all the stuff into 
common/mips-linux-watch.h as per your second patch in this series.  I am 
not entirely sure what the general practice about such changes in GDB has 
been though, so I'd ask other maintainers for opinion here.

 Note that likewise the local PTRACE_GET_THREAD_AREA definition could be 
removed if relying on <asm/ptrace.h> for watchpoint support as the macro 
has already been defined in the 2.6.19 version I have on this system that 
does not have watchpoint definitions yet.  For this reason I think it will 
be better actually if common/mips-linux-watch.h relies on <asm/ptrace.h> 
having been included earlier on by the source file including the former 
header.

 For the record the system I intended to run native testing on does indeed 
support hardware watchpoints, although a minimal number of them:

hardware watchpoint	: yes, count: 2, address/irw mask: [0x0ffc, 0x0ffb]

-- i.e. a single data watchpoint and a single execution watchpoint only 
(as noted by the "irw mask" field, taking the 3 LSBs of the values 
reported).  I expect to have results by the end of tomorrow and will let 
you know how that has gone.

 Would general maintainers please comment on the three-way choice and the 
preferred way to move forward I outlined above?

  Maciej


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-13 17:49   ` Maciej W. Rozycki
@ 2013-06-14  6:53     ` Yao Qi
  2013-06-14 12:53       ` Maciej W. Rozycki
  2013-06-17 16:04     ` Maciej W. Rozycki
  1 sibling, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-14  6:53 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 06/14/2013 01:37 AM, Maciej W. Rozycki wrote:
> ../../src/gdb/mips-linux-nat.c:599: error: storage size of 'dummy_regs' isn't known
>
> etc. for the very reason the system I used for testing has old kernel
> headers installed (2.6.19 it would seem, according to <linux/version.h>).
>
>   Such a failure is not acceptable from the user's point of view; I think
> there are three ways to deal with this:
>
> 1. Add an autoconf test that checks for the presence of a key
>     <asm/ptrace.h> definition; I think 'struct pt_watch_regs' is a good
>     candidate.  If that test does not succeed, then the configure process
>     fails gracefully stating the minimum released version of kernel headers
>     required.
>
> 2. Add the same test, except in the failure case fall back to the internal
>     definitions we already have, wrapped into #ifndef
>     HAVE_STRUCT_PT_WATCH_REGS.
>
> 3. Add the same test and disable hardware watchpoint support in the
>     failure case.

I prefer #3.  If 'struct pt_watch_regs' is not defined, hardware 
watchpoint is not supported in the kernel.  Because 'struct 
pt_watch_regs' was added in this commit in linux kernel,

commit 0926bf953ee79b8f139741b442e5a18520f81705
Author: David Daney <ddaney@avtrex.com>
Date:   Tue Sep 23 00:11:26 2008 -0700

     MIPS: Ptrace support for HARDWARE_WATCHPOINTS

     This is the final part of the watch register patch.  Here we hook up
     ptrace so that the user space debugger (gdb), can set and read the
     registers.

     Signed-off-by: David Daney <ddaney@avtrex.com>
     Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

-- 
Yao (齐尧)


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-14  6:53     ` Yao Qi
@ 2013-06-14 12:53       ` Maciej W. Rozycki
  2013-06-20 19:40         ` Pedro Alves
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-14 12:53 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Fri, 14 Jun 2013, Yao Qi wrote:

> > ../../src/gdb/mips-linux-nat.c:599: error: storage size of 'dummy_regs'
> > isn't known
> > 
> > etc. for the very reason the system I used for testing has old kernel
> > headers installed (2.6.19 it would seem, according to <linux/version.h>).
> > 
> >   Such a failure is not acceptable from the user's point of view; I think
> > there are three ways to deal with this:
> > 
> > 1. Add an autoconf test that checks for the presence of a key
> >     <asm/ptrace.h> definition; I think 'struct pt_watch_regs' is a good
> >     candidate.  If that test does not succeed, then the configure process
> >     fails gracefully stating the minimum released version of kernel headers
> >     required.
> > 
> > 2. Add the same test, except in the failure case fall back to the internal
> >     definitions we already have, wrapped into #ifndef
> >     HAVE_STRUCT_PT_WATCH_REGS.
> > 
> > 3. Add the same test and disable hardware watchpoint support in the
> >     failure case.
> 
> I prefer #3.  If 'struct pt_watch_regs' is not defined, hardware watchpoint is
> not supported in the kernel.  Because 'struct pt_watch_regs' was added in this
> commit in linux kernel,
> 
> commit 0926bf953ee79b8f139741b442e5a18520f81705
> Author: David Daney <ddaney@avtrex.com>
> Date:   Tue Sep 23 00:11:26 2008 -0700
> 
>     MIPS: Ptrace support for HARDWARE_WATCHPOINTS
> 
>     This is the final part of the watch register patch.  Here we hook up
>     ptrace so that the user space debugger (gdb), can set and read the
>     registers.
> 
>     Signed-off-by: David Daney <ddaney@avtrex.com>
>     Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

 Well, kernel headers bundled with the C library installed on a system GDB 
is being built on do not necessarily have to match the kernel binary the 
system uses (as is the case with the system I'm using for this validation) 
or GDB may be run on another system.  So you cannot infer at the build 
time whether the kernel used on a system GDB is going to run on supports 
watchpoints until you actually query the kernel at the run time; you need 
to do a run-time check anyway as hardware may not even if the kernel will.

 Therefore I think my question here is a matter of policy in GDB rather 
than limitations posed by a system in a given configuration.  Which makes 
your preference valid, although not for the reason you stated.

  Maciej


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-13 17:49   ` Maciej W. Rozycki
  2013-06-14  6:53     ` Yao Qi
@ 2013-06-17 16:04     ` Maciej W. Rozycki
  1 sibling, 0 replies; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-17 16:04 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 13 Jun 2013, Maciej W. Rozycki wrote:

>  For the record the system I intended to run native testing on does indeed 
> support hardware watchpoints, although a minimal number of them:
> 
> hardware watchpoint	: yes, count: 2, address/irw mask: [0x0ffc, 0x0ffb]
> 
> -- i.e. a single data watchpoint and a single execution watchpoint only 
> (as noted by the "irw mask" field, taking the 3 LSBs of the values 
> reported).  I expect to have results by the end of tomorrow and will let 
> you know how that has gone.

 I have finished testing, but regrettably test results are inconclusive, 
sorry about that.  Testing revealed issues with the kernel, specifically:

1. I-cache vs D-cache coherency problems affecting GDB execution (crashes)
   and software breakpoints (spurious and missed hits).

2. Hardware watchpoints never hitting regardless of your change being 
   present or not, and then both in GDB and gdbserver.

Therefore I must accept your limited native testing and will assume all is 
right based on code review.  I'll look through the two remaining changes 
and see if all is right there.  We can then address any issues as they pop 
up in the future once a good native platform is available.

 Meanwhile I have contacted the MIPS/Linux maintainer regarding the 
problems I observed.  Hopefully they can be sorted out reasonably soon, 
though I wouldn't bet on it as my suspicion is it's been a long-standing 
problem with that platform (and 2.6.18 is the last known-good version of 
the kernel there -- before the big cache handling rewrite).

  Maciej


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-06-13  4:12   ` Yao Qi
@ 2013-06-19 22:05     ` Maciej W. Rozycki
  2013-06-20 14:21       ` Yao Qi
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-19 22:05 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 13 Jun 2013, Yao Qi wrote:

> 2013-06-13  Yao Qi  <yao@codesourcery.com>

 Thanks for this work.  Please see the individual notes below.

> 	* Makefile.in (HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
> 	(mips-linux-watch.o): New rule.
> 	* common/mips-linux-watch.c, common/mips-linux-watch.h: New.

 Please list these files individually.

> 	* config/mips/linux.mh (NAT_FILE): Add mips-linux-watch.o.

 The `make' variable adjusted is called NATDEPFILES, not NAT_FILE.

> 	* mips-linux-nat.c: Include mips-linux-watch.h.
> 	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
> 	to common/mips-linux-watch.h.
> 	(MAX_DEBUG_REGISTER): Likewise.
> 	(struct mips_watchpoint): Likewise.
> 	(get_irw_mask, get_reg_mask, get_num_valid, get_watchlo): Move to
> 	to common/mips-linux-watch.c and add name prefix 'mips_linux_watch_'.

 Repeated "to", see below however.

> diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
> new file mode 100644
> index 0000000..eeac2f8
> --- /dev/null
> +++ b/gdb/common/mips-linux-watch.c
> @@ -0,0 +1,359 @@
> +/* Copyright (C) 2009-2013 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 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/>.  */
> +
> +#include <sys/ptrace.h>
> +#include "mips-linux-watch.h"
> +#include "gdb_assert.h"
> +
> +#ifdef GDBSERVER
> +#define hw_write '2'
> +#define hw_read '3'
> +#define hw_access '4'
> +#else
> +#include "breakpoint.h"
> +#endif
> +
> +/* Assuming usable watch registers REGS, return the num_valid.  */
> +
> +uint32_t
> +mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
> +{
> +  switch (regs->style)
> +    {
> +    case pt_watch_style_mips32:
> +      return regs->mips32.num_valid;
> +    case pt_watch_style_mips64:
> +      return regs->mips64.num_valid;
> +    default:
> +      internal_error (__FILE__, __LINE__,
> +		      _("Unrecognized watch register style"));
> +    }
> +}
> +
> +/* Assuming usable watch registers REGS, return the irw_mask of
> +   register N.  */
> +
> +uint32_t
> +mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)

 Any particular reason with the move of this function from 
mips-linux-nat.c to mips-linux-watch.c you renamed the SET argument to N 
(while keeping the old name in the prototype in mips-linux-watch.h)?

 You're moving pieces of code between files while at the same time making 
subtle changes.  This makes it easy for something to escape unnoticed.  
In some cases it may be unavoidable, here however it does not appear 
to me you need to make both sets of changes at once.

 Please therefore split this change into two self-contained stages:

1. All the tweaks including function renames, their API changes, comment 
   updates, etc., applied while still a part of mips-linux-nat.c.

2. The move of the adjusted pieces verbatim over to mips-linux-watch.[ch].

Of course you'll still have to make some trivial changes in the course of 
the move, in particular adding/removing header inclusions as necessary and 
adding the conditional stuff around #ifdef GDBSERVER.

 Let me know if you think you may have any trouble with that.

 Barring the pieces that are moved from mips-linux-nat.c to 
mips-linux-watch.[ch] this patch looks good, thanks.  To hopefully save us 
from extra iteration here are some notes on issues in mips-linux-watch.h 
that are readily visible and that you can address in the stage #2 referred 
above.

 Also in the stage #1 (or better yet, as a preparatory #0 patch) please 
make the type of irw variables consistent; "unsigned" is a K&R-ism, 
"uint32_t" will be better as it's already used in many places for this 
purpose ("uint16_t" is used in the kernel structures, but let's leave the 
consideration of any change to this type for another day).

> diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
> new file mode 100644
> index 0000000..5d4fa00
> --- /dev/null
> +++ b/gdb/common/mips-linux-watch.h
> @@ -0,0 +1,76 @@
> +/* Copyright (C) 2009-2013 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 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/>.  */
> +
> +#ifndef MIPS_LINUX_WATCH_H
> +#define MIPS_LINUX_WATCH_H 1
> +
> +#ifdef GDBSERVER
> +#include "server.h"
> +#else
> +#include "defs.h"
> +#endif
> +
> +#include <asm/ptrace.h>
> +#include <stdint.h>
> +
> +#define W_BIT 0
> +#define R_BIT 1
> +#define I_BIT 2
> +
> +#define W_MASK (1 << W_BIT)
> +#define R_MASK (1 << R_BIT)
> +#define I_MASK (1 << I_BIT)
> +
> +#define IRW_MASK (I_MASK | R_MASK | W_MASK)
> +
> +#define MAX_DEBUG_REGISTER 8
> +
> +/* We keep list of all watchpoints we should install and calculate the
> +   watch register values each time the list changes.  This allows for
> +   easy sharing of watch registers for more than one watchpoint.  */
> +
> +struct mips_watchpoint
> +{
> +  CORE_ADDR addr;
> +  int len;
> +  int type;
> +  struct mips_watchpoint *next;
> +};
> +
> +uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
> +uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs,
> +					int set);
> +CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs,
> +					int set);

 The two prototypes above will fit in a single line each.

> +void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs,
> +				   int set, CORE_ADDR value);
> +uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs,
> +				       int n);

 As will one above.

> +void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
> +				   uint16_t value);

 Please carry "int n" onto the second line for consistency with 
mips_linux_watch_set_watchlo.

> +int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
> +				    CORE_ADDR addr, int len,
> +				    unsigned irw);

 The three last arguments above will fit in a single line.

 Please resubmit with the changes requested.

  Maciej


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

* Re: [PATCH 3/3] MIPS h/w watchpoint in GDBserver
  2013-06-13  8:20   ` Yao Qi
  2013-06-13 13:09     ` Eli Zaretskii
  2013-06-13 16:56     ` Pedro Alves
@ 2013-06-19 22:22     ` Maciej W. Rozycki
  2013-06-21 15:00       ` Pedro Alves
  2 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-19 22:22 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 13 Jun 2013, Yao Qi wrote:

> Pedro mentioned that there are "unexplained odd placements for
> includes", however, the only 'oddity' I can see is the order of include
> mips-linux-watch.h and endian.h.  In this version, I exchange the order
> of them.  I also add a news entry for it.

 This is mostly OK, thanks.  Please see individual notes below for some 
issues, mostly minor style ones; code itself looks good to me.

> 2013-06-13  Jie Zhang  <jie@codesourcery.com>
> 	    Daniel Jacobowitz  <dan@codesourcery.com>
> 	    Yao Qi  <yao@codesourcery.com>
> 
> 	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
> 	(mips-linux-watch.o): New rule.
> 	* configure.srv (srv_tgtobj): Add mips-linux-watch.o

 Use:

	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to 
	srv_tgtobj.

> diff --git a/gdb/NEWS b/gdb/NEWS
> index eea9917..d56e18a 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -108,6 +108,8 @@ qXfer:libraries-svr4:read's annex
>    ** GDBserver now supports target-assisted range stepping.  Currently
>       enabled on x86/x86_64 GNU/Linux targets.
>  
> +  ** GDBserver now supports hardware watchpoint on mips GNU/Linux target.

 Please capitalise MIPS.

> diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
> index e8470a8..08a475f 100644
> --- a/gdb/gdbserver/Makefile.in
> +++ b/gdb/gdbserver/Makefile.in
> @@ -556,6 +556,9 @@ agent.o: ../common/agent.c
>  linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
>  	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
>  
> +mips-linux-watch.o: ../common/mips-linux-watch.c ../common/mips-linux-watch.h $(server_h)
> +	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
> +

 Please define and use $(mips_linux_watch_h) as with other header deps.

> diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
> index 879d0de..8dee65b 100644
> --- a/gdb/gdbserver/configure.srv
> +++ b/gdb/gdbserver/configure.srv
> @@ -183,7 +183,7 @@ case "${target}" in
>  			srv_regobj="${srv_regobj} mips64-linux.o"
>  			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
>  			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
> -			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
> +			srv_tgtobj="${srv_tgtobj} linux-ptrace.o mips-linux-watch.o"

 This extends beyond 79th column, add mips-linux-watch.o on another line.

> diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
> index 1010528..5ff9974 100644
> --- a/gdb/gdbserver/linux-mips-low.c
> +++ b/gdb/gdbserver/linux-mips-low.c
> @@ -159,6 +160,39 @@ get_usrregs_info (void)
>    return regs_info->usrregs;
>  }
>  
> +/* Per-process arch-specific data we want to keep.  */
> +
> +struct arch_process_info
> +{
> +  /* -1 if the kernel and/or CPU do not support watch registers.
> +      1 if watch_readback is valid and we can read style, num_valid
> +	and the masks.
> +      0 if we need to read the watch_readback.  */
> +
> +  int watch_readback_valid;
> +
> +  /* Cached watch register read values.  */
> +
> +  struct pt_watch_regs watch_readback;
> +
> +  /* Current watchpoint requests for this process.  */
> +
> +  struct mips_watchpoint *current_watches;
> +
> +  /*  The current set of watch register values for writing the
> +      registers.  */
> +
> +  struct pt_watch_regs watch_mirror;
> +};
> +
> +/* 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;

 Rename to watch_registers_changed.

 Rather than "debug registers" please refer to "watch registers", which is 
the proper architectural name of this facility.  On MIPS processors debug 
registers are the EJTAG register set.  Apply throughout as required, I 
won't play a `sed' role and point out individual cases.

> @@ -257,6 +291,303 @@ mips_breakpoint_at (CORE_ADDR where)
>    return 0;
>  }
>  
> +/* Mark the debug registers of lwp, represented by ENTRY, is changed,

 s/is changed/as changed/ presumably?

> +   if the lwp's process id is *PID_P.  */
> +
> +static int
> +update_debug_registers_callback (struct inferior_list_entry *entry,
> +				 void *pid_p)
> +{
> +  struct lwp_info *lwp = (struct lwp_info *) entry;
> +  int pid = *(int *) pid_p;
> +
> +  /* Only update the threads of this process.  */
> +  if (pid_of (lwp) == pid)
> +    {
> +      /* 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;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   new_process.  */
> +
> +static struct arch_process_info *
> +mips_linux_new_process (void)
> +{
> +  struct arch_process_info *info = xcalloc (1, sizeof (*info));
> +
> +  return info;
> +}
> +
> +/* This is the implementation of linux_target_ops method new_thread.
> +   Mark the debug registers are changed, so the threads' copies will

 s/are changed/as changed/?

> +   be updated.  */
> +
> +static struct arch_lwp_info *
> +mips_linux_new_thread (void)
> +{
> +  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
> +
> +  info->debug_registers_changed = 1;
> +
> +  return info;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   prepare_to_resume.  If the debug regs have changed, update the
> +   thread's copies.  */
> +
> +static void
> +mips_linux_prepare_to_resume (struct lwp_info *lwp)
> +{
> +  ptid_t ptid = ptid_of (lwp);
> +  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
> +  struct arch_process_info *private = proc->private->arch_private;
> +
> +  if (lwp->arch_private->debug_registers_changed)
> +    {
> +      /* Only update the debug registers if we have set or unset a
> +	 watchpoint already.  */
> +      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
> +	{
> +	  /* Write the mirrored watch register values.  */
> +	  int tid = ptid_get_lwp (ptid);
> +
> +	  if (ptrace (PTRACE_SET_WATCH_REGS, tid, &private->watch_mirror) == -1)

 Oversize line.

> +	    perror_with_name ("Couldn't write debug register");

 "Couldn't write watch registers"

> +	}
> +
> +      lwp->arch_private->debug_registers_changed = 0;
> +    }
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   insert_point.  */
> +
> +static int
> +mips_insert_point (char type, CORE_ADDR addr, int len)
> +{
> +  struct process_info *proc = current_process ();
> +  struct arch_process_info *private = proc->private->arch_private;
> +  struct pt_watch_regs regs;
> +  struct mips_watchpoint *new_watch;
> +  struct mips_watchpoint **pw;
> +  int pid;
> +  long lwpid;
> +
> +  /* Breakpoint/watchpoint types:
> +       '0' - software-breakpoint (not supported)
> +       '1' - hardware-breakpoint (not supported)
> +       '2' - write watchpoint (supported)
> +       '3' - read watchpoint (supported)
> +       '4' - access watchpoint (supported).  */
> +
> +  if (type < '2' || type > '4')
> +    {
> +      /* Unsupported.  */
> +      return 1;
> +    }
> +
> +  lwpid = lwpid_of (get_thread_lwp (current_inferior));
> +  if (!mips_linux_read_watch_registers (lwpid,
> +					&private->watch_readback,
> +					&private->watch_readback_valid,
> +					0))
> +    return -1;
> +
> +  if (len <= 0)
> +    return -1;
> +
> +  regs = private->watch_readback;
> +  /* Add the current watches.  */
> +  mips_linux_watch_populate_regs (private->current_watches, &regs);
> +
> +  /* Now try to add the new watch.  */
> +  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
> +				       mips_linux_watch_type_to_irw (type)))
> +    return -1;
> +
> +  /* It fit.  Stick it on the end of the list.  */
> +  new_watch = (struct mips_watchpoint *)
> +    xmalloc (sizeof (struct mips_watchpoint));

 Extraneous cast.

> +  new_watch->addr = addr;
> +  new_watch->len = len;
> +  new_watch->type = type;
> +  new_watch->next = NULL;
> +
> +  pw = &private->current_watches;
> +  while (*pw != NULL)
> +    pw = &(*pw)->next;
> +  *pw = new_watch;
> +
> +  private->watch_mirror = regs;
> +
> +  /* Only update the threads of this process.  */
> +  pid = pid_of (proc);
> +  find_inferior (&all_lwps, update_debug_registers_callback, &pid);
> +
> +  return 0;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   remove_point.  */
> +
> +static int
> +mips_remove_point (char type, CORE_ADDR addr, int len)
> +{
> +  struct process_info *proc = current_process ();
> +  struct arch_process_info *private = proc->private->arch_private;
> +
> +  int deleted_one;
> +  int pid;
> +
> +  struct mips_watchpoint **pw;
> +  struct mips_watchpoint *w;
> +
> +  /* Breakpoint/watchpoint types:
> +       '0' - software-breakpoint (not supported)
> +       '1' - hardware-breakpoint (not supported)
> +       '2' - write watchpoint (supported)
> +       '3' - read watchpoint (supported)
> +       '4' - access watchpoint (supported).  */
> +
> +  if (type < '2' || type > '4')
> +    {
> +      /* Unsupported.  */
> +      return 1;
> +    }
> +
> +  /* Search for a known watch that matches.  Then unlink and free
> +     it.  */

 No need to wrap this line.

> +  deleted_one = 0;
> +  pw = &private->current_watches;
> +  while ((w = *pw))
> +    {
> +      if (w->addr == addr && w->len == len && w->type == type)
> +	{
> +	  *pw = w->next;
> +	  free (w);
> +	  deleted_one = 1;
> +	  break;
> +	}
> +      pw = &(w->next);
> +    }
> +
> +  if (!deleted_one)
> +    return -1;  /* We don't know about it, fail doing nothing.  */
> +
> +  /* At this point watch_readback is known to be valid because we
> +     could not have added the watch without reading it.  */
> +  gdb_assert (private->watch_readback_valid == 1);
> +
> +  private->watch_mirror = private->watch_readback;
> +  mips_linux_watch_populate_regs (private->current_watches,
> +				  &private->watch_mirror);
> +
> +  /* Only update the threads of this process.  */
> +  pid = pid_of (proc);
> +  find_inferior (&all_lwps, update_debug_registers_callback, &pid);
> +  return 0;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   stopped_by_watchpoint.  The watchhi R and W bits indicate
> +   the watch register triggered. */
> +
> +static int
> +mips_stopped_by_watchpoint (void)
> +{
> +  struct process_info *proc = current_process ();
> +  struct arch_process_info *private = proc->private->arch_private;
> +  int n;
> +  int num_valid;
> +  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
> +
> +  if (!mips_linux_read_watch_registers (lwpid,
> +					&private->watch_readback,
> +					&private->watch_readback_valid,
> +					1))
> +    return 0;
> +
> +  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
> +
> +  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
> +    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
> +	& (R_MASK | W_MASK))
> +      return 1;
> +
> +  return 0;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   stopped_data_address.  */
> +
> +static CORE_ADDR
> +mips_stopped_data_address (void)
> +{
> +  struct process_info *proc = current_process ();
> +  struct arch_process_info *private = proc->private->arch_private;
> +  int n;
> +  int num_valid;
> +  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
> +
> +  /* On mips we don't know the low order 3 bits of the data address.

 Capitalise MIPS.

> +     GDB does not support remote targets that can't report the
> +     watchpoint address.  So, make our best guess; return the starting
> +     address of a watchpoint request which overlaps the one that
> +     triggered.  */
> +
> +  if (!mips_linux_read_watch_registers (lwpid,
> +					&private->watch_readback,
> +					&private->watch_readback_valid,
> +					0))
> +    return 0;
> +
> +  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
> +
> +  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
> +    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
> +	& (R_MASK | W_MASK))
> +      {
> +	CORE_ADDR t_low, t_hi;
> +	int t_irw;
> +	struct mips_watchpoint *watch;
> +
> +	t_low = mips_linux_watch_get_watchlo (&private->watch_readback, n);
> +	t_irw = t_low & IRW_MASK;
> +	t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
> +		| IRW_MASK);
> +	t_low &= ~(CORE_ADDR)t_hi;
> +
> +	for (watch = private->current_watches;
> +	     watch != NULL;
> +	     watch = watch->next)
> +	  {
> +	    CORE_ADDR addr = watch->addr;
> +	    CORE_ADDR last_byte = addr + watch->len - 1;
> +	    if ((t_irw & mips_linux_watch_type_to_irw (watch->type))
> +		== 0)

 No need to wrap the line here.

 Please resend with the requested changes applied.

  Maciej


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-06-19 22:05     ` Maciej W. Rozycki
@ 2013-06-20 14:21       ` Yao Qi
  2013-06-20 15:27         ` Maciej W. Rozycki
  0 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-20 14:21 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

Maciej,
Thanks for the review.  I'll split this patch.  A question to the 
comment below,

On 06/20/2013 06:03 AM, Maciej W. Rozycki wrote:
>> +uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
>> >+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs,
>> >+					int set);
>> >+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs,
>> >+					int set);
>   The two prototypes above will fit in a single line each.
>

If we put the prototypes into a single line, the length exceeds the 
74-character limit.  This is the reason I moved parameter "set" to a new 
line.  Shall we keep them as what they are now?

>
>> >+int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
>> >+				    CORE_ADDR addr, int len,
>> >+				    unsigned irw);
>   The three last arguments above will fit in a single line.

Likewise.

-- 
Yao (齐尧)


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-06-20 14:21       ` Yao Qi
@ 2013-06-20 15:27         ` Maciej W. Rozycki
  2013-06-20 17:50           ` Joel Brobecker
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-20 15:27 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 20 Jun 2013, Yao Qi wrote:

> > > +uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
> > > >+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs,
> > > >+					int set);
> > > >+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs,
> > > >+					int set);
> >   The two prototypes above will fit in a single line each.
> > 
> 
> If we put the prototypes into a single line, the length exceeds the
> 74-character limit.  This is the reason I moved parameter "set" to a new line.
> Shall we keep them as what they are now?

 There's no 74-character limit for code, all you need is to stay within 79 
columns.  Did you apply the ChangeLog rule here?

  Maciej


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-06-20 15:27         ` Maciej W. Rozycki
@ 2013-06-20 17:50           ` Joel Brobecker
  2013-06-21  8:03             ` Maciej W. Rozycki
  0 siblings, 1 reply; 52+ messages in thread
From: Joel Brobecker @ 2013-06-20 17:50 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Yao Qi, gdb-patches

> > If we put the prototypes into a single line, the length exceeds the
> > 74-character limit.  This is the reason I moved parameter "set" to a new line.
> > Shall we keep them as what they are now?
> 
>  There's no 74-character limit for code, all you need is to stay
>  within 79 columns.  Did you apply the ChangeLog rule here?

Actually, the last time we discussed maximum code line length,
we settled on 70 characters.

Reference: http://www.sourceware.org/ml/gdb-patches/2011-01/msg00035.html

It's not consistent across files; for instance, it's 74 characters
in ChangeLogs. Those limits are kind of arbitrary, but I do find 79
characters to be slightly harder to read. Jan recently opened that
discussion again, and proposed 80 characters, but that did not stick.
I proposed to standardize on 74 instead, which is already the default
for some editors and the value used for ChangeLogs. But the discussion
then died. I'm not too surprised, since it's impossible to please
everybody, and controversial changes in the GDB porject have a tendency
of getting stuck.

-- 
Joel


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-14 12:53       ` Maciej W. Rozycki
@ 2013-06-20 19:40         ` Pedro Alves
  2013-06-20 20:45           ` Maciej W. Rozycki
  0 siblings, 1 reply; 52+ messages in thread
From: Pedro Alves @ 2013-06-20 19:40 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Yao Qi, gdb-patches

On 06/14/2013 01:37 PM, Maciej W. Rozycki wrote:
> On Fri, 14 Jun 2013, Yao Qi wrote:
> 
>>> ../../src/gdb/mips-linux-nat.c:599: error: storage size of 'dummy_regs'
>>> isn't known
>>>
>>> etc. for the very reason the system I used for testing has old kernel
>>> headers installed (2.6.19 it would seem, according to <linux/version.h>).
>>>
>>>   Such a failure is not acceptable from the user's point of view; I think
>>> there are three ways to deal with this:
>>>
>>> 1. Add an autoconf test that checks for the presence of a key
>>>     <asm/ptrace.h> definition; I think 'struct pt_watch_regs' is a good
>>>     candidate.  If that test does not succeed, then the configure process
>>>     fails gracefully stating the minimum released version of kernel headers
>>>     required.
>>>
>>> 2. Add the same test, except in the failure case fall back to the internal
>>>     definitions we already have, wrapped into #ifndef
>>>     HAVE_STRUCT_PT_WATCH_REGS.
>>>
>>> 3. Add the same test and disable hardware watchpoint support in the
>>>     failure case.
>>
>> I prefer #3.  If 'struct pt_watch_regs' is not defined, hardware watchpoint is
>> not supported in the kernel.  Because 'struct pt_watch_regs' was added in this
>> commit in linux kernel,
>>
>> commit 0926bf953ee79b8f139741b442e5a18520f81705
>> Author: David Daney <ddaney@avtrex.com>
>> Date:   Tue Sep 23 00:11:26 2008 -0700
>>
>>     MIPS: Ptrace support for HARDWARE_WATCHPOINTS
>>
>>     This is the final part of the watch register patch.  Here we hook up
>>     ptrace so that the user space debugger (gdb), can set and read the
>>     registers.
>>
>>     Signed-off-by: David Daney <ddaney@avtrex.com>
>>     Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
> 
>  Well, kernel headers bundled with the C library installed on a system GDB 
> is being built on do not necessarily have to match the kernel binary the 
> system uses (as is the case with the system I'm using for this validation) 
> or GDB may be run on another system.  So you cannot infer at the build 
> time whether the kernel used on a system GDB is going to run on supports 
> watchpoints until you actually query the kernel at the run time; you need 
> to do a run-time check anyway as hardware may not even if the kernel will.
> 
>  Therefore I think my question here is a matter of policy in GDB rather 
> than limitations posed by a system in a given configuration.  Which makes 
> your preference valid, although not for the reason you stated.

We don't have a written or very fixed policy, afaik.

For new ports, we try to push back on adding such fallback definitions,
in order push the submitter into actually adding them to their
right place (the kernel headers). (otherwise, it's been somewhat common
that the defines don't actually make it there!  E.g., PT_TEXT_ADDR
and friends...)  Then, we prefer assuming minimum kernel headers version
the first released version with all the necessary bits for the port.

For new features, things get a bit more blurry.

Given kernel headers guarantee backwards compatibility, it's my
understanding that you should always be able to build against the
latest kernel headers, even if you're running against an old kernel.
ISTR that's how CS builds things.  However, naturally not everyone
will do that.  Most will rely on the system's kernel version's
headers.

Weighing the maintenance cost of a autoconf glue plus #ifdefs
around the feature's code, vs defining a couple fallback constants
ourselves, I'd say the latter is simpler and less effort, thus my
preference.  If we're talking about a set of missing complicated
structure definitions, then I may have the opposite opinion.

In this case, I was borderline when I initially reviewed the
Daney's watchpoints's code, but I accepted it then.  Given they're
already in place, it just sounds like causing unnecessary trouble
to me to remove them, more so you've shown an example where they're
necessary.  I'd vote for keeping them.  Supposedly, MAX_DEBUG_REGISTER
or some other convenient define was added to the kernel's asm/ptrace.h
at the same time as struct pt_watch_regs etc, so we could
still include asm/ptrace.h, and only define the fallbacks if
that such macro is not defined?

-- 
Pedro Alves


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-20 19:40         ` Pedro Alves
@ 2013-06-20 20:45           ` Maciej W. Rozycki
  2013-06-21 14:58             ` Pedro Alves
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-20 20:45 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Yao Qi, gdb-patches

On Thu, 20 Jun 2013, Pedro Alves wrote:

> >>> ../../src/gdb/mips-linux-nat.c:599: error: storage size of 'dummy_regs'
> >>> isn't known
> >>>
> >>> etc. for the very reason the system I used for testing has old kernel
> >>> headers installed (2.6.19 it would seem, according to <linux/version.h>).
> >>>
> >>>   Such a failure is not acceptable from the user's point of view; I think
> >>> there are three ways to deal with this:
> >>>
> >>> 1. Add an autoconf test that checks for the presence of a key
> >>>     <asm/ptrace.h> definition; I think 'struct pt_watch_regs' is a good
> >>>     candidate.  If that test does not succeed, then the configure process
> >>>     fails gracefully stating the minimum released version of kernel headers
> >>>     required.
> >>>
> >>> 2. Add the same test, except in the failure case fall back to the internal
> >>>     definitions we already have, wrapped into #ifndef
> >>>     HAVE_STRUCT_PT_WATCH_REGS.
> >>>
> >>> 3. Add the same test and disable hardware watchpoint support in the
> >>>     failure case.
> >>
> >> I prefer #3.  If 'struct pt_watch_regs' is not defined, hardware watchpoint is
> >> not supported in the kernel.  Because 'struct pt_watch_regs' was added in this
> >> commit in linux kernel,
> >>
> >> commit 0926bf953ee79b8f139741b442e5a18520f81705
> >> Author: David Daney <ddaney@avtrex.com>
> >> Date:   Tue Sep 23 00:11:26 2008 -0700
> >>
> >>     MIPS: Ptrace support for HARDWARE_WATCHPOINTS
> >>
> >>     This is the final part of the watch register patch.  Here we hook up
> >>     ptrace so that the user space debugger (gdb), can set and read the
> >>     registers.
> >>
> >>     Signed-off-by: David Daney <ddaney@avtrex.com>
> >>     Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
> > 
> >  Well, kernel headers bundled with the C library installed on a system GDB 
> > is being built on do not necessarily have to match the kernel binary the 
> > system uses (as is the case with the system I'm using for this validation) 
> > or GDB may be run on another system.  So you cannot infer at the build 
> > time whether the kernel used on a system GDB is going to run on supports 
> > watchpoints until you actually query the kernel at the run time; you need 
> > to do a run-time check anyway as hardware may not even if the kernel will.
> > 
> >  Therefore I think my question here is a matter of policy in GDB rather 
> > than limitations posed by a system in a given configuration.  Which makes 
> > your preference valid, although not for the reason you stated.
> 
> We don't have a written or very fixed policy, afaik.
> 
> For new ports, we try to push back on adding such fallback definitions,
> in order push the submitter into actually adding them to their
> right place (the kernel headers). (otherwise, it's been somewhat common
> that the defines don't actually make it there!  E.g., PT_TEXT_ADDR
> and friends...)  Then, we prefer assuming minimum kernel headers version
> the first released version with all the necessary bits for the port.

 That's pretty straightforward a case, agreed, especially as the same 
kernel has to know the definitions for its own use anyway.

> For new features, things get a bit more blurry.
> 
> Given kernel headers guarantee backwards compatibility, it's my
> understanding that you should always be able to build against the
> latest kernel headers, even if you're running against an old kernel.

 Well, the rule isn't exactly that -- the rule is the kernel headers 
installed in the system for use by user programs must be exactly those the 
C library (typically glibc) has been built against.  Otherwise all hell is 
bound to break loose.  Of course not everyone is prepared to build their 
own C library, and we cannot expect one to be.

 Actually the case is I believe even more complicated.  The rule expressed 
by Linus as I remember it used to be not to make use of the kernel headers 
in user programs at all.  Any definitions and declarations required for 
user programs were expected to be either folded into the relevant C 
library headers (e.g. glibc frequently chooses <bits/foo.h> for such 
stuff), or bundled with the piece of user software that relies on the 
relevant subsystem (that used to be the case with the more obscure stuff, 
e.g. all the programs relying on the netlink stuff used to do that, and 
perhaps still do).

 What we currently have in GDB with regard to MIPS hardware watchpoint 
functionality carefully follows the second choice.  Now times are changing 
and I reckon over the years a project has been under way to split the 
kernel headers into a strictly internal set and an exported user-ABI set, 
with the latter intended to make user program developers' lives easier.  
I haven't tracked progress there and I don't know offhand how far the 
project has gone, but unless you have a better knowledge of what the 
situation is there and can give good counterarguments, we certainly have 
to be careful especially with such an old Linux port the MIPS one is.

> ISTR that's how CS builds things.  However, naturally not everyone
> will do that.  Most will rely on the system's kernel version's
> headers.

 Well, with my upstream reviewer's hat on I try to avoid assuming one's 
build environment is going to be as sophisticated as one used by those who 
professionally work on toolchain components.  The minimal and probably 
still typical recipe of a random developer or even system administrator 
out there roughly is:

$ ./configure && make && make install

and I think our objective is to make this as smooth as possible, avoiding 
making people pull their hair.  Professional software packagers will cope 
either way, we don't need to care that much about them.

> Weighing the maintenance cost of a autoconf glue plus #ifdefs
> around the feature's code, vs defining a couple fallback constants
> ourselves, I'd say the latter is simpler and less effort, thus my
> preference.  If we're talking about a set of missing complicated
> structure definitions, then I may have the opposite opinion.

 In principle I agree, however as I noted above, regrettably the history 
of the Linux user API has not made this choice any more obvious or easier.

> In this case, I was borderline when I initially reviewed the
> Daney's watchpoints's code, but I accepted it then.  Given they're
> already in place, it just sounds like causing unnecessary trouble
> to me to remove them, more so you've shown an example where they're
> necessary.  I'd vote for keeping them.  Supposedly, MAX_DEBUG_REGISTER
> or some other convenient define was added to the kernel's asm/ptrace.h
> at the same time as struct pt_watch_regs etc, so we could
> still include asm/ptrace.h, and only define the fallbacks if
> that such macro is not defined?

 We have the choice between PTRACE_GET_WATCH_REGS and 
PTRACE_SET_WATCH_REGS only here, there have been no other macros added 
with the Linux commit 0926bf953ee79b8f139741b442e5a18520f81705 Yao 
referred to above.  The change regrettably has the maximum architectural 
number of watchpoint register sets possible to implement in hardware 
hardcoded throughout as literal 8 rather than using a macro like our 
MAX_DEBUG_REGISTER (a misnomer actually, as I noted elsewhere).

 Overall, I wonder if it's not <sys/ptrace.h> actually all of this header 
stuff should be moved to, hmm.

  Maciej


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-06-20 17:50           ` Joel Brobecker
@ 2013-06-21  8:03             ` Maciej W. Rozycki
  2013-06-21 15:55               ` Joel Brobecker
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-06-21  8:03 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Yao Qi, gdb-patches

On Thu, 20 Jun 2013, Joel Brobecker wrote:

> > > If we put the prototypes into a single line, the length exceeds the
> > > 74-character limit.  This is the reason I moved parameter "set" to a new line.
> > > Shall we keep them as what they are now?
> > 
> >  There's no 74-character limit for code, all you need is to stay
> >  within 79 columns.  Did you apply the ChangeLog rule here?
> 
> Actually, the last time we discussed maximum code line length,
> we settled on 70 characters.
> 
> Reference: http://www.sourceware.org/ml/gdb-patches/2011-01/msg00035.html

 Hmm, interesting, thanks for your input.

 However I find Mark's observation more focused on comments than actual 
code.  And I tend to agree there, I find reading comments more like 
reading e-mail, they seem to get harder to parse as they get close to 
reaching the right margin and as you may have noticed not only I try to 
keep lines shorter in comments than in code but I try to make paragraphs 
have a good look as well (I sometimes use synonyms, try to substitute 
words or rephrase sentences if the formatting renders bad otherwise).

> It's not consistent across files; for instance, it's 74 characters
> in ChangeLogs. Those limits are kind of arbitrary, but I do find 79
> characters to be slightly harder to read. Jan recently opened that
> discussion again, and proposed 80 characters, but that did not stick.

 I think 80 is dangerous.  Even though CRT (let alone hardcopy) terminals 
are virtually gone (they often truncated rather than wrapped oversize 
lines, at least by default), it's still the canonical line width on many 
terminal emulations and I think many people stick to that.  And operations 
on the last column can yield odd effects with some combinations of a text 
editor and a terminal emulation.  It's even worse if the line is the last 
one on the screen -- some terminals havebeen unable to put a character 
there without issuing a line feed at the same time, making all the screen 
contents scroll away by one line (which is why ncurses have some hacks 
around the last character in the last line too and some full-screen 
programs avoid printing anything there).

 Therefore I think it's simply safer to stay away from the last character, 
except in justified special circumstances (e.g. owing to long statements 
and a syntax different to C with TCL programs I often find it hard to get 
good formatting results where split lines are involved).

> I proposed to standardize on 74 instead, which is already the default
> for some editors and the value used for ChangeLogs. But the discussion
> then died. I'm not too surprised, since it's impossible to please
> everybody, and controversial changes in the GDB porject have a tendency
> of getting stuck.

 All the free software projects I have ever participated in in some way, 
including all the FSF projects and the Linux kernel in particular, seemed 
just to require code lines to fit on a single terminal line, with column 
#80 typically being a taboo as noted above.  I've been wondering whether a 
rule has been written down somewhere for FSF software and checked:

http://www.gnu.org/prep/standards/html_node/Formatting.html

but that doesn't say anything specific.  In the next step I have found out 
that `indent -gnu' sets the line width to 78, that may be indicative, 
however the page referred to above explicitly says any `indent' settings 
are merely recommendations for projects, not hard requirements.

 Personally I think a limit of 74 columns (which is a distance of 6 
characters from the right margin on an 80-column terminal) is somewhat 
difficult to handle in practice, because you have to manually verify each 
individual line is not wider than that (the editor may aid you with that, 
but typically you need to check each line individually, by moving the 
cursor there).  OTOH with the limit of 79 (or maybe 78) characters you can 
see right away by merely looking at a screenful of code if any lines are 
out of the limit, because the distance of 1 or 2 characters from the right 
margin is easily judged by the eye.

 FWIW and IMHO.

  Maciej


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

* Re: [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-20 20:45           ` Maciej W. Rozycki
@ 2013-06-21 14:58             ` Pedro Alves
  0 siblings, 0 replies; 52+ messages in thread
From: Pedro Alves @ 2013-06-21 14:58 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Yao Qi, gdb-patches

On 06/20/2013 09:42 PM, Maciej W. Rozycki wrote:
> On Thu, 20 Jun 2013, Pedro Alves wrote:

>> For new features, things get a bit more blurry.
>>
>> Given kernel headers guarantee backwards compatibility, it's my
>> understanding that you should always be able to build against the
>> latest kernel headers, even if you're running against an old kernel.
> 
>  Well, the rule isn't exactly that -- the rule is the kernel headers 
> installed in the system for use by user programs must be exactly those the 
> C library (typically glibc) has been built against.  Otherwise all hell is 
> bound to break loose.  

Ah.  Yeah, that was it.

> Of course not everyone is prepared to build their 
> own C library, and we cannot expect one to be.

Certainly.

>  Actually the case is I believe even more complicated.  The rule expressed 
> by Linus as I remember it used to be not to make use of the kernel headers 
> in user programs at all.  Any definitions and declarations required for 
> user programs were expected to be either folded into the relevant C 
> library headers (e.g. glibc frequently chooses <bits/foo.h> for such 
> stuff), or bundled with the piece of user software that relies on the 
> relevant subsystem (that used to be the case with the more obscure stuff, 
> e.g. all the programs relying on the netlink stuff used to do that, and 
> perhaps still do).
> 
>  What we currently have in GDB with regard to MIPS hardware watchpoint 
> functionality carefully follows the second choice.  Now times are changing 
> and I reckon over the years a project has been under way to split the 
> kernel headers into a strictly internal set and an exported user-ABI set, 
> with the latter intended to make user program developers' lives easier.  

Yeah, I'm aware of that UAPI header split project as well.
I'd sooner believe we ended up with the structs in GDB because of the desire
to use the feature in GDB with an updated kernel, but not an updated libc
(Daney did the kernel side bits, afterall), rather than due to special
care to follow the second choice, though.

> I haven't tracked progress there and I don't know offhand how far the 
> project has gone, but unless you have a better knowledge of what the 
> situation is there and can give good counterarguments, we certainly have 
> to be careful especially with such an old Linux port the MIPS one is.

No special knowledge, but I wasn't arguing for not being
careful either.

>> ISTR that's how CS builds things.  However, naturally not everyone
>> will do that.  Most will rely on the system's kernel version's
>> headers.
> 
>  Well, with my upstream reviewer's hat on I try to avoid assuming one's 
> build environment is going to be as sophisticated as one used by those who 
> professionally work on toolchain components.  The minimal and probably 
> still typical recipe of a random developer or even system administrator 
> out there roughly is:
> 
> $ ./configure && make && make install

Certainly.  The details were escaping me, but indeed I was thinking
of glibc building.

> 
> and I think our objective is to make this as smooth as possible, avoiding 
> making people pull their hair.  Professional software packagers will cope 
> either way, we don't need to care that much about them.

*nod*

>> In this case, I was borderline when I initially reviewed the
>> Daney's watchpoints's code, but I accepted it then.  Given they're
>> already in place, it just sounds like causing unnecessary trouble
>> to me to remove them, more so you've shown an example where they're
>> necessary.  I'd vote for keeping them.  Supposedly, MAX_DEBUG_REGISTER
>> or some other convenient define was added to the kernel's asm/ptrace.h
>> at the same time as struct pt_watch_regs etc, so we could
>> still include asm/ptrace.h, and only define the fallbacks if
>> that such macro is not defined?
> 
>  We have the choice between PTRACE_GET_WATCH_REGS and 
> PTRACE_SET_WATCH_REGS only here, there have been no other macros added 
> with the Linux commit 0926bf953ee79b8f139741b442e5a18520f81705 Yao 
> referred to above.

Looks like those are good enough to me.  I notice the code added to GDB does:

#ifndef PTRACE_GET_WATCH_REGS
#  define PTRACE_GET_WATCH_REGS 0xd0
#endif

#ifndef PTRACE_SET_WATCH_REGS
#  define PTRACE_SET_WATCH_REGS 0xd1
#endif

and only does that #ifndef dance in those two particular macros...

But I'd hope that was more an historical accident than the case
of Daney finding a system with conflicting PTRACE_GET/SET_WATCH_REGS
definitions (and no corresponding structs)...

> The change regrettably has the maximum architectural
> number of watchpoint register sets possible to implement in hardware 
> hardcoded throughout as literal 8 rather than using a macro like our 
> MAX_DEBUG_REGISTER (a misnomer actually, as I noted elsewhere).

Yeah, to make that accept anything but 8, we'd have to change
the struct's layouts.  Could have worked for SET without breaking
the ABI if num_valid was the first field in the struct, alas,
it isn't...  For GET, we'd be stuck anyway, as the caller would
have no indication of the size of the struct the kernel would fill
in.  As is, MAX_DEBUG_REGISTER is just an ABI array length constant.

-- 
Pedro Alves


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

* Re: [PATCH 3/3] MIPS h/w watchpoint in GDBserver
  2013-06-19 22:22     ` Maciej W. Rozycki
@ 2013-06-21 15:00       ` Pedro Alves
  0 siblings, 0 replies; 52+ messages in thread
From: Pedro Alves @ 2013-06-21 15:00 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Yao Qi, gdb-patches

(I found myself reading this again, )

On 06/19/2013 11:05 PM, Maciej W. Rozycki wrote:
>> > +  ** GDBserver now supports hardware watchpoint on mips GNU/Linux target.

and noticed a typo here:

s/watchpoint/watchpoints/

(I'd also suggest either "on the MIPS ... target", or on "MIPS ... targets").

-- 
Pedro Alves


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

* Re: [PATCH 2/3] Move mips hardware watchpoint stuff to common/
  2013-06-21  8:03             ` Maciej W. Rozycki
@ 2013-06-21 15:55               ` Joel Brobecker
  0 siblings, 0 replies; 52+ messages in thread
From: Joel Brobecker @ 2013-06-21 15:55 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Yao Qi, gdb-patches

>  FWIW and IMHO.

What you say makes sense to me, and I would agree to an update.
I do think that we should try to standardize to a minimum number
of lengths. For new, we have two kinds of "text":
  - Documentation/comments
  - Code

I'd agree to 78 or 79 for code, and I've often found that the extra
length would allow a statement to fit on fewer lines, looking and
reading better. I would add that I've always felt that 70 was a soft
limit, and that people should feel free to extend when needed.

For documentation, I would have stayed with 70, except that ChangeLog
files can be considered code. I'm wondering if we could try 74 instead.

FWIW and IMHO as well :). The problem with those types of discussions
that people tend to discuss them a lot, but then it's hard to actually
make any decision. I'll say I'm flexible - and actually have been
already wrt past code reviews. I think of this "rule" more as a
guideline, rather than a hard rule.

-- 
Joel


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

* [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver.
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
                     ` (2 preceding siblings ...)
  2013-06-29  3:11   ` [PATCH 5/5] MIPS GDBserver watchpoint Yao Qi
@ 2013-06-29  3:11   ` Yao Qi
  2013-07-24  0:26     ` Maciej W. Rozycki
  2013-06-29  8:01   ` [PATCH 4/5] Move mips hardware watchpoint stuff to common/ Yao Qi
  2013-07-22  1:11   ` [PATCH v2 0/5] mips hardware watchpoint support in gdbserver Yao Qi
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-29  3:11 UTC (permalink / raw)
  To: gdb-patches

Hi,
'enum target_hw_bp_type' has been used in both GDB and GDBserver.  It
will be used in MIPS hardware watchpoint support too.  This patch
is to share 'enum target_hw_bp_type' in common/break-common.h.

gdb:

2013-06-29  Yao Qi  <yao@codesourcery.com>

	* breakpoint.h: Include break-common.h.
	(enum target_hw_bp_type): Move to ...
	* common/break-common.h: ... here.  New.

gdb/gdbserver:

2013-06-29  Yao Qi  <yao@codesourcery.com>

	* i386-low.c: Include break-common.h.
	(enum target_hw_bp_type): Remove.
---
 gdb/breakpoint.h          |   10 +---------
 gdb/common/break-common.h |   30 ++++++++++++++++++++++++++++++
 gdb/gdbserver/i386-low.c  |    9 +--------
 3 files changed, 32 insertions(+), 17 deletions(-)
 create mode 100644 gdb/common/break-common.h

diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 19961fe..c82bc71 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -24,6 +24,7 @@
 #include "vec.h"
 #include "ax.h"
 #include "command.h"
+#include "break-common.h"
 
 struct value;
 struct block;
@@ -215,15 +216,6 @@ enum bpdisp
     disp_donttouch		/* Leave it alone */
   };
 
-enum target_hw_bp_type
-  {
-    hw_write   = 0, 		/* Common  HW watchpoint */
-    hw_read    = 1, 		/* Read    HW watchpoint */
-    hw_access  = 2, 		/* Access  HW watchpoint */
-    hw_execute = 3		/* Execute HW breakpoint */
-  };
-
-
 /* Status of breakpoint conditions used when synchronizing
    conditions with the target.  */
 
diff --git a/gdb/common/break-common.h b/gdb/common/break-common.h
new file mode 100644
index 0000000..16ed0e2
--- /dev/null
+++ b/gdb/common/break-common.h
@@ -0,0 +1,30 @@
+/* Data structures associated with breakpoints shared in both GDB and
+   GDBserver.
+   Copyright (C) 1992-2013 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 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/>.  */
+#ifndef BREAK_COMMON_H
+#define BREAK_COMMON_H 1
+
+enum target_hw_bp_type
+  {
+    hw_write   = 0, 		/* Common  HW watchpoint */
+    hw_read    = 1, 		/* Read    HW watchpoint */
+    hw_access  = 2, 		/* Access  HW watchpoint */
+    hw_execute = 3		/* Execute HW breakpoint */
+  };
+
+#endif
diff --git a/gdb/gdbserver/i386-low.c b/gdb/gdbserver/i386-low.c
index 86ec5d8..4eacda0 100644
--- a/gdb/gdbserver/i386-low.c
+++ b/gdb/gdbserver/i386-low.c
@@ -20,6 +20,7 @@
 #include "server.h"
 #include "target.h"
 #include "i386-low.h"
+#include "break-common.h"
 
 /* Support for 8-byte wide hw watchpoints.  */
 #ifndef TARGET_HAS_DR_LEN_8
@@ -27,14 +28,6 @@
 #define TARGET_HAS_DR_LEN_8 (sizeof (void *) == 8)
 #endif
 
-enum target_hw_bp_type
-  {
-    hw_write   = 0,	/* Common  HW watchpoint */
-    hw_read    = 1,	/* Read    HW watchpoint */
-    hw_access  = 2,	/* Access  HW watchpoint */
-    hw_execute = 3	/* Execute HW breakpoint */
-  };
-
 /* DR7 Debug Control register fields.  */
 
 /* How many bits to skip in DR7 to get to R/W and LEN fields.  */
-- 
1.7.7.6


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

* [PATCH 3/5] Refactor in mips-linux-nat.c
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
  2013-06-29  3:11   ` [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
@ 2013-06-29  3:11   ` Yao Qi
  2013-07-24  0:27     ` Maciej W. Rozycki
  2013-06-29  3:11   ` [PATCH 5/5] MIPS GDBserver watchpoint Yao Qi
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-29  3:11 UTC (permalink / raw)
  To: gdb-patches

Hi,
this patch renames some functions and parameters, to pave the way for
the way for the next patch.

gdb:

2013-06-29  Yao Qi  <yao@codesourcery.com>

	* mips-linux-nat.c (get_irw_mask): Rename to ...
	(mips_linux_watch_get_irw_mask): ... this.  Rename parameter
	'set' to 'n'.  Update function comment.  All callers changed.
	(get_reg_mask): Rename parameter 'set' to 'n'.  Update function
	comment.  All callers changed.
	(get_num_valid): Rename to ...
	(mips_linux_watch_get_num_valid): ... this.  Rename parameter
	'set' to 'n'.  Update function comment.  All callers changed.
	(get_watchlo): Rename to ...
	(mips_linux_watch_get_watchlo): ... this.  Rename parameter 'set'
	to 'n'.  Update function comment.  All callers changed.
	(set_watchlo): Rename to ...
	(mips_linux_watch_set_watchlo): ... this.  Rename parameter 'set'
	to 'n'.  Update function comment.  All callers changed.
	(get_watchhi): Rename to ...
	(mips_linux_watch_get_watchhi): ... this.  Update function
	comment.  All callers changed.
	(set_watchhi): Rename to ...
	(mips_linux_watch_set_watchhi): ... this.  Update function
	comment.  All callers changed.
	(mips_linux_read_watch_registers): Update function comment.
	Add new parameters 'lwpid', 'watch_readback', and
	'watch_readback_valid'.  Update.
	(type_to_irw): Rename to ...
	(mips_linux_watch_type_to_irw): ... this.  Update function
	comment.  All callers changed.
	(fill_mask): Update function comment.
	(try_one_watch): Rename to ...
	(mips_linux_watch_try_one_watch): ... this.  Change the type of
	parameter 'irw' from 'unsigned' to 'uint32_t'.
	(populate_regs_from_watches): Rename to ...
	(mips_linux_watch_populate_regs): ... this.  Add parameter
	'current_watches'.  All callers changed.
---
 gdb/mips-linux-nat.c |  208 +++++++++++++++++++++++++++++---------------------
 1 files changed, 121 insertions(+), 87 deletions(-)

diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index 44d23a6..af70945 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -559,44 +559,46 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers, return the irw_mask.  */
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
 
 static uint32_t
-get_irw_mask (struct pt_watch_regs *regs, int set)
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & IRW_MASK;
+      return regs->mips32.watch_masks[n] & IRW_MASK;
     case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & IRW_MASK;
+      return regs->mips64.watch_masks[n] & IRW_MASK;
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unrecognized watch register style"));
     }
 }
 
-/* Assuming usable watch registers, return the reg_mask.  */
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
 
 static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int set)
+get_reg_mask (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & ~IRW_MASK;
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
     case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & ~IRW_MASK;
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unrecognized watch register style"));
     }
 }
 
-/* Assuming usable watch registers, return the num_valid.  */
+/* Assuming usable watch registers REGS, return the num_valid.  */
 
 static uint32_t
-get_num_valid (struct pt_watch_regs *regs)
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
 {
   switch (regs->style)
     {
@@ -610,37 +612,40 @@ get_num_valid (struct pt_watch_regs *regs)
     }
 }
 
-/* Assuming usable watch registers, return the watchlo.  */
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
 
 static CORE_ADDR
-get_watchlo (struct pt_watch_regs *regs, int set)
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
-      return regs->mips32.watchlo[set];
+      return regs->mips32.watchlo[n];
     case pt_watch_style_mips64:
-      return regs->mips64.watchlo[set];
+      return regs->mips64.watchlo[n];
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unrecognized watch register style"));
     }
 }
 
-/* Assuming usable watch registers, set a watchlo value.  */
+/* Assuming usable watch registers REGS, set VALUE to watchlo of
+   register N.  */
 
 static void
-set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
       /*  The cast will never throw away bits as 64 bit addresses can
 	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[set] = (uint32_t)value;
+      regs->mips32.watchlo[n] = (uint32_t) value;
       break;
     case pt_watch_style_mips64:
-      regs->mips64.watchlo[set] = value;
+      regs->mips64.watchlo[n] = value;
       break;
     default:
       internal_error (__FILE__, __LINE__,
@@ -648,10 +653,11 @@ set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
     }
 }
 
-/* Assuming usable watch registers, return the watchhi.  */
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
 
 static uint32_t
-get_watchhi (struct pt_watch_regs *regs, int n)
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
@@ -665,10 +671,12 @@ get_watchhi (struct pt_watch_regs *regs, int n)
     }
 }
 
-/* Assuming usable watch registers, set a watchhi value.  */
+/* Assuming usable watch registers REGS, set VALUE to watchhi of
+   register N.  */
 
 static void
-set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
 {
   switch (regs->style)
     {
@@ -704,57 +712,60 @@ mips_show_dr (const char *func, CORE_ADDR addr,
   for (i = 0; i < MAX_DEBUG_REGISTER; i++)
     printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
 		       paddress (target_gdbarch (),
-				 get_watchlo (&watch_mirror, i)),
+				 mips_linux_watch_get_watchlo (&watch_mirror,
+							       i)),
 		       paddress (target_gdbarch (),
-				 get_watchhi (&watch_mirror, i)));
+				 mips_linux_watch_get_watchhi (&watch_mirror,
+							       i)));
 }
 
-/* Return 1 if watch registers are usable.  Cached information is used
-   unless force is true.  */
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
 
 static int
-mips_linux_read_watch_registers (int force)
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
 {
-  int tid;
-
-  if (force || watch_readback_valid == 0)
+  if (force || *watch_readback_valid == 0)
     {
-      tid = ptid_get_lwp (inferior_ptid);
-      if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
 	{
-	  watch_readback_valid = -1;
+	  *watch_readback_valid = -1;
 	  return 0;
 	}
-      switch (watch_readback.style)
+      switch (watch_readback->style)
 	{
 	case pt_watch_style_mips32:
-	  if (watch_readback.mips32.num_valid == 0)
+	  if (watch_readback->mips32.num_valid == 0)
 	    {
-	      watch_readback_valid = -1;
+	      *watch_readback_valid = -1;
 	      return 0;
 	    }
 	  break;
 	case pt_watch_style_mips64:
-	  if (watch_readback.mips64.num_valid == 0)
+	  if (watch_readback->mips64.num_valid == 0)
 	    {
-	      watch_readback_valid = -1;
+	      *watch_readback_valid = -1;
 	      return 0;
 	    }
 	  break;
 	default:
-	  watch_readback_valid = -1;
+	  *watch_readback_valid = -1;
 	  return 0;
 	}
       /* Watch registers appear to be usable.  */
-      watch_readback_valid = 1;
+      *watch_readback_valid = 1;
     }
-  return (watch_readback_valid == 1) ? 1 : 0;
+  return (*watch_readback_valid == 1) ? 1 : 0;
 }
 
-/* Convert GDB's type to an IRW mask.  */
+/* Convert GDB's TYPE to an IRW mask.  */
 
-static unsigned
-type_to_irw (int type)
+static uint32_t
+mips_linux_watch_type_to_irw (int type)
 {
   switch (type)
     {
@@ -778,7 +789,9 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
   int i;
   uint32_t wanted_mask, irw_mask;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
    switch (type)
@@ -796,9 +809,11 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
       return 0;
     }
  
-  for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
+  for (i = 0;
+       i < mips_linux_watch_get_num_valid (&watch_readback) && cnt;
+       i++)
     {
-      irw_mask = get_irw_mask (&watch_readback, i);
+      irw_mask = mips_linux_watch_get_irw_mask (&watch_readback, i);
       if ((irw_mask & wanted_mask) == wanted_mask)
 	cnt--;
     }
@@ -815,13 +830,15 @@ mips_linux_stopped_by_watchpoint (void)
   int n;
   int num_valid;
 
-  if (!mips_linux_read_watch_registers (1))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 1))
     return 0;
 
-  num_valid = get_num_valid (&watch_readback);
+  num_valid = mips_linux_watch_get_num_valid (&watch_readback);
 
   for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
-    if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
+    if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
       return 1;
 
   return 0;
@@ -839,7 +856,7 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in mask that are not set.  */
+/* Set any low order bits in MASK that are not set.  */
 
 static CORE_ADDR
 fill_mask (CORE_ADDR mask)
@@ -853,15 +870,16 @@ fill_mask (CORE_ADDR mask)
   return mask;
 }
 
-/* Try to add a single watch to the specified registers.  Return 1 on
-   success, 0 on failure.  */
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
 
 static int
-try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
-	       int len, unsigned irw)
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, uint32_t irw)
 {
   CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low, t_low_end;
+  CORE_ADDR mask_bits, t_low;
   uint16_t t_hi;
   int i, free_watches;
   struct pt_watch_regs regs_copy;
@@ -874,29 +892,31 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
   base_addr = addr & ~mask_bits;
 
   /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < get_num_valid (regs); i++)
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
     {
-      t_low = get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((unsigned)t_low & irw))
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
 	{
-	  t_hi = get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR)t_hi;
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
 	  if (addr >= t_low && last_byte <= (t_low + t_hi))
 	    return 1;
 	}
     }
   /* Try to find an empty register.  */
   free_watches = 0;
-  for (i = 0; i < get_num_valid (regs); i++)
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
     {
-      t_low = get_watchlo (regs, i);
-      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
 	{
 	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
 	    {
 	      /* It fits, we'll take it.  */
-	      set_watchlo (regs, i, base_addr | irw);
-	      set_watchhi (regs, i, mask_bits & ~IRW_MASK);
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i,
+					    mask_bits & ~IRW_MASK);
 	      return 1;
 	    }
 	  else
@@ -910,21 +930,25 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
     {
       /* Try to split it across several registers.  */
       regs_copy = *regs;
-      for (i = 0; i < get_num_valid (&regs_copy); i++)
+      for (i = 0;
+	   i < mips_linux_watch_get_num_valid (&regs_copy);
+	   i++)
 	{
-	  t_low = get_watchlo (&regs_copy, i);
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
 	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
 	  if (t_low == 0 && irw == (t_hi & irw))
 	    {
-	      t_low = addr & ~(CORE_ADDR)t_hi;
+	      t_low = addr & ~(CORE_ADDR) t_hi;
 	      break_addr = t_low + t_hi + 1;
 	      if (break_addr >= addr + len)
 		segment_len = len;
 	      else
 		segment_len = break_addr - addr;
 	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      set_watchlo (&regs_copy, i, (addr & ~mask_bits) | irw);
-	      set_watchhi (&regs_copy, i, mask_bits & ~IRW_MASK);
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
 	      if (break_addr >= addr + len)
 		{
 		  *regs = regs_copy;
@@ -948,17 +972,18 @@ mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
   struct pt_watch_regs dummy_regs;
   int i;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
   dummy_regs = watch_readback;
   /* Clear them out.  */
-  for (i = 0; i < get_num_valid (&dummy_regs); i++)
-    set_watchlo (&dummy_regs, i, 0);
-  return try_one_watch (&dummy_regs, addr, len, 0);
+  for (i = 0; i < mips_linux_watch_get_num_valid (&dummy_regs); i++)
+    mips_linux_watch_set_watchlo (&dummy_regs, i, 0);
+  return mips_linux_watch_try_one_watch (&dummy_regs, addr, len, 0);
 }
 
-
 /* Write the mirrored watch register values for each thread.  */
 
 static int
@@ -984,7 +1009,9 @@ mips_linux_new_thread (struct lwp_info *lp)
 {
   int tid;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return;
 
   tid = ptid_get_lwp (lp->ptid);
@@ -992,25 +1019,29 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers with the currently cached watches.  */
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
 
 static void
-populate_regs_from_watches (struct pt_watch_regs *regs)
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
 {
   struct mips_watchpoint *w;
   int i;
 
   /* Clear them out.  */
-  for (i = 0; i < get_num_valid (regs); i++)
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
     {
-      set_watchlo (regs, i, 0);
-      set_watchhi (regs, i, 0);
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
     }
 
   w = current_watches;
   while (w)
     {
-      i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
+      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
       /* They must all fit, because we previously calculated that they
 	 would.  */
       gdb_assert (i);
@@ -1032,7 +1063,9 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
   int i;
   int retval;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return -1;
 
   if (len <= 0)
@@ -1040,10 +1073,11 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
 
   regs = watch_readback;
   /* Add the current watches.  */
-  populate_regs_from_watches (&regs);
+  mips_linux_watch_populate_regs (current_watches, &regs);
 
   /* Now try to add the new watch.  */
-  if (!try_one_watch (&regs, addr, len, type_to_irw (type)))
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
+				       mips_linux_watch_type_to_irw (type)))
     return -1;
 
   /* It fit.  Stick it on the end of the list.  */
@@ -1105,7 +1139,7 @@ mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
   gdb_assert (watch_readback_valid == 1);
 
   watch_mirror = watch_readback;
-  populate_regs_from_watches (&watch_mirror);
+  mips_linux_watch_populate_regs (current_watches, &watch_mirror);
 
   retval = write_watchpoint_regs ();
 
-- 
1.7.7.6


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

* [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
@ 2013-06-29  3:11   ` Yao Qi
  2013-07-24  0:26     ` Maciej W. Rozycki
  2013-06-29  3:11   ` [PATCH 3/5] Refactor " Yao Qi
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-29  3:11 UTC (permalink / raw)
  To: gdb-patches

Hi,
This patch is to include asm/ptrace.h in mips-linux-nat.c and wrap
some structures by "ifndef PTRACE_GET_WATCH_REGS" and "#endif" as a
fallback if watchpoint-related structures are not defined in kernel
header.

gdb:

2013-06-29  Yao Qi  <yao@codesourcery.com>

	* mips-linux-nat.c (MAX_DEBUG_REGISTER): Move it earlier in
	the code.
	(enum pt_watch_style): Remove.
	(struct mips32_watch_regs, struct mips64_watch_regs): Remove.
	(struct pt_watch_regs): Likewise.
	[!PTRACE_GET_WATCH_REGS] (enum pt_watch_style): New.
	[!PTRACE_GET_WATCH_REGS] (struct mips32_watch_regs): New.
	[!PTRACE_GET_WATCH_REGS] (struct mips64_watch_regs): New.
	[!PTRACE_GET_WATCH_REGS] (struct pt_watch_regs): New.
---
 gdb/mips-linux-nat.c |   39 ++++++++++++++++++++++-----------------
 1 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index d323a82..44d23a6 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -34,6 +34,7 @@
 
 #include <sgidefs.h>
 #include <sys/ptrace.h>
+#include <asm/ptrace.h>
 
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
@@ -460,31 +461,19 @@ mips_linux_read_description (struct target_ops *ops)
     return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
 }
 
-#ifndef PTRACE_GET_WATCH_REGS
-#  define PTRACE_GET_WATCH_REGS	0xd0
-#endif
-
-#ifndef PTRACE_SET_WATCH_REGS
-#  define PTRACE_SET_WATCH_REGS	0xd1
-#endif
-
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
+#define MAX_DEBUG_REGISTER 8
 
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
+/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
+   have hardware watchpoint-related structures.  Define them below.  */
 
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+#ifndef PTRACE_GET_WATCH_REGS
+#  define PTRACE_GET_WATCH_REGS	0xd0
 
 enum pt_watch_style {
   pt_watch_style_mips32,
   pt_watch_style_mips64
 };
 
-#define MAX_DEBUG_REGISTER 8
-
 /* A value of zero in a watchlo indicates that it is available.  */
 
 struct mips32_watch_regs
@@ -524,6 +513,22 @@ struct pt_watch_regs
   };
 };
 
+#endif
+
+#ifndef PTRACE_SET_WATCH_REGS
+#  define PTRACE_SET_WATCH_REGS	0xd1
+#endif
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
-- 
1.7.7.6


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

* [PATCH 5/5] MIPS GDBserver watchpoint
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
  2013-06-29  3:11   ` [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
  2013-06-29  3:11   ` [PATCH 3/5] Refactor " Yao Qi
@ 2013-06-29  3:11   ` Yao Qi
  2013-06-29 15:20     ` Eli Zaretskii
                       ` (2 more replies)
  2013-06-29  3:11   ` [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver Yao Qi
                     ` (2 subsequent siblings)
  5 siblings, 3 replies; 52+ messages in thread
From: Yao Qi @ 2013-06-29  3:11 UTC (permalink / raw)
  To: gdb-patches

Hi,
This patch adds the mips hardware watchpoint support in GDBserver.

gdb/gdbserver:

2013-06-29  Jie Zhang  <jie@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>
	    Yao Qi  <yao@codesourcery.com>

	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
	(mips_linux_watch_h): New.
	(mips-linux-watch.o): New rule.
	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to
	srv_tgtobj.
	* linux-mips-low.c: Include mips-linux-watch.h.
	(struct arch_process_info, struct arch_lwp_info): New.
	(update_watch_registers_callback): New.
	(mips_linux_new_process, mips_linux_new_thread) New.
	(mips_linux_prepare_to_resume, mips_insert_point): New.
	(mips_remove_point, mips_stopped_by_watchpoint): New.
	(rsp_bp_type_to_target_hw_bp_type): New.
	(mips_stopped_data_address): New.
	(the_low_target): Add watchpoint support functions.

gdb:

2013-06-29  Yao Qi  <yao@codesourcery.com>

	* NEWS: Mention it.
---
 gdb/NEWS                       |    3 +
 gdb/gdbserver/Makefile.in      |    7 +-
 gdb/gdbserver/configure.srv    |    1 +
 gdb/gdbserver/linux-mips-low.c |  366 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 376 insertions(+), 1 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index e469f1e..daf02ff 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -123,6 +123,9 @@ qXfer:libraries-svr4:read's annex
      'qXfer:traceframe-info:read'.  It has the id of the collected
      trace state variables.
 
+  ** GDBserver now supports hardware watchpoints on the MIPS GNU/Linux
+     target.
+
 *** Changes in GDB 7.6
 
 * Target record has been renamed to record-full.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index e5ecdd3..32e52c0 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -157,7 +157,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
 	$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
 	$(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \
-	$(srcdir)/common/filestuff.c
+	$(srcdir)/common/filestuff.c $(srcdir)/common/mips-linux-watch.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -457,6 +457,8 @@ lynx_low_h = $(srcdir)/lynx-low.h $(srcdir)/server.h
 
 nto_low_h = $(srcdir)/nto-low.h
 
+mips_linux_watch_h = $(srcdir)/../common/mips-linux-watch.h
+
 UST_CFLAGS = $(ustinc) -DCONFIG_UST_GDB_INTEGRATION
 
 # Note, we only build the IPA if -fvisibility=hidden is supported in
@@ -552,6 +554,9 @@ agent.o: ../common/agent.c
 linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
 
+mips-linux-watch.o: ../common/mips-linux-watch.c $(mips_linux_watch_h) $(server_h)
+	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+
 # We build vasprintf with -DHAVE_CONFIG_H because we want that unit to
 # include our config.h file.  Otherwise, some system headers do not get
 # included, and the compiler emits a warning about implicitly defined
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 879d0de..b9dfd6c 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -184,6 +184,7 @@ case "${target}" in
 			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
 			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+			srv_tgtobj="${srv_tgtobj} mips-linux-watch.o"
 			srv_xmlfiles="mips-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml"
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 1010528..6e6e3e0 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -22,6 +22,7 @@
 #include <sys/ptrace.h>
 #include <endian.h>
 
+#include "mips-linux-watch.h"
 #include "gdb_proc_service.h"
 
 /* Defined in auto-generated file mips-linux.c.  */
@@ -159,6 +160,39 @@ get_usrregs_info (void)
   return regs_info->usrregs;
 }
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  /* -1 if the kernel and/or CPU do not support watch registers.
+      1 if watch_readback is valid and we can read style, num_valid
+	and the masks.
+      0 if we need to read the watch_readback.  */
+
+  int watch_readback_valid;
+
+  /* Cached watch register read values.  */
+
+  struct pt_watch_regs watch_readback;
+
+  /* Current watchpoint requests for this process.  */
+
+  struct mips_watchpoint *current_watches;
+
+  /* The current set of watch register values for writing the
+     registers.  */
+
+  struct pt_watch_regs watch_mirror;
+};
+
+/* 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 watch_registers_changed;
+};
+
 /* From mips-linux-nat.c.  */
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
@@ -257,6 +291,328 @@ mips_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Mark the watch registers of lwp, represented by ENTRY, as changed,
+   if the lwp's process id is *PID_P.  */
+
+static int
+update_watch_registers_callback (struct inferior_list_entry *entry,
+				 void *pid_p)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  int pid = *(int *) pid_p;
+
+  /* Only update the threads of this process.  */
+  if (pid_of (lwp) == pid)
+    {
+      /* The actual update is done later just before resuming the lwp,
+	 we just mark that the registers need updating.  */
+      lwp->arch_private->watch_registers_changed = 1;
+
+      /* If the lwp isn't stopped, force it to momentarily pause, so
+	 we can update its watch registers.  */
+      if (!lwp->stopped)
+	linux_stop_lwp (lwp);
+    }
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   new_process.  */
+
+static struct arch_process_info *
+mips_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method new_thread.
+   Mark the watch registers as changed, so the threads' copies will
+   be updated.  */
+
+static struct arch_lwp_info *
+mips_linux_new_thread (void)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->watch_registers_changed = 1;
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method
+   prepare_to_resume.  If the watch regs have changed, update the
+   thread's copies.  */
+
+static void
+mips_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  ptid_t ptid = ptid_of (lwp);
+  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
+  struct arch_process_info *private = proc->private->arch_private;
+
+  if (lwp->arch_private->watch_registers_changed)
+    {
+      /* Only update the watch registers if we have set or unset a
+	 watchpoint already.  */
+      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
+	{
+	  /* Write the mirrored watch register values.  */
+	  int tid = ptid_get_lwp (ptid);
+
+	  if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
+			    &private->watch_mirror))
+	    perror_with_name ("Couldn't write watch register");
+	}
+
+      lwp->arch_private->watch_registers_changed = 0;
+    }
+}
+
+/* Translate breakpoint type TYPE in rsp to 'enum target_hw_bp_type'.  Return
+   -1 if translation failed.  */
+
+static enum target_hw_bp_type
+rsp_bp_type_to_target_hw_bp_type (char type)
+{
+  switch (type)
+    {
+    case '2':
+      return hw_write;
+    case '3':
+      return hw_read;
+    case '4':
+      return hw_access;
+    }
+
+  return -1;
+}
+
+/* This is the implementation of linux_target_ops method
+   insert_point.  */
+
+static int
+mips_insert_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  struct pt_watch_regs regs;
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+  int pid;
+  long lwpid;
+  enum target_hw_bp_type watch_type;
+  uint32_t irw;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  lwpid = lwpid_of (get_thread_lwp (current_inferior));
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = private->watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (private->current_watches, &regs);
+
+  /* Now try to add the new watch.  */
+  watch_type = rsp_bp_type_to_target_hw_bp_type (type);
+  irw = mips_linux_watch_type_to_irw (watch_type);
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len, irw))
+    return -1;
+
+  /* It fit.  Stick it on the end of the list.  */
+  new_watch = xmalloc (sizeof (struct mips_watchpoint));
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = watch_type;
+  new_watch->next = NULL;
+
+  pw = &private->current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+
+  private->watch_mirror = regs;
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_watch_registers_callback, &pid);
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   remove_point.  */
+
+static int
+mips_remove_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+
+  int deleted_one;
+  int pid;
+  enum target_hw_bp_type watch_type;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  /* Search for a known watch that matches.  Then unlink and free it.  */
+  watch_type = rsp_bp_type_to_target_hw_bp_type (type);
+  deleted_one = 0;
+  pw = &private->current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == watch_type)
+	{
+	  *pw = w->next;
+	  free (w);
+	  deleted_one = 1;
+	  break;
+	}
+      pw = &(w->next);
+    }
+
+  if (!deleted_one)
+    return -1;  /* We don't know about it, fail doing nothing.  */
+
+  /* At this point watch_readback is known to be valid because we
+     could not have added the watch without reading it.  */
+  gdb_assert (private->watch_readback_valid == 1);
+
+  private->watch_mirror = private->watch_readback;
+  mips_linux_watch_populate_regs (private->current_watches,
+				  &private->watch_mirror);
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_watch_registers_callback, &pid);
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_by_watchpoint.  The watchhi R and W bits indicate
+   the watch register triggered. */
+
+static int
+mips_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					1))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      return 1;
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_data_address.  */
+
+static CORE_ADDR
+mips_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  /* On MIPS we don't know the low order 3 bits of the data address.
+     GDB does not support remote targets that can't report the
+     watchpoint address.  So, make our best guess; return the starting
+     address of a watchpoint request which overlaps the one that
+     triggered.  */
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      {
+	CORE_ADDR t_low, t_hi;
+	int t_irw;
+	struct mips_watchpoint *watch;
+
+	t_low = mips_linux_watch_get_watchlo (&private->watch_readback, n);
+	t_irw = t_low & IRW_MASK;
+	t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+		| IRW_MASK);
+	t_low &= ~(CORE_ADDR)t_hi;
+
+	for (watch = private->current_watches;
+	     watch != NULL;
+	     watch = watch->next)
+	  {
+	    CORE_ADDR addr = watch->addr;
+	    CORE_ADDR last_byte = addr + watch->len - 1;
+
+	    if ((t_irw & mips_linux_watch_type_to_irw (watch->type)) == 0)
+	      {
+		/* Different type.  */
+		continue;
+	      }
+	    /* Check for overlap of even a single byte.  */
+	    if (last_byte >= t_low && addr <= t_low + t_hi)
+	      return addr;
+	  }
+      }
+
+  /* Shouldn't happen.  */
+  return 0;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -506,6 +862,16 @@ struct linux_target_ops the_low_target = {
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
+  mips_insert_point,
+  mips_remove_point,
+  mips_stopped_by_watchpoint,
+  mips_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, /* siginfo_fixup */
+  mips_linux_new_process,
+  mips_linux_new_thread,
+  mips_linux_prepare_to_resume
 };
 
 void
-- 
1.7.7.6


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

* [PATCH v2 0/5] mips hardware watchpoint support in gdbserver
  2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
                   ` (4 preceding siblings ...)
  2013-05-30 18:06 ` Pedro Alves
@ 2013-06-29  3:11 ` Yao Qi
  2013-06-29  3:11   ` [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
                     ` (5 more replies)
  5 siblings, 6 replies; 52+ messages in thread
From: Yao Qi @ 2013-06-29  3:11 UTC (permalink / raw)
  To: gdb-patches

Here is the V2 of this patch series which is to post Jie and Dan's work
to support mips hardware watchpoint in gdbserver.  There are several
changes compared with V1:

 - Keep these watchpoint-related structures as the fall back when
PTRACE_GET_WATCH_REGS is not defined.
 - Re-org the patch series as Maciej suggested, split the function
renaming patch out of the function moving patch.
 - Share 'enum target_hw_bp_type' in GDB and GDBserver, so that a new
file common/break-common.h is created.
 - Some typos and code format issues are fixed.
 - Rename 'debug register' to 'watch register' in comments and code.

Patch 1/5 is to share 'enum target_hw_bp_type' and patch 2/5 is to
include asm/ptrace.h in mips-linux-nat.c, but keep watchpoint related
structures as a fall back.  Patch 3/5 is to refactor mips-linux-nat.c,
rename functions and update comments, etc.  Patch 4/5 is to move mips h/w
wathcpoint stuff to common, and Patch 5/5 is to support h/w watchpoint
in gdbserver for MIPS.

The whole series is tested on a MIPS board with only one hardware
watchpoint register.  I pick this patch up during the test, because
it fixes an internal error, so this patch series depend on it.

  [RFC] Catch exception after stepped over watchpoint.
  http://sourceware.org/ml/gdb-patches/2013-06/msg00866.html

*** BLURB HERE ***

Yao Qi (5):
  Share 'enum target_hw_bp_type' in GDB and GDBserver.
  Include asm/ptrace.h in mips-linux-nat.c
  Refactor in mips-linux-nat.c
  Move mips hardware watchpoint stuff to common/
  MIPS GDBserver watchpoint

 gdb/Makefile.in                |    6 +-
 gdb/NEWS                       |    3 +
 gdb/breakpoint.h               |   10 +-
 gdb/common/break-common.h      |   30 +++
 gdb/common/mips-linux-watch.c  |  352 ++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h  |  129 ++++++++++++
 gdb/config/mips/linux.mh       |    2 +-
 gdb/gdbserver/Makefile.in      |    7 +-
 gdb/gdbserver/configure.srv    |    1 +
 gdb/gdbserver/i386-low.c       |    9 +-
 gdb/gdbserver/linux-mips-low.c |  366 +++++++++++++++++++++++++++++++++
 gdb/mips-linux-nat.c           |  439 +++------------------------------------
 12 files changed, 929 insertions(+), 425 deletions(-)
 create mode 100644 gdb/common/break-common.h
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

-- 
1.7.7.6


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

* [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
                     ` (3 preceding siblings ...)
  2013-06-29  3:11   ` [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver Yao Qi
@ 2013-06-29  8:01   ` Yao Qi
  2013-07-24  0:31     ` Maciej W. Rozycki
  2013-07-22  1:11   ` [PATCH v2 0/5] mips hardware watchpoint support in gdbserver Yao Qi
  5 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-06-29  8:01 UTC (permalink / raw)
  To: gdb-patches

This patch does a cut in mips-linux-nat.c and paste in
common/mips-linux-watch.[c,h].

gdb:

2013-06-29  Yao Qi  <yao@codesourcery.com>

	* Makefile.in ((HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
	(mips-linux-watch.o): New rule.
	* common/mips-linux-watch.c: New.
	* common/mips-linux-watch.h: New.
	* config/mips/linux.mh (NATDEPFILES): Add mips-linux-watch.o
	* mips-linux-nat.c: Don't include asm/ptrace.  Include
	mips-linux-watch.h.
	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
	to common/mips-linux-watch.h.
	(MAX_DEBUG_REGISTER): Likewise.
	(enum pt_watch_style): Likewise.
	(struct mips32_watch_regs): Likewise.
	(struct mips64_watch_regs): Likewise.
	(struct pt_watch_regs): Likewise.
	(struct mips_watchpoint): Likewise.
	(mips_linux_watch_get_irw_mask): Move to
	common/mips-linux-watch.c.
	(get_reg_mask, mips_linux_watch_get_num_valid): Likewise.
	(mips_linux_watch_get_watchlo): Likewise.
	(mips_linux_watch_set_watchlo): Likewise.
	(mips_linux_watch_get_watchhi): Likewise.
	(mips_linux_watch_set_watchhi): Likewise.
	(mips_linux_read_watch_registers): Likewise.
	(mips_linux_watch_type_to_irw): Likewise.
	(mips_linux_stopped_data_address, fill_mask): Likewise.
	(mips_linux_watch_try_one_watch): Likewise.
	(mips_linux_watch_populate_regs): Likewise.
---
 gdb/Makefile.in               |    6 +-
 gdb/common/mips-linux-watch.c |  352 ++++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h |  129 +++++++++++++
 gdb/config/mips/linux.mh      |    2 +-
 gdb/mips-linux-nat.c          |  414 +----------------------------------------
 5 files changed, 489 insertions(+), 414 deletions(-)
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index c27c03a..8031130 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -784,7 +784,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 HFILES_NO_SRCDIR = \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-ptrace.h common/mips-linux-watch.h \
 proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
 ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -2007,6 +2007,10 @@ linux-btrace.o: ${srcdir}/common/linux-btrace.c
 	$(COMPILE) $(srcdir)/common/linux-btrace.c
 	$(POSTCOMPILE)
 
+mips-linux-watch.o: ${srcdir}/common/mips-linux-watch.c
+	$(COMPILE) $(srcdir)/common/mips-linux-watch.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
new file mode 100644
index 0000000..f107530
--- /dev/null
+++ b/gdb/common/mips-linux-watch.c
@@ -0,0 +1,352 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#include <sys/ptrace.h>
+#include "mips-linux-watch.h"
+#include "gdb_assert.h"
+
+/* Assuming usable watch registers REGS, return the num_valid.  */
+
+uint32_t
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.num_valid;
+    case pt_watch_style_mips64:
+      return regs->mips64.num_valid;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
+
+CORE_ADDR
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchlo[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchlo[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchlo VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      /*  The cast will never throw away bits as 64 bit addresses can
+	  never be used on a 32 bit kernel.  */
+      regs->mips32.watchlo[n] = (uint32_t) value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchlo[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchhi[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchhi[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchhi VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      regs->mips32.watchhi[n] = value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchhi[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Set any low order bits in MASK that are not set.  */
+
+static CORE_ADDR
+fill_mask (CORE_ADDR mask)
+{
+  CORE_ADDR f = 1;
+
+  while (f && f < mask)
+    {
+      mask |= f;
+      f <<= 1;
+    }
+  return mask;
+}
+
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
+
+static uint32_t
+get_reg_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
+
+int
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, uint32_t irw)
+{
+  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
+  CORE_ADDR mask_bits, t_low;
+  uint16_t t_hi;
+  int i, free_watches;
+  struct pt_watch_regs regs_copy;
+
+  if (len <= 0)
+    return 0;
+
+  last_byte = addr + len - 1;
+  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
+  base_addr = addr & ~mask_bits;
+
+  /* Check to see if it is covered by current registers.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
+	{
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
+	  if (addr >= t_low && last_byte <= (t_low + t_hi))
+	    return 1;
+	}
+    }
+  /* Try to find an empty register.  */
+  free_watches = 0;
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
+	{
+	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
+	    {
+	      /* It fits, we'll take it.  */
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i,
+					    mask_bits & ~IRW_MASK);
+	      return 1;
+	    }
+	  else
+	    {
+	      /* It doesn't fit, but has the proper IRW capabilities.  */
+	      free_watches++;
+	    }
+	}
+    }
+  if (free_watches > 1)
+    {
+      /* Try to split it across several registers.  */
+      regs_copy = *regs;
+      for (i = 0;
+	   i < mips_linux_watch_get_num_valid (&regs_copy);
+	   i++)
+	{
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
+	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
+	  if (t_low == 0 && irw == (t_hi & irw))
+	    {
+	      t_low = addr & ~(CORE_ADDR) t_hi;
+	      break_addr = t_low + t_hi + 1;
+	      if (break_addr >= addr + len)
+		segment_len = len;
+	      else
+		segment_len = break_addr - addr;
+	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
+	      if (break_addr >= addr + len)
+		{
+		  *regs = regs_copy;
+		  return 1;
+		}
+	      len = addr + len - break_addr;
+	      addr = break_addr;
+	    }
+	}
+    }
+  /* It didn't fit anywhere, we failed.  */
+  return 0;
+}
+
+/* Convert GDB's TYPE to an IRW mask.  */
+
+uint32_t
+mips_linux_watch_type_to_irw (int type)
+{
+  switch (type)
+    {
+    case hw_write:
+      return W_MASK;
+    case hw_read:
+      return R_MASK;
+    case hw_access:
+      return (W_MASK | R_MASK);
+    default:
+      return 0;
+    }
+}
+
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
+
+void
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
+{
+  struct mips_watchpoint *w;
+  int i;
+
+  /* Clear them out.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
+    }
+
+  w = current_watches;
+  while (w)
+    {
+      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
+      /* They must all fit, because we previously calculated that they
+	 would.  */
+      gdb_assert (i);
+      w = w->next;
+    }
+}
+
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
+
+int
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
+{
+  if (force || *watch_readback_valid == 0)
+    {
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
+	{
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      switch (watch_readback->style)
+	{
+	case pt_watch_style_mips32:
+	  if (watch_readback->mips32.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	case pt_watch_style_mips64:
+	  if (watch_readback->mips64.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	default:
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      /* Watch registers appear to be usable.  */
+      *watch_readback_valid = 1;
+    }
+  return (*watch_readback_valid == 1) ? 1 : 0;
+}
diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
new file mode 100644
index 0000000..4f91183
--- /dev/null
+++ b/gdb/common/mips-linux-watch.h
@@ -0,0 +1,129 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#ifndef MIPS_LINUX_WATCH_H
+#define MIPS_LINUX_WATCH_H 1
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#endif
+
+#include <asm/ptrace.h>
+#include <stdint.h>
+
+#include "break-common.h"
+
+#define MAX_DEBUG_REGISTER 8
+
+/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
+   have hardware watchpoint-related structures.  Define them below.  */
+
+#ifndef PTRACE_GET_WATCH_REGS
+#  define PTRACE_GET_WATCH_REGS	0xd0
+
+enum pt_watch_style {
+  pt_watch_style_mips32,
+  pt_watch_style_mips64
+};
+
+/* A value of zero in a watchlo indicates that it is available.  */
+
+struct mips32_watch_regs
+{
+  uint32_t watchlo[MAX_DEBUG_REGISTER];
+  /* Lower 16 bits of watchhi.  */
+  uint16_t watchhi[MAX_DEBUG_REGISTER];
+  /* Valid mask and I R W bits.
+   * bit 0 -- 1 if W bit is usable.
+   * bit 1 -- 1 if R bit is usable.
+   * bit 2 -- 1 if I bit is usable.
+   * bits 3 - 11 -- Valid watchhi mask bits.
+   */
+  uint16_t watch_masks[MAX_DEBUG_REGISTER];
+  /* The number of valid watch register pairs.  */
+  uint32_t num_valid;
+  /* There is confusion across gcc versions about structure alignment,
+     so we force 8 byte alignment for these structures so they match
+     the kernel even if it was build with a different gcc version.  */
+} __attribute__ ((aligned (8)));
+
+struct mips64_watch_regs
+{
+  uint64_t watchlo[MAX_DEBUG_REGISTER];
+  uint16_t watchhi[MAX_DEBUG_REGISTER];
+  uint16_t watch_masks[MAX_DEBUG_REGISTER];
+  uint32_t num_valid;
+} __attribute__ ((aligned (8)));
+
+struct pt_watch_regs
+{
+  enum pt_watch_style style;
+  union
+  {
+    struct mips32_watch_regs mips32;
+    struct mips64_watch_regs mips64;
+  };
+};
+
+#endif
+
+#ifndef PTRACE_SET_WATCH_REGS
+#  define PTRACE_SET_WATCH_REGS	0xd1
+#endif
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
+/* We keep list of all watchpoints we should install and calculate the
+   watch register values each time the list changes.  This allows for
+   easy sharing of watch registers for more than one watchpoint.  */
+
+struct mips_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
+  struct mips_watchpoint *next;
+};
+
+uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n);
+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n);
+void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+				   CORE_ADDR value);
+uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n);
+void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+				   uint16_t value);
+int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				    CORE_ADDR addr, int len, uint32_t irw);
+void mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				     struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_type_to_irw (int type);
+
+int mips_linux_read_watch_registers (long lwpid,
+				     struct pt_watch_regs *watch_readback,
+				     int *watch_readback_valid, int force);
+#endif
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index 2f8e5dd..a4f23e3 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
-	linux-procfs.o linux-ptrace.o
+	linux-procfs.o linux-ptrace.o mips-linux-watch.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
 LOADLIBES = -ldl $(RDYNAMIC)
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index af70945..27467f4 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -34,7 +34,8 @@
 
 #include <sgidefs.h>
 #include <sys/ptrace.h>
-#include <asm/ptrace.h>
+
+#include "mips-linux-watch.h"
 
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
@@ -461,74 +462,6 @@ mips_linux_read_description (struct target_ops *ops)
     return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
 }
 
-#define MAX_DEBUG_REGISTER 8
-
-/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
-   have hardware watchpoint-related structures.  Define them below.  */
-
-#ifndef PTRACE_GET_WATCH_REGS
-#  define PTRACE_GET_WATCH_REGS	0xd0
-
-enum pt_watch_style {
-  pt_watch_style_mips32,
-  pt_watch_style_mips64
-};
-
-/* A value of zero in a watchlo indicates that it is available.  */
-
-struct mips32_watch_regs
-{
-  uint32_t watchlo[MAX_DEBUG_REGISTER];
-  /* Lower 16 bits of watchhi.  */
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  /* Valid mask and I R W bits.
-   * bit 0 -- 1 if W bit is usable.
-   * bit 1 -- 1 if R bit is usable.
-   * bit 2 -- 1 if I bit is usable.
-   * bits 3 - 11 -- Valid watchhi mask bits.
-   */
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  /* The number of valid watch register pairs.  */
-  uint32_t num_valid;
-  /* There is confusion across gcc versions about structure alignment,
-     so we force 8 byte alignment for these structures so they match
-     the kernel even if it was build with a different gcc version.  */
-} __attribute__ ((aligned (8)));
-
-struct mips64_watch_regs
-{
-  uint64_t watchlo[MAX_DEBUG_REGISTER];
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  uint32_t num_valid;
-} __attribute__ ((aligned (8)));
-
-struct pt_watch_regs
-{
-  enum pt_watch_style style;
-  union
-  {
-    struct mips32_watch_regs mips32;
-    struct mips64_watch_regs mips64;
-  };
-};
-
-#endif
-
-#ifndef PTRACE_SET_WATCH_REGS
-#  define PTRACE_SET_WATCH_REGS	0xd1
-#endif
-
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
-
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
-
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
-
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
@@ -540,18 +473,6 @@ static int watch_readback_valid;
 
 static struct pt_watch_regs watch_readback;
 
-/* We keep list of all watchpoints we should install and calculate the
-   watch register values each time the list changes.  This allows for
-   easy sharing of watch registers for more than one watchpoint.  */
-
-struct mips_watchpoint
-{
-  CORE_ADDR addr;
-  int len;
-  int type;
-  struct mips_watchpoint *next;
-};
-
 static struct mips_watchpoint *current_watches;
 
 /*  The current set of watch register values for writing the
@@ -559,139 +480,6 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers REGS, return the irw_mask of
-   register N.  */
-
-static uint32_t
-mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[n] & IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[n] & IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the reg_mask of
-   register N.  */
-
-static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[n] & ~IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[n] & ~IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the num_valid.  */
-
-static uint32_t
-mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.num_valid;
-    case pt_watch_style_mips64:
-      return regs->mips64.num_valid;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the watchlo of
-   register N.  */
-
-static CORE_ADDR
-mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchlo[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchlo[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, set VALUE to watchlo of
-   register N.  */
-
-static void
-mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
-			      CORE_ADDR value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      /*  The cast will never throw away bits as 64 bit addresses can
-	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[n] = (uint32_t) value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchlo[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the watchhi of
-   register N.  */
-
-static uint32_t
-mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchhi[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchhi[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, set VALUE to watchhi of
-   register N.  */
-
-static void
-mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
-			      uint16_t value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      regs->mips32.watchhi[n] = value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchhi[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
 static void
 mips_show_dr (const char *func, CORE_ADDR addr,
 	      int len, enum target_hw_bp_type type)
@@ -719,67 +507,6 @@ mips_show_dr (const char *func, CORE_ADDR addr,
 							       i)));
 }
 
-/* Read the watch registers of process LWPID and store it in
-   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
-   registers are valid.  Return 1 if watch registers are usable.
-   Cached information is used unless FORCE is true.  */
-
-static int
-mips_linux_read_watch_registers (long lwpid,
-				 struct pt_watch_regs *watch_readback,
-				 int *watch_readback_valid, int force)
-{
-  if (force || *watch_readback_valid == 0)
-    {
-      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
-	{
-	  *watch_readback_valid = -1;
-	  return 0;
-	}
-      switch (watch_readback->style)
-	{
-	case pt_watch_style_mips32:
-	  if (watch_readback->mips32.num_valid == 0)
-	    {
-	      *watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	case pt_watch_style_mips64:
-	  if (watch_readback->mips64.num_valid == 0)
-	    {
-	      *watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	default:
-	  *watch_readback_valid = -1;
-	  return 0;
-	}
-      /* Watch registers appear to be usable.  */
-      *watch_readback_valid = 1;
-    }
-  return (*watch_readback_valid == 1) ? 1 : 0;
-}
-
-/* Convert GDB's TYPE to an IRW mask.  */
-
-static uint32_t
-mips_linux_watch_type_to_irw (int type)
-{
-  switch (type)
-    {
-    case hw_write:
-      return W_MASK;
-    case hw_read:
-      return R_MASK;
-    case hw_access:
-      return (W_MASK | R_MASK);
-    default:
-      return 0;
-    }
-}
-
 /* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
    handle the specified watch type.  */
 
@@ -856,113 +583,6 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in MASK that are not set.  */
-
-static CORE_ADDR
-fill_mask (CORE_ADDR mask)
-{
-  CORE_ADDR f = 1;
-  while (f && f < mask)
-    {
-      mask |= f;
-      f <<= 1;
-    }
-  return mask;
-}
-
-/* Try to add a single watch to the specified registers REGS.  The
-   address of added watch is ADDR, the length is LEN, and the mask
-   is IRW.  Return 1 on success, 0 on failure.  */
-
-static int
-mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
-				CORE_ADDR addr, int len, uint32_t irw)
-{
-  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low;
-  uint16_t t_hi;
-  int i, free_watches;
-  struct pt_watch_regs regs_copy;
-
-  if (len <= 0)
-    return 0;
-
-  last_byte = addr + len - 1;
-  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
-  base_addr = addr & ~mask_bits;
-
-  /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      t_low = mips_linux_watch_get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
-	{
-	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR) t_hi;
-	  if (addr >= t_low && last_byte <= (t_low + t_hi))
-	    return 1;
-	}
-    }
-  /* Try to find an empty register.  */
-  free_watches = 0;
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      t_low = mips_linux_watch_get_watchlo (regs, i);
-      if (t_low == 0
-	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
-	{
-	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
-	    {
-	      /* It fits, we'll take it.  */
-	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
-	      mips_linux_watch_set_watchhi (regs, i,
-					    mask_bits & ~IRW_MASK);
-	      return 1;
-	    }
-	  else
-	    {
-	      /* It doesn't fit, but has the proper IRW capabilities.  */
-	      free_watches++;
-	    }
-	}
-    }
-  if (free_watches > 1)
-    {
-      /* Try to split it across several registers.  */
-      regs_copy = *regs;
-      for (i = 0;
-	   i < mips_linux_watch_get_num_valid (&regs_copy);
-	   i++)
-	{
-	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
-	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
-	  if (t_low == 0 && irw == (t_hi & irw))
-	    {
-	      t_low = addr & ~(CORE_ADDR) t_hi;
-	      break_addr = t_low + t_hi + 1;
-	      if (break_addr >= addr + len)
-		segment_len = len;
-	      else
-		segment_len = break_addr - addr;
-	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      mips_linux_watch_set_watchlo (&regs_copy, i,
-					    (addr & ~mask_bits) | irw);
-	      mips_linux_watch_set_watchhi (&regs_copy, i,
-					    mask_bits & ~IRW_MASK);
-	      if (break_addr >= addr + len)
-		{
-		  *regs = regs_copy;
-		  return 1;
-		}
-	      len = addr + len - break_addr;
-	      addr = break_addr;
-	    }
-	}
-    }
-  /* It didn't fit anywhere, we failed.  */
-  return 0;
-}
-
 /* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
    the specified region can be covered by the watch registers.  */
 
@@ -1019,36 +639,6 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers REGS with the currently cached
-   watches CURRENT_WATCHES.  */
-
-static void
-mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
-				struct pt_watch_regs *regs)
-{
-  struct mips_watchpoint *w;
-  int i;
-
-  /* Clear them out.  */
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      mips_linux_watch_set_watchlo (regs, i, 0);
-      mips_linux_watch_set_watchhi (regs, i, 0);
-    }
-
-  w = current_watches;
-  while (w)
-    {
-      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
-
-      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
-      /* They must all fit, because we previously calculated that they
-	 would.  */
-      gdb_assert (i);
-      w = w->next;
-    }
-}
-
 /* Target to_insert_watchpoint implementation.  Try to insert a new
    watch.  Return zero on success.  */
 
-- 
1.7.7.6


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

* Re: [PATCH 5/5] MIPS GDBserver watchpoint
  2013-06-29  3:11   ` [PATCH 5/5] MIPS GDBserver watchpoint Yao Qi
@ 2013-06-29 15:20     ` Eli Zaretskii
  2013-07-24  0:35     ` Maciej W. Rozycki
  2013-07-24 18:11     ` Pedro Alves
  2 siblings, 0 replies; 52+ messages in thread
From: Eli Zaretskii @ 2013-06-29 15:20 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

> From: Yao Qi <yao@codesourcery.com>
> Date: Sat, 29 Jun 2013 11:10:27 +0800
> 
> This patch adds the mips hardware watchpoint support in GDBserver.
> 
> gdb/gdbserver:
> 
> 2013-06-29  Jie Zhang  <jie@codesourcery.com>
> 	    Daniel Jacobowitz  <dan@codesourcery.com>
> 	    Yao Qi  <yao@codesourcery.com>
> 
> 	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
> 	(mips_linux_watch_h): New.
> 	(mips-linux-watch.o): New rule.
> 	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to
> 	srv_tgtobj.
> 	* linux-mips-low.c: Include mips-linux-watch.h.
> 	(struct arch_process_info, struct arch_lwp_info): New.
> 	(update_watch_registers_callback): New.
> 	(mips_linux_new_process, mips_linux_new_thread) New.
> 	(mips_linux_prepare_to_resume, mips_insert_point): New.
> 	(mips_remove_point, mips_stopped_by_watchpoint): New.
> 	(rsp_bp_type_to_target_hw_bp_type): New.
> 	(mips_stopped_data_address): New.
> 	(the_low_target): Add watchpoint support functions.
> 
> gdb:
> 
> 2013-06-29  Yao Qi  <yao@codesourcery.com>
> 
> 	* NEWS: Mention it.

The NEWS part is approved.

Thanks.


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

* Re: [PATCH v2 0/5] mips hardware watchpoint support in gdbserver
  2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
                     ` (4 preceding siblings ...)
  2013-06-29  8:01   ` [PATCH 4/5] Move mips hardware watchpoint stuff to common/ Yao Qi
@ 2013-07-22  1:11   ` Yao Qi
  5 siblings, 0 replies; 52+ messages in thread
From: Yao Qi @ 2013-07-22  1:11 UTC (permalink / raw)
  To: gdb-patches

On 06/29/2013 11:10 AM, Yao Qi wrote:
> Here is the V2 of this patch series which is to post Jie and Dan's work
> to support mips hardware watchpoint in gdbserver.  There are several
> changes compared with V1:
>
>   - Keep these watchpoint-related structures as the fall back when
> PTRACE_GET_WATCH_REGS is not defined.
>   - Re-org the patch series as Maciej suggested, split the function
> renaming patch out of the function moving patch.
>   - Share 'enum target_hw_bp_type' in GDB and GDBserver, so that a new
> file common/break-common.h is created.
>   - Some typos and code format issues are fixed.
>   - Rename 'debug register' to 'watch register' in comments and code.
>
> Patch 1/5 is to share 'enum target_hw_bp_type' and patch 2/5 is to
> include asm/ptrace.h in mips-linux-nat.c, but keep watchpoint related
> structures as a fall back.  Patch 3/5 is to refactor mips-linux-nat.c,
> rename functions and update comments, etc.  Patch 4/5 is to move mips h/w
> wathcpoint stuff to common, and Patch 5/5 is to support h/w watchpoint
> in gdbserver for MIPS.
>
> The whole series is tested on a MIPS board with only one hardware
> watchpoint register.  I pick this patch up during the test, because
> it fixes an internal error, so this patch series depend on it.
>
>    [RFC] Catch exception after stepped over watchpoint.
>    http://sourceware.org/ml/gdb-patches/2013-06/msg00866.html

Ping.  http://sourceware.org/ml/gdb-patches/2013-06/msg00927.html

-- 
Yao (齐尧)


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

* Re: [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c
  2013-06-29  3:11   ` [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
@ 2013-07-24  0:26     ` Maciej W. Rozycki
  2013-07-28  0:43       ` Yao Qi
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-24  0:26 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Sat, 29 Jun 2013, Yao Qi wrote:

> 2013-06-29  Yao Qi  <yao@codesourcery.com>
> 
> 	* mips-linux-nat.c (MAX_DEBUG_REGISTER): Move it earlier in
> 	the code.
> 	(enum pt_watch_style): Remove.
> 	(struct mips32_watch_regs, struct mips64_watch_regs): Remove.
> 	(struct pt_watch_regs): Likewise.
> 	[!PTRACE_GET_WATCH_REGS] (enum pt_watch_style): New.
> 	[!PTRACE_GET_WATCH_REGS] (struct mips32_watch_regs): New.
> 	[!PTRACE_GET_WATCH_REGS] (struct mips64_watch_regs): New.
> 	[!PTRACE_GET_WATCH_REGS] (struct pt_watch_regs): New.
> ---
>  gdb/mips-linux-nat.c |   39 ++++++++++++++++++++++-----------------
>  1 files changed, 22 insertions(+), 17 deletions(-)
> 
> diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
> index d323a82..44d23a6 100644
> --- a/gdb/mips-linux-nat.c
> +++ b/gdb/mips-linux-nat.c
> @@ -460,31 +461,19 @@ mips_linux_read_description (struct target_ops *ops)
>      return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
>  }
>  
> -#ifndef PTRACE_GET_WATCH_REGS
> -#  define PTRACE_GET_WATCH_REGS	0xd0
> -#endif
> -
> -#ifndef PTRACE_SET_WATCH_REGS
> -#  define PTRACE_SET_WATCH_REGS	0xd1
> -#endif
> -
> -#define W_BIT 0
> -#define R_BIT 1
> -#define I_BIT 2
> +#define MAX_DEBUG_REGISTER 8
>  
> -#define W_MASK (1 << W_BIT)
> -#define R_MASK (1 << R_BIT)
> -#define I_MASK (1 << I_BIT)
> +/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
> +   have hardware watchpoint-related structures.  Define them below.  */
>  
> -#define IRW_MASK (I_MASK | R_MASK | W_MASK)
> +#ifndef PTRACE_GET_WATCH_REGS
> +#  define PTRACE_GET_WATCH_REGS	0xd0
>  
>  enum pt_watch_style {
>    pt_watch_style_mips32,
>    pt_watch_style_mips64
>  };
>  
> -#define MAX_DEBUG_REGISTER 8
> -
>  /* A value of zero in a watchlo indicates that it is available.  */
>  
>  struct mips32_watch_regs
> @@ -524,6 +513,22 @@ struct pt_watch_regs
>    };
>  };
>  
> +#endif

#endif /* !PTRACE_GET_WATCH_REGS */

please.

> +
> +#ifndef PTRACE_SET_WATCH_REGS
> +#  define PTRACE_SET_WATCH_REGS	0xd1
> +#endif

 With the inclusion of the kernel header I think there's no need to wrap
this definition separately -- a system header configuration where
PTRACE_GET_WATCH_REGS is defined but PTRACE_SET_WATCH_REGS is not would be
broken and could not be relied upon anyway.  Please just use:

#ifndef PTRACE_GET_WATCH_REGS
#  define PTRACE_GET_WATCH_REGS	0xd0
#  define PTRACE_SET_WATCH_REGS	0xd1
[...]

instead.  OK with these changes, thanks.

  Maciej


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

* Re: [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver.
  2013-06-29  3:11   ` [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver Yao Qi
@ 2013-07-24  0:26     ` Maciej W. Rozycki
  2013-07-24 14:04       ` Tom Tromey
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-24  0:26 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Sat, 29 Jun 2013, Yao Qi wrote:

> 'enum target_hw_bp_type' has been used in both GDB and GDBserver.  It
> will be used in MIPS hardware watchpoint support too.  This patch
> is to share 'enum target_hw_bp_type' in common/break-common.h.

 FWIW this patch looks reasonable to me, though I can't approve or reject 
a generic change like this.  I can see gdb/gdbserver/linux-aarch64-low.c 
has a similar target_point_type enum.  It might be a good idea to unify 
them all.

  Maciej


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

* Re: [PATCH 3/5] Refactor in mips-linux-nat.c
  2013-06-29  3:11   ` [PATCH 3/5] Refactor " Yao Qi
@ 2013-07-24  0:27     ` Maciej W. Rozycki
  2013-07-28  0:44       ` Yao Qi
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-24  0:27 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Sat, 29 Jun 2013, Yao Qi wrote:

> 2013-06-29  Yao Qi  <yao@codesourcery.com>
> 
> 	* mips-linux-nat.c (get_irw_mask): Rename to ...
> 	(mips_linux_watch_get_irw_mask): ... this.  Rename parameter
> 	'set' to 'n'.  Update function comment.  All callers changed.
> 	(get_reg_mask): Rename parameter 'set' to 'n'.  Update function
> 	comment.  All callers changed.
> 	(get_num_valid): Rename to ...
> 	(mips_linux_watch_get_num_valid): ... this.  Rename parameter
> 	'set' to 'n'.  Update function comment.  All callers changed.
> 	(get_watchlo): Rename to ...
> 	(mips_linux_watch_get_watchlo): ... this.  Rename parameter 'set'
> 	to 'n'.  Update function comment.  All callers changed.
> 	(set_watchlo): Rename to ...
> 	(mips_linux_watch_set_watchlo): ... this.  Rename parameter 'set'
> 	to 'n'.  Update function comment.  All callers changed.
> 	(get_watchhi): Rename to ...
> 	(mips_linux_watch_get_watchhi): ... this.  Update function
> 	comment.  All callers changed.
> 	(set_watchhi): Rename to ...
> 	(mips_linux_watch_set_watchhi): ... this.  Update function
> 	comment.  All callers changed.
> 	(mips_linux_read_watch_registers): Update function comment.
> 	Add new parameters 'lwpid', 'watch_readback', and
> 	'watch_readback_valid'.  Update.
> 	(type_to_irw): Rename to ...
> 	(mips_linux_watch_type_to_irw): ... this.  Update function
> 	comment.  All callers changed.
> 	(fill_mask): Update function comment.
> 	(try_one_watch): Rename to ...
> 	(mips_linux_watch_try_one_watch): ... this.  Change the type of
> 	parameter 'irw' from 'unsigned' to 'uint32_t'.
> 	(populate_regs_from_watches): Rename to ...
> 	(mips_linux_watch_populate_regs): ... this.  Add parameter
> 	'current_watches'.  All callers changed.
> ---
>  gdb/mips-linux-nat.c |  208 +++++++++++++++++++++++++++++---------------------
>  1 files changed, 121 insertions(+), 87 deletions(-)
> 
> diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
> index 44d23a6..af70945 100644
> --- a/gdb/mips-linux-nat.c
> +++ b/gdb/mips-linux-nat.c
> @@ -874,29 +892,31 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
>    base_addr = addr & ~mask_bits;
>  
>    /* Check to see if it is covered by current registers.  */
> -  for (i = 0; i < get_num_valid (regs); i++)
> +  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
>      {
> -      t_low = get_watchlo (regs, i);
> -      if (t_low != 0 && irw == ((unsigned)t_low & irw))
> +      t_low = mips_linux_watch_get_watchlo (regs, i);
> +      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
>  	{
> -	  t_hi = get_watchhi (regs, i) | IRW_MASK;
> -	  t_low &= ~(CORE_ADDR)t_hi;
> +	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
> +	  t_low &= ~(CORE_ADDR) t_hi;
>  	  if (addr >= t_low && last_byte <= (t_low + t_hi))
>  	    return 1;
>  	}
>      }
>    /* Try to find an empty register.  */
>    free_watches = 0;
> -  for (i = 0; i < get_num_valid (regs); i++)
> +  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
>      {
> -      t_low = get_watchlo (regs, i);
> -      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
> +      t_low = mips_linux_watch_get_watchlo (regs, i);
> +      if (t_low == 0
> +	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
>  	{
>  	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
>  	    {
>  	      /* It fits, we'll take it.  */
> -	      set_watchlo (regs, i, base_addr | irw);
> -	      set_watchhi (regs, i, mask_bits & ~IRW_MASK);
> +	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
> +	      mips_linux_watch_set_watchhi (regs, i,
> +					    mask_bits & ~IRW_MASK);

 This fits on one line, please adjust.

> @@ -910,21 +930,25 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
>      {
>        /* Try to split it across several registers.  */
>        regs_copy = *regs;
> -      for (i = 0; i < get_num_valid (&regs_copy); i++)
> +      for (i = 0;
> +	   i < mips_linux_watch_get_num_valid (&regs_copy);
> +	   i++)

 Likewise.  OK with these changes, thanks.

  Maciej


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

* Re: [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-06-29  8:01   ` [PATCH 4/5] Move mips hardware watchpoint stuff to common/ Yao Qi
@ 2013-07-24  0:31     ` Maciej W. Rozycki
  2013-07-24  2:08       ` Yao Qi
  2013-07-25  0:07       ` Yao Qi
  0 siblings, 2 replies; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-24  0:31 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Sat, 29 Jun 2013, Yao Qi wrote:

> 2013-06-29  Yao Qi  <yao@codesourcery.com>
> 
> 	* Makefile.in ((HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
> 	(mips-linux-watch.o): New rule.
> 	* common/mips-linux-watch.c: New.
> 	* common/mips-linux-watch.h: New.
> 	* config/mips/linux.mh (NATDEPFILES): Add mips-linux-watch.o
> 	* mips-linux-nat.c: Don't include asm/ptrace.  Include
> 	mips-linux-watch.h.
> 	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
> 	to common/mips-linux-watch.h.
> 	(MAX_DEBUG_REGISTER): Likewise.
> 	(enum pt_watch_style): Likewise.
> 	(struct mips32_watch_regs): Likewise.
> 	(struct mips64_watch_regs): Likewise.
> 	(struct pt_watch_regs): Likewise.
> 	(struct mips_watchpoint): Likewise.
> 	(mips_linux_watch_get_irw_mask): Move to
> 	common/mips-linux-watch.c.
> 	(get_reg_mask, mips_linux_watch_get_num_valid): Likewise.
> 	(mips_linux_watch_get_watchlo): Likewise.
> 	(mips_linux_watch_set_watchlo): Likewise.
> 	(mips_linux_watch_get_watchhi): Likewise.
> 	(mips_linux_watch_set_watchhi): Likewise.
> 	(mips_linux_read_watch_registers): Likewise.
> 	(mips_linux_watch_type_to_irw): Likewise.
> 	(mips_linux_stopped_data_address, fill_mask): Likewise.
> 	(mips_linux_watch_try_one_watch): Likewise.
> 	(mips_linux_watch_populate_regs): Likewise.
> ---
>  gdb/Makefile.in               |    6 +-
>  gdb/common/mips-linux-watch.c |  352 ++++++++++++++++++++++++++++++++++
>  gdb/common/mips-linux-watch.h |  129 +++++++++++++
>  gdb/config/mips/linux.mh      |    2 +-
>  gdb/mips-linux-nat.c          |  414 +----------------------------------------
>  5 files changed, 489 insertions(+), 414 deletions(-)
>  create mode 100644 gdb/common/mips-linux-watch.c
>  create mode 100644 gdb/common/mips-linux-watch.h
> 
> diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
> new file mode 100644
> index 0000000..f107530
> --- /dev/null
> +++ b/gdb/common/mips-linux-watch.c
> @@ -0,0 +1,352 @@
> +/* Copyright (C) 2009-2013 Free Software Foundation, Inc.

 The copyright years don't appear right to me.  Either 2001-2013, taken 
from gdb/mips-linux-nat.c, or just lone 2013 seem more appropriate to me, 
but http://www.gnu.org/prep/maintain/maintain.html does not appear clear 
to me on it -- would someone please step in and explain what GDB's usual 
policy has been here?

 Can you please reorder the sequence of functions moved here to match the 
original one in gdb/mips-linux-nat.c?

 Also, anyone: do we still aim to maintain gdb/config/djgpp/fnchange.lst?  
If so, then on what basis -- ad hoc?  ChangeLogs show most recent random 
additions last year only and files appear to be missing from the listing.

> diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
> new file mode 100644
> index 0000000..4f91183
> --- /dev/null
> +++ b/gdb/common/mips-linux-watch.h
> @@ -0,0 +1,129 @@
> +/* Copyright (C) 2009-2013 Free Software Foundation, Inc.

 Same copyright year concern as above.

> diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
> index af70945..27467f4 100644
> --- a/gdb/mips-linux-nat.c
> +++ b/gdb/mips-linux-nat.c
> @@ -34,7 +34,8 @@
>  
>  #include <sgidefs.h>
>  #include <sys/ptrace.h>
> -#include <asm/ptrace.h>
> +
> +#include "mips-linux-watch.h"

 You actually need to keep that <asm/ptrace.h> inclusion, per GDB's coding 
requirements (see gdbint.info).

 Please resend with the changes requested.

  Maciej


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

* Re: [PATCH 5/5] MIPS GDBserver watchpoint
  2013-06-29  3:11   ` [PATCH 5/5] MIPS GDBserver watchpoint Yao Qi
  2013-06-29 15:20     ` Eli Zaretskii
@ 2013-07-24  0:35     ` Maciej W. Rozycki
  2013-07-25  0:17       ` Yao Qi
  2013-07-24 18:11     ` Pedro Alves
  2 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-24  0:35 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Sat, 29 Jun 2013, Yao Qi wrote:

> gdb/gdbserver:
> 
> 2013-06-29  Jie Zhang  <jie@codesourcery.com>
> 	    Daniel Jacobowitz  <dan@codesourcery.com>
> 	    Yao Qi  <yao@codesourcery.com>
> 
> 	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
> 	(mips_linux_watch_h): New.
> 	(mips-linux-watch.o): New rule.
> 	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to
> 	srv_tgtobj.
> 	* linux-mips-low.c: Include mips-linux-watch.h.
> 	(struct arch_process_info, struct arch_lwp_info): New.
> 	(update_watch_registers_callback): New.
> 	(mips_linux_new_process, mips_linux_new_thread) New.
> 	(mips_linux_prepare_to_resume, mips_insert_point): New.
> 	(mips_remove_point, mips_stopped_by_watchpoint): New.
> 	(rsp_bp_type_to_target_hw_bp_type): New.
> 	(mips_stopped_data_address): New.
> 	(the_low_target): Add watchpoint support functions.
> 
> gdb:
> 
> 2013-06-29  Yao Qi  <yao@codesourcery.com>
> 
> 	* NEWS: Mention it.
> ---
>  gdb/NEWS                       |    3 +
>  gdb/gdbserver/Makefile.in      |    7 +-
>  gdb/gdbserver/configure.srv    |    1 +
>  gdb/gdbserver/linux-mips-low.c |  366 ++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 376 insertions(+), 1 deletions(-)
> 
> diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
> index 1010528..6e6e3e0 100644
> --- a/gdb/gdbserver/linux-mips-low.c
> +++ b/gdb/gdbserver/linux-mips-low.c
> @@ -257,6 +291,328 @@ mips_breakpoint_at (CORE_ADDR where)
>    return 0;
>  }
>  
> +/* Mark the watch registers of lwp, represented by ENTRY, as changed,
> +   if the lwp's process id is *PID_P.  */
> +
> +static int
> +update_watch_registers_callback (struct inferior_list_entry *entry,
> +				 void *pid_p)
> +{
> +  struct lwp_info *lwp = (struct lwp_info *) entry;
> +  int pid = *(int *) pid_p;
> +
> +  /* Only update the threads of this process.  */
> +  if (pid_of (lwp) == pid)
> +    {
> +      /* The actual update is done later just before resuming the lwp,
> +	 we just mark that the registers need updating.  */
> +      lwp->arch_private->watch_registers_changed = 1;
> +
> +      /* If the lwp isn't stopped, force it to momentarily pause, so
> +	 we can update its watch registers.  */
> +      if (!lwp->stopped)
> +	linux_stop_lwp (lwp);
> +    }
> +
> +  return 0;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   new_process.  */
> +
> +static struct arch_process_info *
> +mips_linux_new_process (void)
> +{
> +  struct arch_process_info *info = xcalloc (1, sizeof (*info));
> +
> +  return info;
> +}
> +
> +/* This is the implementation of linux_target_ops method new_thread.
> +   Mark the watch registers as changed, so the threads' copies will
> +   be updated.  */
> +
> +static struct arch_lwp_info *
> +mips_linux_new_thread (void)
> +{
> +  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
> +
> +  info->watch_registers_changed = 1;
> +
> +  return info;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   prepare_to_resume.  If the watch regs have changed, update the
> +   thread's copies.  */
> +
> +static void
> +mips_linux_prepare_to_resume (struct lwp_info *lwp)
> +{
> +  ptid_t ptid = ptid_of (lwp);
> +  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
> +  struct arch_process_info *private = proc->private->arch_private;
> +
> +  if (lwp->arch_private->watch_registers_changed)
> +    {
> +      /* Only update the watch registers if we have set or unset a
> +	 watchpoint already.  */
> +      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
> +	{
> +	  /* Write the mirrored watch register values.  */
> +	  int tid = ptid_get_lwp (ptid);
> +
> +	  if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
> +			    &private->watch_mirror))
> +	    perror_with_name ("Couldn't write watch register");
> +	}
> +
> +      lwp->arch_private->watch_registers_changed = 0;
> +    }
> +}
> +
> +/* Translate breakpoint type TYPE in rsp to 'enum target_hw_bp_type'.  Return
> +   -1 if translation failed.  */
> +
> +static enum target_hw_bp_type
> +rsp_bp_type_to_target_hw_bp_type (char type)
> +{
> +  switch (type)
> +    {
> +    case '2':
> +      return hw_write;
> +    case '3':
> +      return hw_read;
> +    case '4':
> +      return hw_access;
> +    }
> +
> +  return -1;

 This looks unclean to me, you're returning a value that's outside the 
valid range of the enum type used.  By the structure of the callers this 
code is expected to be dead though, so please use gdb_assert_not_reached.

 Thanks for going ahead and adding rsp_bp_type_to_target_hw_bp_type, 
however in the future please try to name in the patch description any 
changes you've made (non-trivial ones that is, obvious typo fixes, 
formatting adjustments, etc. need no mention, although there'll be no harm 
from making an overall statement that you've made such clean-ups) beyond 
ones requested in the review.  This will make the review process easier 
for me as otherwise I may assume proposed changes I have already accepted 
will have remained the same in the updated patch.

 Please resend with the adjustment requested, the change looks otherwise 
OK to me.

  Maciej


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

* Re: [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-07-24  0:31     ` Maciej W. Rozycki
@ 2013-07-24  2:08       ` Yao Qi
  2013-07-24 18:09         ` Pedro Alves
  2013-07-25  0:07       ` Yao Qi
  1 sibling, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-07-24  2:08 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/24/2013 08:30 AM, Maciej W. Rozycki wrote:
>> +/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
>   The copyright years don't appear right to me.  Either 2001-2013, taken
> from gdb/mips-linux-nat.c, or just lone 2013 seem more appropriate to me,
> buthttp://www.gnu.org/prep/maintain/maintain.html  does not appear clear
> to me on it -- would someone please step in and explain what GDB's usual
> policy has been here?

Watchpoint stuff was added in 2009, so 2009-2013 is right, IMO.

-- 
Yao (齐尧)


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

* Re: [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver.
  2013-07-24  0:26     ` Maciej W. Rozycki
@ 2013-07-24 14:04       ` Tom Tromey
  2013-07-28  0:41         ` Yao Qi
  0 siblings, 1 reply; 52+ messages in thread
From: Tom Tromey @ 2013-07-24 14:04 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Yao Qi, gdb-patches

>>>>> "Maciej" == Maciej W Rozycki <macro@codesourcery.com> writes:

Maciej> On Sat, 29 Jun 2013, Yao Qi wrote:
>> 'enum target_hw_bp_type' has been used in both GDB and GDBserver.  It
>> will be used in MIPS hardware watchpoint support too.  This patch
>> is to share 'enum target_hw_bp_type' in common/break-common.h.

Maciej>  FWIW this patch looks reasonable to me, though I can't approve
Maciej> or reject a generic change like this.  I can see
Maciej> gdb/gdbserver/linux-aarch64-low.c has a similar
Maciej> target_point_type enum.  It might be a good idea to unify them
Maciej> all.

This patch is ok.

Tom


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

* Re: [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-07-24  2:08       ` Yao Qi
@ 2013-07-24 18:09         ` Pedro Alves
  0 siblings, 0 replies; 52+ messages in thread
From: Pedro Alves @ 2013-07-24 18:09 UTC (permalink / raw)
  To: Yao Qi; +Cc: Maciej W. Rozycki, gdb-patches

On 07/24/2013 03:07 AM, Yao Qi wrote:
> On 07/24/2013 08:30 AM, Maciej W. Rozycki wrote:
>>> +/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
>>   The copyright years don't appear right to me.  Either 2001-2013, taken
>> from gdb/mips-linux-nat.c, or just lone 2013 seem more appropriate to me,
>> buthttp://www.gnu.org/prep/maintain/maintain.html  does not appear clear
>> to me on it -- would someone please step in and explain what GDB's usual
>> policy has been here?

Retain the original copyright year:

http://www.sourceware.org/ml/gdb-patches/2012-04/msg00640.html

> 
> Watchpoint stuff was added in 2009, so 2009-2013 is right, IMO.

I agree.

-- 
Pedro Alves


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

* Re: [PATCH 5/5] MIPS GDBserver watchpoint
  2013-06-29  3:11   ` [PATCH 5/5] MIPS GDBserver watchpoint Yao Qi
  2013-06-29 15:20     ` Eli Zaretskii
  2013-07-24  0:35     ` Maciej W. Rozycki
@ 2013-07-24 18:11     ` Pedro Alves
  2 siblings, 0 replies; 52+ messages in thread
From: Pedro Alves @ 2013-07-24 18:11 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On 06/29/2013 04:10 AM, Yao Qi wrote:
> gdb:
> 
> 2013-06-29  Yao Qi  <yao@codesourcery.com>
> 
> 	* NEWS: Mention it.

"it" will be meaningless to whoever reads gdb/ChangeLog
in isolation.

-- 
Pedro Alves


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

* Re: [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-07-24  0:31     ` Maciej W. Rozycki
  2013-07-24  2:08       ` Yao Qi
@ 2013-07-25  0:07       ` Yao Qi
  2013-07-25 21:17         ` Maciej W. Rozycki
  1 sibling, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-07-25  0:07 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/24/2013 08:30 AM, Maciej W. Rozycki wrote:
>> diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
>> >index af70945..27467f4 100644
>> >--- a/gdb/mips-linux-nat.c
>> >+++ b/gdb/mips-linux-nat.c
>> >@@ -34,7 +34,8 @@
>> >  
>> >  #include <sgidefs.h>
>> >  #include <sys/ptrace.h>
>> >-#include <asm/ptrace.h>
>> >+
>> >+#include "mips-linux-watch.h"
>   You actually need to keep that <asm/ptrace.h> inclusion, per GDB's coding
> requirements (see gdbint.info).
> 
>   Please resend with the changes requested.

OK, I keep <asm/ptrace.h> inclusion in the updated patch
below.  The functions order is fixed in the updated patch
too.

-- 
Yao (齐尧)

gdb:

2013-07-25  Yao Qi  <yao@codesourcery.com>

	* Makefile.in ((HFILES_NO_SRCDIR): Add common/mips-linux-watch.h.
	(mips-linux-watch.o): New rule.
	* common/mips-linux-watch.c: New.
	* common/mips-linux-watch.h: New.
	* config/mips/linux.mh (NATDEPFILES): Add mips-linux-watch.o
	* mips-linux-nat.c: Include mips-linux-watch.h.
	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
	to common/mips-linux-watch.h.
	(MAX_DEBUG_REGISTER): Likewise.
	(enum pt_watch_style): Likewise.
	(struct mips32_watch_regs): Likewise.
	(struct mips64_watch_regs): Likewise.
	(struct pt_watch_regs): Likewise.
	(struct mips_watchpoint): Likewise.
	(mips_linux_watch_get_irw_mask): Move to
	common/mips-linux-watch.c.
	(get_reg_mask, mips_linux_watch_get_num_valid): Likewise.
	(mips_linux_watch_get_watchlo): Likewise.
	(mips_linux_watch_set_watchlo): Likewise.
	(mips_linux_watch_get_watchhi): Likewise.
	(mips_linux_watch_set_watchhi): Likewise.
	(mips_linux_read_watch_registers): Likewise.
	(mips_linux_watch_type_to_irw): Likewise.
	(mips_linux_stopped_data_address, fill_mask): Likewise.
	(mips_linux_watch_try_one_watch): Likewise.
	(mips_linux_watch_populate_regs): Likewise.
---
 gdb/Makefile.in               |    6 +-
 gdb/common/mips-linux-watch.c |  349 +++++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h |  126 +++++++++++++
 gdb/config/mips/linux.mh      |    2 +-
 gdb/mips-linux-nat.c          |  407 +----------------------------------------
 5 files changed, 483 insertions(+), 407 deletions(-)
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index a51afcb..00823ad 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -786,7 +786,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 HFILES_NO_SRCDIR = \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-ptrace.h common/mips-linux-watch.h \
 proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
 ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -2021,6 +2021,10 @@ linux-btrace.o: ${srcdir}/common/linux-btrace.c
 	$(COMPILE) $(srcdir)/common/linux-btrace.c
 	$(POSTCOMPILE)
 
+mips-linux-watch.o: ${srcdir}/common/mips-linux-watch.c
+	$(COMPILE) $(srcdir)/common/mips-linux-watch.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
new file mode 100644
index 0000000..810fbb8
--- /dev/null
+++ b/gdb/common/mips-linux-watch.c
@@ -0,0 +1,349 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#include <sys/ptrace.h>
+#include "mips-linux-watch.h"
+#include "gdb_assert.h"
+
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
+
+static uint32_t
+get_reg_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the num_valid.  */
+
+uint32_t
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.num_valid;
+    case pt_watch_style_mips64:
+      return regs->mips64.num_valid;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
+
+CORE_ADDR
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchlo[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchlo[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchlo VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      /*  The cast will never throw away bits as 64 bit addresses can
+	  never be used on a 32 bit kernel.  */
+      regs->mips32.watchlo[n] = (uint32_t) value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchlo[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchhi[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchhi[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set a watchhi VALUE of
+   register N.  */
+
+void
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      regs->mips32.watchhi[n] = value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchhi[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
+
+int
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
+{
+  if (force || *watch_readback_valid == 0)
+    {
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
+	{
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      switch (watch_readback->style)
+	{
+	case pt_watch_style_mips32:
+	  if (watch_readback->mips32.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	case pt_watch_style_mips64:
+	  if (watch_readback->mips64.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	default:
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      /* Watch registers appear to be usable.  */
+      *watch_readback_valid = 1;
+    }
+  return (*watch_readback_valid == 1) ? 1 : 0;
+}
+
+/* Convert GDB's TYPE to an IRW mask.  */
+
+uint32_t
+mips_linux_watch_type_to_irw (int type)
+{
+  switch (type)
+    {
+    case hw_write:
+      return W_MASK;
+    case hw_read:
+      return R_MASK;
+    case hw_access:
+      return (W_MASK | R_MASK);
+    default:
+      return 0;
+    }
+}
+
+/* Set any low order bits in MASK that are not set.  */
+
+static CORE_ADDR
+fill_mask (CORE_ADDR mask)
+{
+  CORE_ADDR f = 1;
+
+  while (f && f < mask)
+    {
+      mask |= f;
+      f <<= 1;
+    }
+  return mask;
+}
+
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
+
+int
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, uint32_t irw)
+{
+  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
+  CORE_ADDR mask_bits, t_low;
+  uint16_t t_hi;
+  int i, free_watches;
+  struct pt_watch_regs regs_copy;
+
+  if (len <= 0)
+    return 0;
+
+  last_byte = addr + len - 1;
+  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
+  base_addr = addr & ~mask_bits;
+
+  /* Check to see if it is covered by current registers.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
+	{
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
+	  if (addr >= t_low && last_byte <= (t_low + t_hi))
+	    return 1;
+	}
+    }
+  /* Try to find an empty register.  */
+  free_watches = 0;
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
+	{
+	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
+	    {
+	      /* It fits, we'll take it.  */
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
+	      return 1;
+	    }
+	  else
+	    {
+	      /* It doesn't fit, but has the proper IRW capabilities.  */
+	      free_watches++;
+	    }
+	}
+    }
+  if (free_watches > 1)
+    {
+      /* Try to split it across several registers.  */
+      regs_copy = *regs;
+      for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
+	{
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
+	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
+	  if (t_low == 0 && irw == (t_hi & irw))
+	    {
+	      t_low = addr & ~(CORE_ADDR) t_hi;
+	      break_addr = t_low + t_hi + 1;
+	      if (break_addr >= addr + len)
+		segment_len = len;
+	      else
+		segment_len = break_addr - addr;
+	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
+	      if (break_addr >= addr + len)
+		{
+		  *regs = regs_copy;
+		  return 1;
+		}
+	      len = addr + len - break_addr;
+	      addr = break_addr;
+	    }
+	}
+    }
+  /* It didn't fit anywhere, we failed.  */
+  return 0;
+}
+
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
+
+void
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
+{
+  struct mips_watchpoint *w;
+  int i;
+
+  /* Clear them out.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
+    }
+
+  w = current_watches;
+  while (w)
+    {
+      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
+      /* They must all fit, because we previously calculated that they
+	 would.  */
+      gdb_assert (i);
+      w = w->next;
+    }
+}
diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
new file mode 100644
index 0000000..aa89f19
--- /dev/null
+++ b/gdb/common/mips-linux-watch.h
@@ -0,0 +1,126 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#ifndef MIPS_LINUX_WATCH_H
+#define MIPS_LINUX_WATCH_H 1
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#endif
+
+#include <asm/ptrace.h>
+#include <stdint.h>
+
+#include "break-common.h"
+
+#define MAX_DEBUG_REGISTER 8
+
+/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
+   have hardware watchpoint-related structures.  Define them below.  */
+
+#ifndef PTRACE_GET_WATCH_REGS
+#  define PTRACE_GET_WATCH_REGS	0xd0
+#  define PTRACE_SET_WATCH_REGS	0xd1
+
+enum pt_watch_style {
+  pt_watch_style_mips32,
+  pt_watch_style_mips64
+};
+
+/* A value of zero in a watchlo indicates that it is available.  */
+
+struct mips32_watch_regs
+{
+  uint32_t watchlo[MAX_DEBUG_REGISTER];
+  /* Lower 16 bits of watchhi.  */
+  uint16_t watchhi[MAX_DEBUG_REGISTER];
+  /* Valid mask and I R W bits.
+   * bit 0 -- 1 if W bit is usable.
+   * bit 1 -- 1 if R bit is usable.
+   * bit 2 -- 1 if I bit is usable.
+   * bits 3 - 11 -- Valid watchhi mask bits.
+   */
+  uint16_t watch_masks[MAX_DEBUG_REGISTER];
+  /* The number of valid watch register pairs.  */
+  uint32_t num_valid;
+  /* There is confusion across gcc versions about structure alignment,
+     so we force 8 byte alignment for these structures so they match
+     the kernel even if it was build with a different gcc version.  */
+} __attribute__ ((aligned (8)));
+
+struct mips64_watch_regs
+{
+  uint64_t watchlo[MAX_DEBUG_REGISTER];
+  uint16_t watchhi[MAX_DEBUG_REGISTER];
+  uint16_t watch_masks[MAX_DEBUG_REGISTER];
+  uint32_t num_valid;
+} __attribute__ ((aligned (8)));
+
+struct pt_watch_regs
+{
+  enum pt_watch_style style;
+  union
+  {
+    struct mips32_watch_regs mips32;
+    struct mips64_watch_regs mips64;
+  };
+};
+
+#endif /* !PTRACE_GET_WATCH_REGS */
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
+/* We keep list of all watchpoints we should install and calculate the
+   watch register values each time the list changes.  This allows for
+   easy sharing of watch registers for more than one watchpoint.  */
+
+struct mips_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
+  struct mips_watchpoint *next;
+};
+
+uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n);
+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n);
+void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+				   CORE_ADDR value);
+uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n);
+void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+				   uint16_t value);
+int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				    CORE_ADDR addr, int len, uint32_t irw);
+void mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				     struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_type_to_irw (int type);
+
+int mips_linux_read_watch_registers (long lwpid,
+				     struct pt_watch_regs *watch_readback,
+				     int *watch_readback_valid, int force);
+#endif
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index 2f8e5dd..a4f23e3 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
-	linux-procfs.o linux-ptrace.o
+	linux-procfs.o linux-ptrace.o mips-linux-watch.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
 LOADLIBES = -ldl $(RDYNAMIC)
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index e641ca8..9246741 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -36,6 +36,8 @@
 #include <sys/ptrace.h>
 #include <asm/ptrace.h>
 
+#include "mips-linux-watch.h"
+
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
 #include "features/mips64-linux.c"
@@ -461,71 +463,6 @@ mips_linux_read_description (struct target_ops *ops)
     return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
 }
 
-#define MAX_DEBUG_REGISTER 8
-
-/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
-   have hardware watchpoint-related structures.  Define them below.  */
-
-#ifndef PTRACE_GET_WATCH_REGS
-#  define PTRACE_GET_WATCH_REGS	0xd0
-#  define PTRACE_SET_WATCH_REGS	0xd1
-
-enum pt_watch_style {
-  pt_watch_style_mips32,
-  pt_watch_style_mips64
-};
-
-/* A value of zero in a watchlo indicates that it is available.  */
-
-struct mips32_watch_regs
-{
-  uint32_t watchlo[MAX_DEBUG_REGISTER];
-  /* Lower 16 bits of watchhi.  */
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  /* Valid mask and I R W bits.
-   * bit 0 -- 1 if W bit is usable.
-   * bit 1 -- 1 if R bit is usable.
-   * bit 2 -- 1 if I bit is usable.
-   * bits 3 - 11 -- Valid watchhi mask bits.
-   */
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  /* The number of valid watch register pairs.  */
-  uint32_t num_valid;
-  /* There is confusion across gcc versions about structure alignment,
-     so we force 8 byte alignment for these structures so they match
-     the kernel even if it was build with a different gcc version.  */
-} __attribute__ ((aligned (8)));
-
-struct mips64_watch_regs
-{
-  uint64_t watchlo[MAX_DEBUG_REGISTER];
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  uint32_t num_valid;
-} __attribute__ ((aligned (8)));
-
-struct pt_watch_regs
-{
-  enum pt_watch_style style;
-  union
-  {
-    struct mips32_watch_regs mips32;
-    struct mips64_watch_regs mips64;
-  };
-};
-
-#endif /* !PTRACE_GET_WATCH_REGS */
-
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
-
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
-
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
-
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
@@ -537,18 +474,6 @@ static int watch_readback_valid;
 
 static struct pt_watch_regs watch_readback;
 
-/* We keep list of all watchpoints we should install and calculate the
-   watch register values each time the list changes.  This allows for
-   easy sharing of watch registers for more than one watchpoint.  */
-
-struct mips_watchpoint
-{
-  CORE_ADDR addr;
-  int len;
-  int type;
-  struct mips_watchpoint *next;
-};
-
 static struct mips_watchpoint *current_watches;
 
 /*  The current set of watch register values for writing the
@@ -556,139 +481,6 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers REGS, return the irw_mask of
-   register N.  */
-
-static uint32_t
-mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[n] & IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[n] & IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the reg_mask of
-   register N.  */
-
-static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[n] & ~IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[n] & ~IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the num_valid.  */
-
-static uint32_t
-mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.num_valid;
-    case pt_watch_style_mips64:
-      return regs->mips64.num_valid;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the watchlo of
-   register N.  */
-
-static CORE_ADDR
-mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchlo[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchlo[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, set VALUE to watchlo of
-   register N.  */
-
-static void
-mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
-			      CORE_ADDR value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      /*  The cast will never throw away bits as 64 bit addresses can
-	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[n] = (uint32_t) value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchlo[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the watchhi of
-   register N.  */
-
-static uint32_t
-mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchhi[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchhi[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, set VALUE to watchhi of
-   register N.  */
-
-static void
-mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
-			      uint16_t value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      regs->mips32.watchhi[n] = value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchhi[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
 static void
 mips_show_dr (const char *func, CORE_ADDR addr,
 	      int len, enum target_hw_bp_type type)
@@ -716,67 +508,6 @@ mips_show_dr (const char *func, CORE_ADDR addr,
 							       i)));
 }
 
-/* Read the watch registers of process LWPID and store it in
-   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
-   registers are valid.  Return 1 if watch registers are usable.
-   Cached information is used unless FORCE is true.  */
-
-static int
-mips_linux_read_watch_registers (long lwpid,
-				 struct pt_watch_regs *watch_readback,
-				 int *watch_readback_valid, int force)
-{
-  if (force || *watch_readback_valid == 0)
-    {
-      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
-	{
-	  *watch_readback_valid = -1;
-	  return 0;
-	}
-      switch (watch_readback->style)
-	{
-	case pt_watch_style_mips32:
-	  if (watch_readback->mips32.num_valid == 0)
-	    {
-	      *watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	case pt_watch_style_mips64:
-	  if (watch_readback->mips64.num_valid == 0)
-	    {
-	      *watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	default:
-	  *watch_readback_valid = -1;
-	  return 0;
-	}
-      /* Watch registers appear to be usable.  */
-      *watch_readback_valid = 1;
-    }
-  return (*watch_readback_valid == 1) ? 1 : 0;
-}
-
-/* Convert GDB's TYPE to an IRW mask.  */
-
-static uint32_t
-mips_linux_watch_type_to_irw (int type)
-{
-  switch (type)
-    {
-    case hw_write:
-      return W_MASK;
-    case hw_read:
-      return R_MASK;
-    case hw_access:
-      return (W_MASK | R_MASK);
-    default:
-      return 0;
-    }
-}
-
 /* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
    handle the specified watch type.  */
 
@@ -853,110 +584,6 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in MASK that are not set.  */
-
-static CORE_ADDR
-fill_mask (CORE_ADDR mask)
-{
-  CORE_ADDR f = 1;
-  while (f && f < mask)
-    {
-      mask |= f;
-      f <<= 1;
-    }
-  return mask;
-}
-
-/* Try to add a single watch to the specified registers REGS.  The
-   address of added watch is ADDR, the length is LEN, and the mask
-   is IRW.  Return 1 on success, 0 on failure.  */
-
-static int
-mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
-				CORE_ADDR addr, int len, uint32_t irw)
-{
-  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low;
-  uint16_t t_hi;
-  int i, free_watches;
-  struct pt_watch_regs regs_copy;
-
-  if (len <= 0)
-    return 0;
-
-  last_byte = addr + len - 1;
-  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
-  base_addr = addr & ~mask_bits;
-
-  /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      t_low = mips_linux_watch_get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
-	{
-	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR) t_hi;
-	  if (addr >= t_low && last_byte <= (t_low + t_hi))
-	    return 1;
-	}
-    }
-  /* Try to find an empty register.  */
-  free_watches = 0;
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      t_low = mips_linux_watch_get_watchlo (regs, i);
-      if (t_low == 0
-	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
-	{
-	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
-	    {
-	      /* It fits, we'll take it.  */
-	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
-	      mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
-	      return 1;
-	    }
-	  else
-	    {
-	      /* It doesn't fit, but has the proper IRW capabilities.  */
-	      free_watches++;
-	    }
-	}
-    }
-  if (free_watches > 1)
-    {
-      /* Try to split it across several registers.  */
-      regs_copy = *regs;
-      for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
-	{
-	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
-	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
-	  if (t_low == 0 && irw == (t_hi & irw))
-	    {
-	      t_low = addr & ~(CORE_ADDR) t_hi;
-	      break_addr = t_low + t_hi + 1;
-	      if (break_addr >= addr + len)
-		segment_len = len;
-	      else
-		segment_len = break_addr - addr;
-	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      mips_linux_watch_set_watchlo (&regs_copy, i,
-					    (addr & ~mask_bits) | irw);
-	      mips_linux_watch_set_watchhi (&regs_copy, i,
-					    mask_bits & ~IRW_MASK);
-	      if (break_addr >= addr + len)
-		{
-		  *regs = regs_copy;
-		  return 1;
-		}
-	      len = addr + len - break_addr;
-	      addr = break_addr;
-	    }
-	}
-    }
-  /* It didn't fit anywhere, we failed.  */
-  return 0;
-}
-
 /* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
    the specified region can be covered by the watch registers.  */
 
@@ -1013,36 +640,6 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers REGS with the currently cached
-   watches CURRENT_WATCHES.  */
-
-static void
-mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
-				struct pt_watch_regs *regs)
-{
-  struct mips_watchpoint *w;
-  int i;
-
-  /* Clear them out.  */
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      mips_linux_watch_set_watchlo (regs, i, 0);
-      mips_linux_watch_set_watchhi (regs, i, 0);
-    }
-
-  w = current_watches;
-  while (w)
-    {
-      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
-
-      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
-      /* They must all fit, because we previously calculated that they
-	 would.  */
-      gdb_assert (i);
-      w = w->next;
-    }
-}
-
 /* Target to_insert_watchpoint implementation.  Try to insert a new
    watch.  Return zero on success.  */
 
-- 
1.7.7.6


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

* Re: [PATCH 5/5] MIPS GDBserver watchpoint
  2013-07-24  0:35     ` Maciej W. Rozycki
@ 2013-07-25  0:17       ` Yao Qi
  2013-07-25 21:20         ` Maciej W. Rozycki
  0 siblings, 1 reply; 52+ messages in thread
From: Yao Qi @ 2013-07-25  0:17 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/24/2013 08:34 AM, Maciej W. Rozycki wrote:
>> +static enum target_hw_bp_type
>> >+rsp_bp_type_to_target_hw_bp_type (char type)
>> >+{
>> >+  switch (type)
>> >+    {
>> >+    case '2':
>> >+      return hw_write;
>> >+    case '3':
>> >+      return hw_read;
>> >+    case '4':
>> >+      return hw_access;
>> >+    }
>> >+
>> >+  return -1;
>   This looks unclean to me, you're returning a value that's outside the
> valid range of the enum type used.  By the structure of the callers this
> code is expected to be dead though, so please use gdb_assert_not_reached.

OK, gdb_assert_not_reached is added.

> 
>   Please resend with the adjustment requested, the change looks otherwise
> OK to me.

Here is the updated patch, with adding more words in ChangeLog to
address Pedro's comment.

-- 
Yao (齐尧)

gdb/gdbserver:

2013-07-25  Jie Zhang  <jie@codesourcery.com>
	    Daniel Jacobowitz  <dan@codesourcery.com>
	    Yao Qi  <yao@codesourcery.com>

	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
	(mips-linux-watch.o): New rule.
	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to
	srv_tgtobj.
	* linux-mips-low.c: Include mips-linux-watch.h.
	(struct arch_process_info, struct arch_lwp_info): New.
	(update_watch_registers_callback): New.
	(mips_linux_new_process, mips_linux_new_thread) New.
	(mips_linux_prepare_to_resume, mips_insert_point): New.
	(mips_remove_point, mips_stopped_by_watchpoint): New.
	(rsp_bp_type_to_target_hw_bp_type): New.
	(mips_stopped_data_address): New.
	(the_low_target): Add watchpoint support functions.

gdb:

2013-07-25  Yao Qi  <yao@codesourcery.com>

	* NEWS: Mention that GDBserver now supports hardware
	watchpoints on the MIPS GNU/Linux target.
---
 gdb/NEWS                       |    3 +
 gdb/gdbserver/Makefile.in      |    7 +-
 gdb/gdbserver/configure.srv    |    1 +
 gdb/gdbserver/linux-mips-low.c |  366 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 376 insertions(+), 1 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index a4238d0..31a8bc6 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -128,6 +128,9 @@ qXfer:libraries-svr4:read's annex
      'qXfer:traceframe-info:read'.  It has the id of the collected
      trace state variables.
 
+  ** GDBserver now supports hardware watchpoints on the MIPS GNU/Linux
+     target.
+
 *** Changes in GDB 7.6
 
 * Target record has been renamed to record-full.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 2cbf208..fe16cb4 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -157,7 +157,7 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
 	$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
 	$(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \
-	$(srcdir)/common/filestuff.c
+	$(srcdir)/common/filestuff.c $(srcdir)/common/mips-linux-watch.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -457,6 +457,8 @@ lynx_low_h = $(srcdir)/lynx-low.h $(srcdir)/server.h
 
 nto_low_h = $(srcdir)/nto-low.h
 
+mips_linux_watch_h = $(srcdir)/../common/mips-linux-watch.h
+
 UST_CFLAGS = $(ustinc) -DCONFIG_UST_GDB_INTEGRATION
 
 # Note, we only build the IPA if -fvisibility=hidden is supported in
@@ -552,6 +554,9 @@ agent.o: ../common/agent.c
 linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
 
+mips-linux-watch.o: ../common/mips-linux-watch.c $(mips_linux_watch_h) $(server_h)
+	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+
 # We build vasprintf with -DHAVE_CONFIG_H because we want that unit to
 # include our config.h file.  Otherwise, some system headers do not get
 # included, and the compiler emits a warning about implicitly defined
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 879d0de..b9dfd6c 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -184,6 +184,7 @@ case "${target}" in
 			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
 			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+			srv_tgtobj="${srv_tgtobj} mips-linux-watch.o"
 			srv_xmlfiles="mips-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml"
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 1010528..dd6ebaf 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -22,6 +22,7 @@
 #include <sys/ptrace.h>
 #include <endian.h>
 
+#include "mips-linux-watch.h"
 #include "gdb_proc_service.h"
 
 /* Defined in auto-generated file mips-linux.c.  */
@@ -159,6 +160,39 @@ get_usrregs_info (void)
   return regs_info->usrregs;
 }
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  /* -1 if the kernel and/or CPU do not support watch registers.
+      1 if watch_readback is valid and we can read style, num_valid
+	and the masks.
+      0 if we need to read the watch_readback.  */
+
+  int watch_readback_valid;
+
+  /* Cached watch register read values.  */
+
+  struct pt_watch_regs watch_readback;
+
+  /* Current watchpoint requests for this process.  */
+
+  struct mips_watchpoint *current_watches;
+
+  /* The current set of watch register values for writing the
+     registers.  */
+
+  struct pt_watch_regs watch_mirror;
+};
+
+/* 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 watch_registers_changed;
+};
+
 /* From mips-linux-nat.c.  */
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
@@ -257,6 +291,328 @@ mips_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Mark the watch registers of lwp, represented by ENTRY, as changed,
+   if the lwp's process id is *PID_P.  */
+
+static int
+update_watch_registers_callback (struct inferior_list_entry *entry,
+				 void *pid_p)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  int pid = *(int *) pid_p;
+
+  /* Only update the threads of this process.  */
+  if (pid_of (lwp) == pid)
+    {
+      /* The actual update is done later just before resuming the lwp,
+	 we just mark that the registers need updating.  */
+      lwp->arch_private->watch_registers_changed = 1;
+
+      /* If the lwp isn't stopped, force it to momentarily pause, so
+	 we can update its watch registers.  */
+      if (!lwp->stopped)
+	linux_stop_lwp (lwp);
+    }
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   new_process.  */
+
+static struct arch_process_info *
+mips_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method new_thread.
+   Mark the watch registers as changed, so the threads' copies will
+   be updated.  */
+
+static struct arch_lwp_info *
+mips_linux_new_thread (void)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->watch_registers_changed = 1;
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method
+   prepare_to_resume.  If the watch regs have changed, update the
+   thread's copies.  */
+
+static void
+mips_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  ptid_t ptid = ptid_of (lwp);
+  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
+  struct arch_process_info *private = proc->private->arch_private;
+
+  if (lwp->arch_private->watch_registers_changed)
+    {
+      /* Only update the watch registers if we have set or unset a
+	 watchpoint already.  */
+      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
+	{
+	  /* Write the mirrored watch register values.  */
+	  int tid = ptid_get_lwp (ptid);
+
+	  if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
+			    &private->watch_mirror))
+	    perror_with_name ("Couldn't write watch register");
+	}
+
+      lwp->arch_private->watch_registers_changed = 0;
+    }
+}
+
+/* Translate breakpoint type TYPE in rsp to 'enum target_hw_bp_type'.  */
+
+static enum target_hw_bp_type
+rsp_bp_type_to_target_hw_bp_type (char type)
+{
+  switch (type)
+    {
+    case '2':
+      return hw_write;
+    case '3':
+      return hw_read;
+    case '4':
+      return hw_access;
+    }
+
+  gdb_assert_not_reached ("unhandled RSP breakpoint type");
+  return -1;
+}
+
+/* This is the implementation of linux_target_ops method
+   insert_point.  */
+
+static int
+mips_insert_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  struct pt_watch_regs regs;
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+  int pid;
+  long lwpid;
+  enum target_hw_bp_type watch_type;
+  uint32_t irw;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  lwpid = lwpid_of (get_thread_lwp (current_inferior));
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = private->watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (private->current_watches, &regs);
+
+  /* Now try to add the new watch.  */
+  watch_type = rsp_bp_type_to_target_hw_bp_type (type);
+  irw = mips_linux_watch_type_to_irw (watch_type);
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len, irw))
+    return -1;
+
+  /* It fit.  Stick it on the end of the list.  */
+  new_watch = xmalloc (sizeof (struct mips_watchpoint));
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = watch_type;
+  new_watch->next = NULL;
+
+  pw = &private->current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+
+  private->watch_mirror = regs;
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_watch_registers_callback, &pid);
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   remove_point.  */
+
+static int
+mips_remove_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+
+  int deleted_one;
+  int pid;
+  enum target_hw_bp_type watch_type;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  /* Search for a known watch that matches.  Then unlink and free it.  */
+  watch_type = rsp_bp_type_to_target_hw_bp_type (type);
+  deleted_one = 0;
+  pw = &private->current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == watch_type)
+	{
+	  *pw = w->next;
+	  free (w);
+	  deleted_one = 1;
+	  break;
+	}
+      pw = &(w->next);
+    }
+
+  if (!deleted_one)
+    return -1;  /* We don't know about it, fail doing nothing.  */
+
+  /* At this point watch_readback is known to be valid because we
+     could not have added the watch without reading it.  */
+  gdb_assert (private->watch_readback_valid == 1);
+
+  private->watch_mirror = private->watch_readback;
+  mips_linux_watch_populate_regs (private->current_watches,
+				  &private->watch_mirror);
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_watch_registers_callback, &pid);
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_by_watchpoint.  The watchhi R and W bits indicate
+   the watch register triggered. */
+
+static int
+mips_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					1))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      return 1;
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_data_address.  */
+
+static CORE_ADDR
+mips_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  /* On MIPS we don't know the low order 3 bits of the data address.
+     GDB does not support remote targets that can't report the
+     watchpoint address.  So, make our best guess; return the starting
+     address of a watchpoint request which overlaps the one that
+     triggered.  */
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      {
+	CORE_ADDR t_low, t_hi;
+	int t_irw;
+	struct mips_watchpoint *watch;
+
+	t_low = mips_linux_watch_get_watchlo (&private->watch_readback, n);
+	t_irw = t_low & IRW_MASK;
+	t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+		| IRW_MASK);
+	t_low &= ~(CORE_ADDR)t_hi;
+
+	for (watch = private->current_watches;
+	     watch != NULL;
+	     watch = watch->next)
+	  {
+	    CORE_ADDR addr = watch->addr;
+	    CORE_ADDR last_byte = addr + watch->len - 1;
+
+	    if ((t_irw & mips_linux_watch_type_to_irw (watch->type)) == 0)
+	      {
+		/* Different type.  */
+		continue;
+	      }
+	    /* Check for overlap of even a single byte.  */
+	    if (last_byte >= t_low && addr <= t_low + t_hi)
+	      return addr;
+	  }
+      }
+
+  /* Shouldn't happen.  */
+  return 0;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -506,6 +862,16 @@ struct linux_target_ops the_low_target = {
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
+  mips_insert_point,
+  mips_remove_point,
+  mips_stopped_by_watchpoint,
+  mips_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, /* siginfo_fixup */
+  mips_linux_new_process,
+  mips_linux_new_thread,
+  mips_linux_prepare_to_resume
 };
 
 void
-- 
1.7.7.6


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

* Re: [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-07-25  0:07       ` Yao Qi
@ 2013-07-25 21:17         ` Maciej W. Rozycki
  2013-07-28  0:47           ` Yao Qi
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-25 21:17 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 25 Jul 2013, Yao Qi wrote:

> OK, I keep <asm/ptrace.h> inclusion in the updated patch
> below.  The functions order is fixed in the updated patch
> too.

 Thanks.  This shows the following changes that you made in the process of 
moving the functions across.  They are fine with me, but I prefer to have 
them included with 3/5 where changes are supposed to be made, so please 
move them there.

--- gdb/mips-linux-nat.c~	2013-07-25 17:15:17.318692194 +0100
+++ gdb/common/mips-linux-watch.c	2013-07-25 17:15:32.318690373 +0100
@@ -627,10 +90,10 @@ mips_linux_watch_get_watchlo (struct pt_
     }
 }
 
-/* Assuming usable watch registers REGS, set VALUE to watchlo of
+/* Assuming usable watch registers REGS, set a watchlo VALUE of
    register N.  */
 
[...]
@@ -668,10 +131,10 @@ mips_linux_watch_get_watchhi (struct pt_
     }
 }
 
-/* Assuming usable watch registers REGS, set VALUE to watchhi of
+/* Assuming usable watch registers REGS, set a watchhi VALUE of
    register N.  */
 
[...]
 fill_mask (CORE_ADDR mask)
 {
   CORE_ADDR f = 1;
+
   while (f && f < mask)
     {
       mask |= f;

 OK with this change, thanks.

 [The wording of the function descriptions is a bit unfortunate, but 
that's a preexisting problem, so you don't need to do anything about them 
unless you want to (e.g. "[...] set watchlo of register N to VALUE." would 
be better).]

  Maciej


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

* Re: [PATCH 5/5] MIPS GDBserver watchpoint
  2013-07-25  0:17       ` Yao Qi
@ 2013-07-25 21:20         ` Maciej W. Rozycki
  2013-07-28  0:49           ` Yao Qi
  0 siblings, 1 reply; 52+ messages in thread
From: Maciej W. Rozycki @ 2013-07-25 21:20 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

On Thu, 25 Jul 2013, Yao Qi wrote:

> gdb/gdbserver:
> 
> 2013-07-25  Jie Zhang  <jie@codesourcery.com>
> 	    Daniel Jacobowitz  <dan@codesourcery.com>
> 	    Yao Qi  <yao@codesourcery.com>
> 
> 	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
> 	(mips-linux-watch.o): New rule.

 You've lost an entry for mips_linux_watch_h:

	(mips_linux_watch_h): New variable.

should do.

> 	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to
> 	srv_tgtobj.
> 	* linux-mips-low.c: Include mips-linux-watch.h.
> 	(struct arch_process_info, struct arch_lwp_info): New.
> 	(update_watch_registers_callback): New.
> 	(mips_linux_new_process, mips_linux_new_thread) New.
> 	(mips_linux_prepare_to_resume, mips_insert_point): New.
> 	(mips_remove_point, mips_stopped_by_watchpoint): New.
> 	(rsp_bp_type_to_target_hw_bp_type): New.
> 	(mips_stopped_data_address): New.
> 	(the_low_target): Add watchpoint support functions.

 Please name entity types, e.g.: "New function.", "New variables.", etc.
as applicable.

> diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
> index 1010528..dd6ebaf 100644
> --- a/gdb/gdbserver/linux-mips-low.c
> +++ b/gdb/gdbserver/linux-mips-low.c
> @@ -257,6 +291,328 @@ mips_breakpoint_at (CORE_ADDR where)
>    return 0;
>  }
>  
> +/* Mark the watch registers of lwp, represented by ENTRY, as changed,
> +   if the lwp's process id is *PID_P.  */
> +
> +static int
> +update_watch_registers_callback (struct inferior_list_entry *entry,
> +				 void *pid_p)
> +{
> +  struct lwp_info *lwp = (struct lwp_info *) entry;
> +  int pid = *(int *) pid_p;
> +
> +  /* Only update the threads of this process.  */
> +  if (pid_of (lwp) == pid)
> +    {
> +      /* The actual update is done later just before resuming the lwp,
> +	 we just mark that the registers need updating.  */
> +      lwp->arch_private->watch_registers_changed = 1;
> +
> +      /* If the lwp isn't stopped, force it to momentarily pause, so
> +	 we can update its watch registers.  */
> +      if (!lwp->stopped)
> +	linux_stop_lwp (lwp);
> +    }
> +
> +  return 0;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   new_process.  */
> +
> +static struct arch_process_info *
> +mips_linux_new_process (void)
> +{
> +  struct arch_process_info *info = xcalloc (1, sizeof (*info));
> +
> +  return info;
> +}
> +
> +/* This is the implementation of linux_target_ops method new_thread.
> +   Mark the watch registers as changed, so the threads' copies will
> +   be updated.  */
> +
> +static struct arch_lwp_info *
> +mips_linux_new_thread (void)
> +{
> +  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
> +
> +  info->watch_registers_changed = 1;
> +
> +  return info;
> +}
> +
> +/* This is the implementation of linux_target_ops method
> +   prepare_to_resume.  If the watch regs have changed, update the
> +   thread's copies.  */
> +
> +static void
> +mips_linux_prepare_to_resume (struct lwp_info *lwp)
> +{
> +  ptid_t ptid = ptid_of (lwp);
> +  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
> +  struct arch_process_info *private = proc->private->arch_private;
> +
> +  if (lwp->arch_private->watch_registers_changed)
> +    {
> +      /* Only update the watch registers if we have set or unset a
> +	 watchpoint already.  */
> +      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
> +	{
> +	  /* Write the mirrored watch register values.  */
> +	  int tid = ptid_get_lwp (ptid);
> +
> +	  if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
> +			    &private->watch_mirror))
> +	    perror_with_name ("Couldn't write watch register");
> +	}
> +
> +      lwp->arch_private->watch_registers_changed = 0;
> +    }
> +}
> +
> +/* Translate breakpoint type TYPE in rsp to 'enum target_hw_bp_type'.  */
> +
> +static enum target_hw_bp_type
> +rsp_bp_type_to_target_hw_bp_type (char type)
> +{
> +  switch (type)
> +    {
> +    case '2':
> +      return hw_write;
> +    case '3':
> +      return hw_read;
> +    case '4':
> +      return hw_access;
> +    }
> +
> +  gdb_assert_not_reached ("unhandled RSP breakpoint type");
> +  return -1;
> +}

 gdb_assert_not_reached is `__attribute__ ((noreturn))', so there's no 
need for the `return -1' statement.  Please remove it.

 OK with this change and the ChangeLog updates, thanks for your work.

  Maciej


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

* Re: [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver.
  2013-07-24 14:04       ` Tom Tromey
@ 2013-07-28  0:41         ` Yao Qi
  0 siblings, 0 replies; 52+ messages in thread
From: Yao Qi @ 2013-07-28  0:41 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Maciej W. Rozycki, gdb-patches

On 07/24/2013 10:03 PM, Tom Tromey wrote:
> This patch is ok.

Patch is committed.

-- 
Yao (齐尧)


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

* Re: [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c
  2013-07-24  0:26     ` Maciej W. Rozycki
@ 2013-07-28  0:43       ` Yao Qi
  0 siblings, 0 replies; 52+ messages in thread
From: Yao Qi @ 2013-07-28  0:43 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/24/2013 08:26 AM, Maciej W. Rozycki wrote:
> #endif /* !PTRACE_GET_WATCH_REGS */
> 
> please.

OK.
> 
>> >+
>> >+#ifndef PTRACE_SET_WATCH_REGS
>> >+#  define PTRACE_SET_WATCH_REGS	0xd1
>> >+#endif
>   With the inclusion of the kernel header I think there's no need to wrap
> this definition separately -- a system header configuration where
> PTRACE_GET_WATCH_REGS is defined but PTRACE_SET_WATCH_REGS is not would be
> broken and could not be relied upon anyway.  Please just use:
> 
> #ifndef PTRACE_GET_WATCH_REGS
> #  define PTRACE_GET_WATCH_REGS	0xd0
> #  define PTRACE_SET_WATCH_REGS	0xd1
> [...]
> 

Fixed.

> instead.  OK with these changes, thanks.

Patch below is what I committed.

-- 
Yao (齐尧)

---
 gdb/ChangeLog        |   13 +++++++++++++
 gdb/mips-linux-nat.c |   34 ++++++++++++++++++----------------
 2 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 94d5c12..6350b53 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,18 @@
 2013-07-27  Yao Qi  <yao@codesourcery.com>
 
+	* mips-linux-nat.c (MAX_DEBUG_REGISTER): Move it earlier in
+	the code.
+	(PTRACE_SET_WATCH_REGS, enum pt_watch_style): Remove.
+	(struct mips32_watch_regs, struct mips64_watch_regs): Remove.
+	(struct pt_watch_regs): Likewise.
+	[!PTRACE_GET_WATCH_REGS] (PTRACE_SET_WATCH_REGS): New macro.
+	[!PTRACE_GET_WATCH_REGS] (enum pt_watch_style): New.
+	[!PTRACE_GET_WATCH_REGS] (struct mips32_watch_regs): New.
+	[!PTRACE_GET_WATCH_REGS] (struct mips64_watch_regs): New.
+	[!PTRACE_GET_WATCH_REGS] (struct pt_watch_regs): New.
+
+2013-07-27  Yao Qi  <yao@codesourcery.com>
+
 	* breakpoint.h: Include break-common.h.
 	(enum target_hw_bp_type): Move to ...
 	* common/break-common.h: ... here.  New.
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index d323a82..63cc140 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -34,6 +34,7 @@
 
 #include <sgidefs.h>
 #include <sys/ptrace.h>
+#include <asm/ptrace.h>
 
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
@@ -460,31 +461,20 @@ mips_linux_read_description (struct target_ops *ops)
     return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
 }
 
+#define MAX_DEBUG_REGISTER 8
+
+/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
+   have hardware watchpoint-related structures.  Define them below.  */
+
 #ifndef PTRACE_GET_WATCH_REGS
 #  define PTRACE_GET_WATCH_REGS	0xd0
-#endif
-
-#ifndef PTRACE_SET_WATCH_REGS
 #  define PTRACE_SET_WATCH_REGS	0xd1
-#endif
-
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
-
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
-
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
 
 enum pt_watch_style {
   pt_watch_style_mips32,
   pt_watch_style_mips64
 };
 
-#define MAX_DEBUG_REGISTER 8
-
 /* A value of zero in a watchlo indicates that it is available.  */
 
 struct mips32_watch_regs
@@ -524,6 +514,18 @@ struct pt_watch_regs
   };
 };
 
+#endif /* !PTRACE_GET_WATCH_REGS */
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
-- 
1.7.7.6


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

* Re: [PATCH 3/5] Refactor in mips-linux-nat.c
  2013-07-24  0:27     ` Maciej W. Rozycki
@ 2013-07-28  0:44       ` Yao Qi
  0 siblings, 0 replies; 52+ messages in thread
From: Yao Qi @ 2013-07-28  0:44 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/24/2013 08:26 AM, Maciej W. Rozycki wrote:
>   This fits on one line, please adjust.
> 
>> >@@ -910,21 +930,25 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
>> >      {
>> >        /* Try to split it across several registers.  */
>> >        regs_copy = *regs;
>> >-      for (i = 0; i < get_num_valid (&regs_copy); i++)
>> >+      for (i = 0;
>> >+	   i < mips_linux_watch_get_num_valid (&regs_copy);
>> >+	   i++)
>   Likewise.  OK with these changes, thanks.

Fixed.  Patch below is what I committed.

-- 
Yao (齐尧)

---
 gdb/ChangeLog        |   36 +++++++++
 gdb/mips-linux-nat.c |  206 +++++++++++++++++++++++++++++---------------------
 2 files changed, 155 insertions(+), 87 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 6350b53..2259dd4 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,41 @@
 2013-07-27  Yao Qi  <yao@codesourcery.com>
 
+	* mips-linux-nat.c (get_irw_mask): Rename to ...
+	(mips_linux_watch_get_irw_mask): ... this.  Rename parameter
+	'set' to 'n'.  Update function comment.  All callers changed.
+	(get_reg_mask): Rename parameter 'set' to 'n'.  Update
+	function comment.  All callers changed.
+	(get_num_valid): Rename to ...
+	(mips_linux_watch_get_num_valid): ... this.  Rename parameter
+	'set' to 'n'.  Update function comment.  All callers changed.
+	(get_watchlo): Rename to ...
+	(mips_linux_watch_get_watchlo): ... this.  Rename parameter
+	'set' to 'n'.  Update function comment.  All callers changed.
+	(set_watchlo): Rename to ...
+	(mips_linux_watch_set_watchlo): ... this.  Rename parameter
+	'set' to 'n'.  Update function comment.  All callers changed.
+	(get_watchhi): Rename to ...
+	(mips_linux_watch_get_watchhi): ... this.  Update function
+	comment.  All callers changed.
+	(set_watchhi): Rename to ...
+	(mips_linux_watch_set_watchhi): ... this.  Update function
+	comment.  All callers changed.
+	(mips_linux_read_watch_registers): Update function comment.
+	Add new parameters 'lwpid', 'watch_readback', and
+	'watch_readback_valid'.  Update.
+	(type_to_irw): Rename to ...
+	(mips_linux_watch_type_to_irw): ... this.  Update function
+	comment.  All callers changed.
+	(fill_mask): Update function comment.
+	(try_one_watch): Rename to ...
+	(mips_linux_watch_try_one_watch): ... this.  Change the type
+	of parameter 'irw' from 'unsigned' to 'uint32_t'.
+	(populate_regs_from_watches): Rename to ...
+	(mips_linux_watch_populate_regs): ... this.  Add parameter
+	'current_watches'.  All callers changed.
+
+2013-07-27  Yao Qi  <yao@codesourcery.com>
+
 	* mips-linux-nat.c (MAX_DEBUG_REGISTER): Move it earlier in
 	the code.
 	(PTRACE_SET_WATCH_REGS, enum pt_watch_style): Remove.
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index 63cc140..d792cb3 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -556,44 +556,46 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers, return the irw_mask.  */
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
 
 static uint32_t
-get_irw_mask (struct pt_watch_regs *regs, int set)
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & IRW_MASK;
+      return regs->mips32.watch_masks[n] & IRW_MASK;
     case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & IRW_MASK;
+      return regs->mips64.watch_masks[n] & IRW_MASK;
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unrecognized watch register style"));
     }
 }
 
-/* Assuming usable watch registers, return the reg_mask.  */
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
 
 static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int set)
+get_reg_mask (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[set] & ~IRW_MASK;
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
     case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[set] & ~IRW_MASK;
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unrecognized watch register style"));
     }
 }
 
-/* Assuming usable watch registers, return the num_valid.  */
+/* Assuming usable watch registers REGS, return the num_valid.  */
 
 static uint32_t
-get_num_valid (struct pt_watch_regs *regs)
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
 {
   switch (regs->style)
     {
@@ -607,37 +609,40 @@ get_num_valid (struct pt_watch_regs *regs)
     }
 }
 
-/* Assuming usable watch registers, return the watchlo.  */
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
 
 static CORE_ADDR
-get_watchlo (struct pt_watch_regs *regs, int set)
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
-      return regs->mips32.watchlo[set];
+      return regs->mips32.watchlo[n];
     case pt_watch_style_mips64:
-      return regs->mips64.watchlo[set];
+      return regs->mips64.watchlo[n];
     default:
       internal_error (__FILE__, __LINE__,
 		      _("Unrecognized watch register style"));
     }
 }
 
-/* Assuming usable watch registers, set a watchlo value.  */
+/* Assuming usable watch registers REGS, set watchlo of register N to
+   VALUE.  */
 
 static void
-set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
 {
   switch (regs->style)
     {
     case pt_watch_style_mips32:
       /*  The cast will never throw away bits as 64 bit addresses can
 	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[set] = (uint32_t)value;
+      regs->mips32.watchlo[n] = (uint32_t) value;
       break;
     case pt_watch_style_mips64:
-      regs->mips64.watchlo[set] = value;
+      regs->mips64.watchlo[n] = value;
       break;
     default:
       internal_error (__FILE__, __LINE__,
@@ -645,10 +650,11 @@ set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
     }
 }
 
-/* Assuming usable watch registers, return the watchhi.  */
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
 
 static uint32_t
-get_watchhi (struct pt_watch_regs *regs, int n)
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
 {
   switch (regs->style)
     {
@@ -662,10 +668,12 @@ get_watchhi (struct pt_watch_regs *regs, int n)
     }
 }
 
-/* Assuming usable watch registers, set a watchhi value.  */
+/* Assuming usable watch registers REGS, set watchhi of register N to
+   VALUE.  */
 
 static void
-set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
 {
   switch (regs->style)
     {
@@ -701,57 +709,60 @@ mips_show_dr (const char *func, CORE_ADDR addr,
   for (i = 0; i < MAX_DEBUG_REGISTER; i++)
     printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
 		       paddress (target_gdbarch (),
-				 get_watchlo (&watch_mirror, i)),
+				 mips_linux_watch_get_watchlo (&watch_mirror,
+							       i)),
 		       paddress (target_gdbarch (),
-				 get_watchhi (&watch_mirror, i)));
+				 mips_linux_watch_get_watchhi (&watch_mirror,
+							       i)));
 }
 
-/* Return 1 if watch registers are usable.  Cached information is used
-   unless force is true.  */
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
 
 static int
-mips_linux_read_watch_registers (int force)
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
 {
-  int tid;
-
-  if (force || watch_readback_valid == 0)
+  if (force || *watch_readback_valid == 0)
     {
-      tid = ptid_get_lwp (inferior_ptid);
-      if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
 	{
-	  watch_readback_valid = -1;
+	  *watch_readback_valid = -1;
 	  return 0;
 	}
-      switch (watch_readback.style)
+      switch (watch_readback->style)
 	{
 	case pt_watch_style_mips32:
-	  if (watch_readback.mips32.num_valid == 0)
+	  if (watch_readback->mips32.num_valid == 0)
 	    {
-	      watch_readback_valid = -1;
+	      *watch_readback_valid = -1;
 	      return 0;
 	    }
 	  break;
 	case pt_watch_style_mips64:
-	  if (watch_readback.mips64.num_valid == 0)
+	  if (watch_readback->mips64.num_valid == 0)
 	    {
-	      watch_readback_valid = -1;
+	      *watch_readback_valid = -1;
 	      return 0;
 	    }
 	  break;
 	default:
-	  watch_readback_valid = -1;
+	  *watch_readback_valid = -1;
 	  return 0;
 	}
       /* Watch registers appear to be usable.  */
-      watch_readback_valid = 1;
+      *watch_readback_valid = 1;
     }
-  return (watch_readback_valid == 1) ? 1 : 0;
+  return (*watch_readback_valid == 1) ? 1 : 0;
 }
 
-/* Convert GDB's type to an IRW mask.  */
+/* Convert GDB's TYPE to an IRW mask.  */
 
-static unsigned
-type_to_irw (int type)
+static uint32_t
+mips_linux_watch_type_to_irw (int type)
 {
   switch (type)
     {
@@ -775,7 +786,9 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
   int i;
   uint32_t wanted_mask, irw_mask;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
    switch (type)
@@ -793,9 +806,11 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
       return 0;
     }
  
-  for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
+  for (i = 0;
+       i < mips_linux_watch_get_num_valid (&watch_readback) && cnt;
+       i++)
     {
-      irw_mask = get_irw_mask (&watch_readback, i);
+      irw_mask = mips_linux_watch_get_irw_mask (&watch_readback, i);
       if ((irw_mask & wanted_mask) == wanted_mask)
 	cnt--;
     }
@@ -812,13 +827,15 @@ mips_linux_stopped_by_watchpoint (void)
   int n;
   int num_valid;
 
-  if (!mips_linux_read_watch_registers (1))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 1))
     return 0;
 
-  num_valid = get_num_valid (&watch_readback);
+  num_valid = mips_linux_watch_get_num_valid (&watch_readback);
 
   for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
-    if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
+    if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
       return 1;
 
   return 0;
@@ -836,12 +853,13 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in mask that are not set.  */
+/* Set any low order bits in MASK that are not set.  */
 
 static CORE_ADDR
 fill_mask (CORE_ADDR mask)
 {
   CORE_ADDR f = 1;
+
   while (f && f < mask)
     {
       mask |= f;
@@ -850,15 +868,16 @@ fill_mask (CORE_ADDR mask)
   return mask;
 }
 
-/* Try to add a single watch to the specified registers.  Return 1 on
-   success, 0 on failure.  */
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
 
 static int
-try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
-	       int len, unsigned irw)
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, uint32_t irw)
 {
   CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low, t_low_end;
+  CORE_ADDR mask_bits, t_low;
   uint16_t t_hi;
   int i, free_watches;
   struct pt_watch_regs regs_copy;
@@ -871,29 +890,30 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
   base_addr = addr & ~mask_bits;
 
   /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < get_num_valid (regs); i++)
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
     {
-      t_low = get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((unsigned)t_low & irw))
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
 	{
-	  t_hi = get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR)t_hi;
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
 	  if (addr >= t_low && last_byte <= (t_low + t_hi))
 	    return 1;
 	}
     }
   /* Try to find an empty register.  */
   free_watches = 0;
-  for (i = 0; i < get_num_valid (regs); i++)
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
     {
-      t_low = get_watchlo (regs, i);
-      if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
 	{
 	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
 	    {
 	      /* It fits, we'll take it.  */
-	      set_watchlo (regs, i, base_addr | irw);
-	      set_watchhi (regs, i, mask_bits & ~IRW_MASK);
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
 	      return 1;
 	    }
 	  else
@@ -907,21 +927,23 @@ try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
     {
       /* Try to split it across several registers.  */
       regs_copy = *regs;
-      for (i = 0; i < get_num_valid (&regs_copy); i++)
+      for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
 	{
-	  t_low = get_watchlo (&regs_copy, i);
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
 	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
 	  if (t_low == 0 && irw == (t_hi & irw))
 	    {
-	      t_low = addr & ~(CORE_ADDR)t_hi;
+	      t_low = addr & ~(CORE_ADDR) t_hi;
 	      break_addr = t_low + t_hi + 1;
 	      if (break_addr >= addr + len)
 		segment_len = len;
 	      else
 		segment_len = break_addr - addr;
 	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      set_watchlo (&regs_copy, i, (addr & ~mask_bits) | irw);
-	      set_watchhi (&regs_copy, i, mask_bits & ~IRW_MASK);
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
 	      if (break_addr >= addr + len)
 		{
 		  *regs = regs_copy;
@@ -945,17 +967,18 @@ mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
   struct pt_watch_regs dummy_regs;
   int i;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return 0;
 
   dummy_regs = watch_readback;
   /* Clear them out.  */
-  for (i = 0; i < get_num_valid (&dummy_regs); i++)
-    set_watchlo (&dummy_regs, i, 0);
-  return try_one_watch (&dummy_regs, addr, len, 0);
+  for (i = 0; i < mips_linux_watch_get_num_valid (&dummy_regs); i++)
+    mips_linux_watch_set_watchlo (&dummy_regs, i, 0);
+  return mips_linux_watch_try_one_watch (&dummy_regs, addr, len, 0);
 }
 
-
 /* Write the mirrored watch register values for each thread.  */
 
 static int
@@ -981,7 +1004,9 @@ mips_linux_new_thread (struct lwp_info *lp)
 {
   int tid;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return;
 
   tid = ptid_get_lwp (lp->ptid);
@@ -989,25 +1014,29 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers with the currently cached watches.  */
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
 
 static void
-populate_regs_from_watches (struct pt_watch_regs *regs)
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
 {
   struct mips_watchpoint *w;
   int i;
 
   /* Clear them out.  */
-  for (i = 0; i < get_num_valid (regs); i++)
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
     {
-      set_watchlo (regs, i, 0);
-      set_watchhi (regs, i, 0);
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
     }
 
   w = current_watches;
   while (w)
     {
-      i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
+      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
       /* They must all fit, because we previously calculated that they
 	 would.  */
       gdb_assert (i);
@@ -1029,7 +1058,9 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
   int i;
   int retval;
 
-  if (!mips_linux_read_watch_registers (0))
+  if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
+					&watch_readback,
+					&watch_readback_valid, 0))
     return -1;
 
   if (len <= 0)
@@ -1037,10 +1068,11 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
 
   regs = watch_readback;
   /* Add the current watches.  */
-  populate_regs_from_watches (&regs);
+  mips_linux_watch_populate_regs (current_watches, &regs);
 
   /* Now try to add the new watch.  */
-  if (!try_one_watch (&regs, addr, len, type_to_irw (type)))
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len,
+				       mips_linux_watch_type_to_irw (type)))
     return -1;
 
   /* It fit.  Stick it on the end of the list.  */
@@ -1102,7 +1134,7 @@ mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
   gdb_assert (watch_readback_valid == 1);
 
   watch_mirror = watch_readback;
-  populate_regs_from_watches (&watch_mirror);
+  mips_linux_watch_populate_regs (current_watches, &watch_mirror);
 
   retval = write_watchpoint_regs ();
 
-- 
1.7.7.6


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

* Re: [PATCH 4/5] Move mips hardware watchpoint stuff to common/
  2013-07-25 21:17         ` Maciej W. Rozycki
@ 2013-07-28  0:47           ` Yao Qi
  0 siblings, 0 replies; 52+ messages in thread
From: Yao Qi @ 2013-07-28  0:47 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/26/2013 05:17 AM, Maciej W. Rozycki wrote:
>   Thanks.  This shows the following changes that you made in the process of
> moving the functions across.  They are fine with me, but I prefer to have
> them included with 3/5 where changes are supposed to be made, so please
> move them there.
> 
> --- gdb/mips-linux-nat.c~	2013-07-25 17:15:17.318692194 +0100
> +++ gdb/common/mips-linux-watch.c	2013-07-25 17:15:32.318690373 +0100
> @@ -627,10 +90,10 @@ mips_linux_watch_get_watchlo (struct pt_
>       }
>   }
>   
> -/* Assuming usable watch registers REGS, set VALUE to watchlo of
> +/* Assuming usable watch registers REGS, set a watchlo VALUE of
>      register N.  */
>   
> [...]
> @@ -668,10 +131,10 @@ mips_linux_watch_get_watchhi (struct pt_
>       }
>   }
>   
> -/* Assuming usable watch registers REGS, set VALUE to watchhi of
> +/* Assuming usable watch registers REGS, set a watchhi VALUE of
>      register N.  */
>   
> [...]
>   fill_mask (CORE_ADDR mask)
>   {
>     CORE_ADDR f = 1;
> +
>     while (f && f < mask)
>       {
>         mask |= f;
> 
>   OK with this change, thanks.

These changes are moved to patch 3/5.  Patch below is what I committed.

-- 
Yao (齐尧)

---
 gdb/ChangeLog                 |   30 +++
 gdb/Makefile.in               |    6 +-
 gdb/common/mips-linux-watch.c |  349 +++++++++++++++++++++++++++++++++++
 gdb/common/mips-linux-watch.h |  126 +++++++++++++
 gdb/config/mips/linux.mh      |    2 +-
 gdb/mips-linux-nat.c          |  408 +----------------------------------------
 6 files changed, 513 insertions(+), 408 deletions(-)
 create mode 100644 gdb/common/mips-linux-watch.c
 create mode 100644 gdb/common/mips-linux-watch.h

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2259dd4..2d953fb 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,35 @@
 2013-07-27  Yao Qi  <yao@codesourcery.com>
 
+	* Makefile.in (HFILES_NO_SRCDIR): Add
+	common/mips-linux-watch.h.
+	(mips-linux-watch.o): New rule.
+	* common/mips-linux-watch.c: New.
+	* common/mips-linux-watch.h: New.
+	* config/mips/linux.mh (NATDEPFILES): Add mips-linux-watch.o
+	* mips-linux-nat.c: Include mips-linux-watch.h.
+	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
+	to common/mips-linux-watch.h.
+	(MAX_DEBUG_REGISTER): Likewise.
+	(enum pt_watch_style): Likewise.
+	(struct mips32_watch_regs): Likewise.
+	(struct mips64_watch_regs): Likewise.
+	(struct pt_watch_regs): Likewise.
+	(struct mips_watchpoint): Likewise.
+	(mips_linux_watch_get_irw_mask): Move to
+	common/mips-linux-watch.c.
+	(get_reg_mask, mips_linux_watch_get_num_valid): Likewise.
+	(mips_linux_watch_get_watchlo): Likewise.
+	(mips_linux_watch_set_watchlo): Likewise.
+	(mips_linux_watch_get_watchhi): Likewise.
+	(mips_linux_watch_set_watchhi): Likewise.
+	(mips_linux_read_watch_registers): Likewise.
+	(mips_linux_watch_type_to_irw): Likewise.
+	(mips_linux_stopped_data_address, fill_mask): Likewise.
+	(mips_linux_watch_try_one_watch): Likewise.
+	(mips_linux_watch_populate_regs): Likewise.
+
+2013-07-27  Yao Qi  <yao@codesourcery.com>
+
 	* mips-linux-nat.c (get_irw_mask): Rename to ...
 	(mips_linux_watch_get_irw_mask): ... this.  Rename parameter
 	'set' to 'n'.  Update function comment.  All callers changed.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 2d574d4..8f4ee9e 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -787,7 +787,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
 HFILES_NO_SRCDIR = \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
-common/i386-xstate.h common/linux-ptrace.h \
+common/i386-xstate.h common/linux-ptrace.h common/mips-linux-watch.h \
 proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
 ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@@ -2026,6 +2026,10 @@ target-common.o: ${srcdir}/common/target-common.c
 	$(COMPILE) $(srcdir)/common/target-common.c
 	$(POSTCOMPILE)
 
+mips-linux-watch.o: ${srcdir}/common/mips-linux-watch.c
+	$(COMPILE) $(srcdir)/common/mips-linux-watch.c
+	$(POSTCOMPILE)
+
 #
 # gdb/tui/ dependencies
 #
diff --git a/gdb/common/mips-linux-watch.c b/gdb/common/mips-linux-watch.c
new file mode 100644
index 0000000..875d6b7
--- /dev/null
+++ b/gdb/common/mips-linux-watch.c
@@ -0,0 +1,349 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#include <sys/ptrace.h>
+#include "mips-linux-watch.h"
+#include "gdb_assert.h"
+
+/* Assuming usable watch registers REGS, return the irw_mask of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the reg_mask of
+   register N.  */
+
+static uint32_t
+get_reg_mask (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watch_masks[n] & ~IRW_MASK;
+    case pt_watch_style_mips64:
+      return regs->mips64.watch_masks[n] & ~IRW_MASK;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the num_valid.  */
+
+uint32_t
+mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.num_valid;
+    case pt_watch_style_mips64:
+      return regs->mips64.num_valid;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchlo of
+   register N.  */
+
+CORE_ADDR
+mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchlo[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchlo[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set watchlo of register N to
+   VALUE.  */
+
+void
+mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+			      CORE_ADDR value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      /*  The cast will never throw away bits as 64 bit addresses can
+	  never be used on a 32 bit kernel.  */
+      regs->mips32.watchlo[n] = (uint32_t) value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchlo[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, return the watchhi of
+   register N.  */
+
+uint32_t
+mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      return regs->mips32.watchhi[n];
+    case pt_watch_style_mips64:
+      return regs->mips64.watchhi[n];
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Assuming usable watch registers REGS, set watchhi of register N to
+   VALUE.  */
+
+void
+mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+			      uint16_t value)
+{
+  switch (regs->style)
+    {
+    case pt_watch_style_mips32:
+      regs->mips32.watchhi[n] = value;
+      break;
+    case pt_watch_style_mips64:
+      regs->mips64.watchhi[n] = value;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Unrecognized watch register style"));
+    }
+}
+
+/* Read the watch registers of process LWPID and store it in
+   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
+   registers are valid.  Return 1 if watch registers are usable.
+   Cached information is used unless FORCE is true.  */
+
+int
+mips_linux_read_watch_registers (long lwpid,
+				 struct pt_watch_regs *watch_readback,
+				 int *watch_readback_valid, int force)
+{
+  if (force || *watch_readback_valid == 0)
+    {
+      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
+	{
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      switch (watch_readback->style)
+	{
+	case pt_watch_style_mips32:
+	  if (watch_readback->mips32.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	case pt_watch_style_mips64:
+	  if (watch_readback->mips64.num_valid == 0)
+	    {
+	      *watch_readback_valid = -1;
+	      return 0;
+	    }
+	  break;
+	default:
+	  *watch_readback_valid = -1;
+	  return 0;
+	}
+      /* Watch registers appear to be usable.  */
+      *watch_readback_valid = 1;
+    }
+  return (*watch_readback_valid == 1) ? 1 : 0;
+}
+
+/* Convert GDB's TYPE to an IRW mask.  */
+
+uint32_t
+mips_linux_watch_type_to_irw (int type)
+{
+  switch (type)
+    {
+    case hw_write:
+      return W_MASK;
+    case hw_read:
+      return R_MASK;
+    case hw_access:
+      return (W_MASK | R_MASK);
+    default:
+      return 0;
+    }
+}
+
+/* Set any low order bits in MASK that are not set.  */
+
+static CORE_ADDR
+fill_mask (CORE_ADDR mask)
+{
+  CORE_ADDR f = 1;
+
+  while (f && f < mask)
+    {
+      mask |= f;
+      f <<= 1;
+    }
+  return mask;
+}
+
+/* Try to add a single watch to the specified registers REGS.  The
+   address of added watch is ADDR, the length is LEN, and the mask
+   is IRW.  Return 1 on success, 0 on failure.  */
+
+int
+mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				CORE_ADDR addr, int len, uint32_t irw)
+{
+  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
+  CORE_ADDR mask_bits, t_low;
+  uint16_t t_hi;
+  int i, free_watches;
+  struct pt_watch_regs regs_copy;
+
+  if (len <= 0)
+    return 0;
+
+  last_byte = addr + len - 1;
+  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
+  base_addr = addr & ~mask_bits;
+
+  /* Check to see if it is covered by current registers.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
+	{
+	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
+	  t_low &= ~(CORE_ADDR) t_hi;
+	  if (addr >= t_low && last_byte <= (t_low + t_hi))
+	    return 1;
+	}
+    }
+  /* Try to find an empty register.  */
+  free_watches = 0;
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      t_low = mips_linux_watch_get_watchlo (regs, i);
+      if (t_low == 0
+	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
+	{
+	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
+	    {
+	      /* It fits, we'll take it.  */
+	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
+	      mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
+	      return 1;
+	    }
+	  else
+	    {
+	      /* It doesn't fit, but has the proper IRW capabilities.  */
+	      free_watches++;
+	    }
+	}
+    }
+  if (free_watches > 1)
+    {
+      /* Try to split it across several registers.  */
+      regs_copy = *regs;
+      for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
+	{
+	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
+	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
+	  if (t_low == 0 && irw == (t_hi & irw))
+	    {
+	      t_low = addr & ~(CORE_ADDR) t_hi;
+	      break_addr = t_low + t_hi + 1;
+	      if (break_addr >= addr + len)
+		segment_len = len;
+	      else
+		segment_len = break_addr - addr;
+	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
+	      mips_linux_watch_set_watchlo (&regs_copy, i,
+					    (addr & ~mask_bits) | irw);
+	      mips_linux_watch_set_watchhi (&regs_copy, i,
+					    mask_bits & ~IRW_MASK);
+	      if (break_addr >= addr + len)
+		{
+		  *regs = regs_copy;
+		  return 1;
+		}
+	      len = addr + len - break_addr;
+	      addr = break_addr;
+	    }
+	}
+    }
+  /* It didn't fit anywhere, we failed.  */
+  return 0;
+}
+
+/* Fill in the watch registers REGS with the currently cached
+   watches CURRENT_WATCHES.  */
+
+void
+mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				struct pt_watch_regs *regs)
+{
+  struct mips_watchpoint *w;
+  int i;
+
+  /* Clear them out.  */
+  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
+    {
+      mips_linux_watch_set_watchlo (regs, i, 0);
+      mips_linux_watch_set_watchhi (regs, i, 0);
+    }
+
+  w = current_watches;
+  while (w)
+    {
+      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
+
+      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
+      /* They must all fit, because we previously calculated that they
+	 would.  */
+      gdb_assert (i);
+      w = w->next;
+    }
+}
diff --git a/gdb/common/mips-linux-watch.h b/gdb/common/mips-linux-watch.h
new file mode 100644
index 0000000..aa89f19
--- /dev/null
+++ b/gdb/common/mips-linux-watch.h
@@ -0,0 +1,126 @@
+/* Copyright (C) 2009-2013 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 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/>.  */
+
+#ifndef MIPS_LINUX_WATCH_H
+#define MIPS_LINUX_WATCH_H 1
+
+#ifdef GDBSERVER
+#include "server.h"
+#else
+#include "defs.h"
+#endif
+
+#include <asm/ptrace.h>
+#include <stdint.h>
+
+#include "break-common.h"
+
+#define MAX_DEBUG_REGISTER 8
+
+/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
+   have hardware watchpoint-related structures.  Define them below.  */
+
+#ifndef PTRACE_GET_WATCH_REGS
+#  define PTRACE_GET_WATCH_REGS	0xd0
+#  define PTRACE_SET_WATCH_REGS	0xd1
+
+enum pt_watch_style {
+  pt_watch_style_mips32,
+  pt_watch_style_mips64
+};
+
+/* A value of zero in a watchlo indicates that it is available.  */
+
+struct mips32_watch_regs
+{
+  uint32_t watchlo[MAX_DEBUG_REGISTER];
+  /* Lower 16 bits of watchhi.  */
+  uint16_t watchhi[MAX_DEBUG_REGISTER];
+  /* Valid mask and I R W bits.
+   * bit 0 -- 1 if W bit is usable.
+   * bit 1 -- 1 if R bit is usable.
+   * bit 2 -- 1 if I bit is usable.
+   * bits 3 - 11 -- Valid watchhi mask bits.
+   */
+  uint16_t watch_masks[MAX_DEBUG_REGISTER];
+  /* The number of valid watch register pairs.  */
+  uint32_t num_valid;
+  /* There is confusion across gcc versions about structure alignment,
+     so we force 8 byte alignment for these structures so they match
+     the kernel even if it was build with a different gcc version.  */
+} __attribute__ ((aligned (8)));
+
+struct mips64_watch_regs
+{
+  uint64_t watchlo[MAX_DEBUG_REGISTER];
+  uint16_t watchhi[MAX_DEBUG_REGISTER];
+  uint16_t watch_masks[MAX_DEBUG_REGISTER];
+  uint32_t num_valid;
+} __attribute__ ((aligned (8)));
+
+struct pt_watch_regs
+{
+  enum pt_watch_style style;
+  union
+  {
+    struct mips32_watch_regs mips32;
+    struct mips64_watch_regs mips64;
+  };
+};
+
+#endif /* !PTRACE_GET_WATCH_REGS */
+
+#define W_BIT 0
+#define R_BIT 1
+#define I_BIT 2
+
+#define W_MASK (1 << W_BIT)
+#define R_MASK (1 << R_BIT)
+#define I_MASK (1 << I_BIT)
+
+#define IRW_MASK (I_MASK | R_MASK | W_MASK)
+
+/* We keep list of all watchpoints we should install and calculate the
+   watch register values each time the list changes.  This allows for
+   easy sharing of watch registers for more than one watchpoint.  */
+
+struct mips_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
+  struct mips_watchpoint *next;
+};
+
+uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n);
+CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n);
+void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
+				   CORE_ADDR value);
+uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n);
+void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
+				   uint16_t value);
+int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
+				    CORE_ADDR addr, int len, uint32_t irw);
+void mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
+				     struct pt_watch_regs *regs);
+uint32_t mips_linux_watch_type_to_irw (int type);
+
+int mips_linux_read_watch_registers (long lwpid,
+				     struct pt_watch_regs *watch_readback,
+				     int *watch_readback_valid, int force);
+#endif
diff --git a/gdb/config/mips/linux.mh b/gdb/config/mips/linux.mh
index 2f8e5dd..a4f23e3 100644
--- a/gdb/config/mips/linux.mh
+++ b/gdb/config/mips/linux.mh
@@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h
 NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
 	linux-thread-db.o proc-service.o \
 	linux-nat.o linux-osdata.o linux-fork.o \
-	linux-procfs.o linux-ptrace.o
+	linux-procfs.o linux-ptrace.o mips-linux-watch.o
 NAT_CDEPS = $(srcdir)/proc-service.list
 
 LOADLIBES = -ldl $(RDYNAMIC)
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index d792cb3..9246741 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -36,6 +36,8 @@
 #include <sys/ptrace.h>
 #include <asm/ptrace.h>
 
+#include "mips-linux-watch.h"
+
 #include "features/mips-linux.c"
 #include "features/mips-dsp-linux.c"
 #include "features/mips64-linux.c"
@@ -461,71 +463,6 @@ mips_linux_read_description (struct target_ops *ops)
     return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
 }
 
-#define MAX_DEBUG_REGISTER 8
-
-/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
-   have hardware watchpoint-related structures.  Define them below.  */
-
-#ifndef PTRACE_GET_WATCH_REGS
-#  define PTRACE_GET_WATCH_REGS	0xd0
-#  define PTRACE_SET_WATCH_REGS	0xd1
-
-enum pt_watch_style {
-  pt_watch_style_mips32,
-  pt_watch_style_mips64
-};
-
-/* A value of zero in a watchlo indicates that it is available.  */
-
-struct mips32_watch_regs
-{
-  uint32_t watchlo[MAX_DEBUG_REGISTER];
-  /* Lower 16 bits of watchhi.  */
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  /* Valid mask and I R W bits.
-   * bit 0 -- 1 if W bit is usable.
-   * bit 1 -- 1 if R bit is usable.
-   * bit 2 -- 1 if I bit is usable.
-   * bits 3 - 11 -- Valid watchhi mask bits.
-   */
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  /* The number of valid watch register pairs.  */
-  uint32_t num_valid;
-  /* There is confusion across gcc versions about structure alignment,
-     so we force 8 byte alignment for these structures so they match
-     the kernel even if it was build with a different gcc version.  */
-} __attribute__ ((aligned (8)));
-
-struct mips64_watch_regs
-{
-  uint64_t watchlo[MAX_DEBUG_REGISTER];
-  uint16_t watchhi[MAX_DEBUG_REGISTER];
-  uint16_t watch_masks[MAX_DEBUG_REGISTER];
-  uint32_t num_valid;
-} __attribute__ ((aligned (8)));
-
-struct pt_watch_regs
-{
-  enum pt_watch_style style;
-  union
-  {
-    struct mips32_watch_regs mips32;
-    struct mips64_watch_regs mips64;
-  };
-};
-
-#endif /* !PTRACE_GET_WATCH_REGS */
-
-#define W_BIT 0
-#define R_BIT 1
-#define I_BIT 2
-
-#define W_MASK (1 << W_BIT)
-#define R_MASK (1 << R_BIT)
-#define I_MASK (1 << I_BIT)
-
-#define IRW_MASK (I_MASK | R_MASK | W_MASK)
-
 /* -1 if the kernel and/or CPU do not support watch registers.
     1 if watch_readback is valid and we can read style, num_valid
       and the masks.
@@ -537,18 +474,6 @@ static int watch_readback_valid;
 
 static struct pt_watch_regs watch_readback;
 
-/* We keep list of all watchpoints we should install and calculate the
-   watch register values each time the list changes.  This allows for
-   easy sharing of watch registers for more than one watchpoint.  */
-
-struct mips_watchpoint
-{
-  CORE_ADDR addr;
-  int len;
-  int type;
-  struct mips_watchpoint *next;
-};
-
 static struct mips_watchpoint *current_watches;
 
 /*  The current set of watch register values for writing the
@@ -556,139 +481,6 @@ static struct mips_watchpoint *current_watches;
 
 static struct pt_watch_regs watch_mirror;
 
-/* Assuming usable watch registers REGS, return the irw_mask of
-   register N.  */
-
-static uint32_t
-mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[n] & IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[n] & IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the reg_mask of
-   register N.  */
-
-static uint32_t
-get_reg_mask (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watch_masks[n] & ~IRW_MASK;
-    case pt_watch_style_mips64:
-      return regs->mips64.watch_masks[n] & ~IRW_MASK;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the num_valid.  */
-
-static uint32_t
-mips_linux_watch_get_num_valid (struct pt_watch_regs *regs)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.num_valid;
-    case pt_watch_style_mips64:
-      return regs->mips64.num_valid;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the watchlo of
-   register N.  */
-
-static CORE_ADDR
-mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchlo[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchlo[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, set watchlo of register N to
-   VALUE.  */
-
-static void
-mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
-			      CORE_ADDR value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      /*  The cast will never throw away bits as 64 bit addresses can
-	  never be used on a 32 bit kernel.  */
-      regs->mips32.watchlo[n] = (uint32_t) value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchlo[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, return the watchhi of
-   register N.  */
-
-static uint32_t
-mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      return regs->mips32.watchhi[n];
-    case pt_watch_style_mips64:
-      return regs->mips64.watchhi[n];
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
-/* Assuming usable watch registers REGS, set watchhi of register N to
-   VALUE.  */
-
-static void
-mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
-			      uint16_t value)
-{
-  switch (regs->style)
-    {
-    case pt_watch_style_mips32:
-      regs->mips32.watchhi[n] = value;
-      break;
-    case pt_watch_style_mips64:
-      regs->mips64.watchhi[n] = value;
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-		      _("Unrecognized watch register style"));
-    }
-}
-
 static void
 mips_show_dr (const char *func, CORE_ADDR addr,
 	      int len, enum target_hw_bp_type type)
@@ -716,67 +508,6 @@ mips_show_dr (const char *func, CORE_ADDR addr,
 							       i)));
 }
 
-/* Read the watch registers of process LWPID and store it in
-   WATCH_READBACK.  Save true to *WATCH_READBACK_VALID if watch
-   registers are valid.  Return 1 if watch registers are usable.
-   Cached information is used unless FORCE is true.  */
-
-static int
-mips_linux_read_watch_registers (long lwpid,
-				 struct pt_watch_regs *watch_readback,
-				 int *watch_readback_valid, int force)
-{
-  if (force || *watch_readback_valid == 0)
-    {
-      if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, watch_readback) == -1)
-	{
-	  *watch_readback_valid = -1;
-	  return 0;
-	}
-      switch (watch_readback->style)
-	{
-	case pt_watch_style_mips32:
-	  if (watch_readback->mips32.num_valid == 0)
-	    {
-	      *watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	case pt_watch_style_mips64:
-	  if (watch_readback->mips64.num_valid == 0)
-	    {
-	      *watch_readback_valid = -1;
-	      return 0;
-	    }
-	  break;
-	default:
-	  *watch_readback_valid = -1;
-	  return 0;
-	}
-      /* Watch registers appear to be usable.  */
-      *watch_readback_valid = 1;
-    }
-  return (*watch_readback_valid == 1) ? 1 : 0;
-}
-
-/* Convert GDB's TYPE to an IRW mask.  */
-
-static uint32_t
-mips_linux_watch_type_to_irw (int type)
-{
-  switch (type)
-    {
-    case hw_write:
-      return W_MASK;
-    case hw_read:
-      return R_MASK;
-    case hw_access:
-      return (W_MASK | R_MASK);
-    default:
-      return 0;
-    }
-}
-
 /* Target to_can_use_hw_breakpoint implementation.  Return 1 if we can
    handle the specified watch type.  */
 
@@ -853,111 +584,6 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
   return 0;
 }
 
-/* Set any low order bits in MASK that are not set.  */
-
-static CORE_ADDR
-fill_mask (CORE_ADDR mask)
-{
-  CORE_ADDR f = 1;
-
-  while (f && f < mask)
-    {
-      mask |= f;
-      f <<= 1;
-    }
-  return mask;
-}
-
-/* Try to add a single watch to the specified registers REGS.  The
-   address of added watch is ADDR, the length is LEN, and the mask
-   is IRW.  Return 1 on success, 0 on failure.  */
-
-static int
-mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
-				CORE_ADDR addr, int len, uint32_t irw)
-{
-  CORE_ADDR base_addr, last_byte, break_addr, segment_len;
-  CORE_ADDR mask_bits, t_low;
-  uint16_t t_hi;
-  int i, free_watches;
-  struct pt_watch_regs regs_copy;
-
-  if (len <= 0)
-    return 0;
-
-  last_byte = addr + len - 1;
-  mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
-  base_addr = addr & ~mask_bits;
-
-  /* Check to see if it is covered by current registers.  */
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      t_low = mips_linux_watch_get_watchlo (regs, i);
-      if (t_low != 0 && irw == ((uint32_t) t_low & irw))
-	{
-	  t_hi = mips_linux_watch_get_watchhi (regs, i) | IRW_MASK;
-	  t_low &= ~(CORE_ADDR) t_hi;
-	  if (addr >= t_low && last_byte <= (t_low + t_hi))
-	    return 1;
-	}
-    }
-  /* Try to find an empty register.  */
-  free_watches = 0;
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      t_low = mips_linux_watch_get_watchlo (regs, i);
-      if (t_low == 0
-	  && irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
-	{
-	  if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
-	    {
-	      /* It fits, we'll take it.  */
-	      mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
-	      mips_linux_watch_set_watchhi (regs, i, mask_bits & ~IRW_MASK);
-	      return 1;
-	    }
-	  else
-	    {
-	      /* It doesn't fit, but has the proper IRW capabilities.  */
-	      free_watches++;
-	    }
-	}
-    }
-  if (free_watches > 1)
-    {
-      /* Try to split it across several registers.  */
-      regs_copy = *regs;
-      for (i = 0; i < mips_linux_watch_get_num_valid (&regs_copy); i++)
-	{
-	  t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
-	  t_hi = get_reg_mask (&regs_copy, i) | IRW_MASK;
-	  if (t_low == 0 && irw == (t_hi & irw))
-	    {
-	      t_low = addr & ~(CORE_ADDR) t_hi;
-	      break_addr = t_low + t_hi + 1;
-	      if (break_addr >= addr + len)
-		segment_len = len;
-	      else
-		segment_len = break_addr - addr;
-	      mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
-	      mips_linux_watch_set_watchlo (&regs_copy, i,
-					    (addr & ~mask_bits) | irw);
-	      mips_linux_watch_set_watchhi (&regs_copy, i,
-					    mask_bits & ~IRW_MASK);
-	      if (break_addr >= addr + len)
-		{
-		  *regs = regs_copy;
-		  return 1;
-		}
-	      len = addr + len - break_addr;
-	      addr = break_addr;
-	    }
-	}
-    }
-  /* It didn't fit anywhere, we failed.  */
-  return 0;
-}
-
 /* Target to_region_ok_for_hw_watchpoint implementation.  Return 1 if
    the specified region can be covered by the watch registers.  */
 
@@ -1014,36 +640,6 @@ mips_linux_new_thread (struct lwp_info *lp)
     perror_with_name (_("Couldn't write debug register"));
 }
 
-/* Fill in the watch registers REGS with the currently cached
-   watches CURRENT_WATCHES.  */
-
-static void
-mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
-				struct pt_watch_regs *regs)
-{
-  struct mips_watchpoint *w;
-  int i;
-
-  /* Clear them out.  */
-  for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
-    {
-      mips_linux_watch_set_watchlo (regs, i, 0);
-      mips_linux_watch_set_watchhi (regs, i, 0);
-    }
-
-  w = current_watches;
-  while (w)
-    {
-      uint32_t irw = mips_linux_watch_type_to_irw (w->type);
-
-      i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
-      /* They must all fit, because we previously calculated that they
-	 would.  */
-      gdb_assert (i);
-      w = w->next;
-    }
-}
-
 /* Target to_insert_watchpoint implementation.  Try to insert a new
    watch.  Return zero on success.  */
 
-- 
1.7.7.6


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

* Re: [PATCH 5/5] MIPS GDBserver watchpoint
  2013-07-25 21:20         ` Maciej W. Rozycki
@ 2013-07-28  0:49           ` Yao Qi
  0 siblings, 0 replies; 52+ messages in thread
From: Yao Qi @ 2013-07-28  0:49 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: gdb-patches

On 07/26/2013 05:19 AM, Maciej W. Rozycki wrote:
>   gdb_assert_not_reached is `__attribute__ ((noreturn))', so there's no
> need for the `return -1' statement.  Please remove it.

OK.  Removed 'return -1'.

> 
>   OK with this change and the ChangeLog updates, thanks for your work.

ChangeLog entry is updated too.  Patch below is what I committed.

-- 
Yao (齐尧)

---
 gdb/ChangeLog                  |    5 +
 gdb/NEWS                       |    3 +
 gdb/gdbserver/ChangeLog        |   21 +++
 gdb/gdbserver/Makefile.in      |    8 +-
 gdb/gdbserver/configure.srv    |    1 +
 gdb/gdbserver/linux-mips-low.c |  365 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 402 insertions(+), 1 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 2d953fb..519e488 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,10 @@
 2013-07-27  Yao Qi  <yao@codesourcery.com>
 
+	* NEWS: Mention that GDBserver now supports hardware
+	watchpoints on the MIPS GNU/Linux target.
+
+2013-07-27  Yao Qi  <yao@codesourcery.com>
+
 	* Makefile.in (HFILES_NO_SRCDIR): Add
 	common/mips-linux-watch.h.
 	(mips-linux-watch.o): New rule.
diff --git a/gdb/NEWS b/gdb/NEWS
index 6ee8ad7..6ee82f7 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -128,6 +128,9 @@ qXfer:libraries-svr4:read's annex
      'qXfer:traceframe-info:read'.  It has the id of the collected
      trace state variables.
 
+  ** GDBserver now supports hardware watchpoints on the MIPS GNU/Linux
+     target.
+
 * New 'z' formatter for printing and examining memory, this displays the
   value as hexadecimal zero padded on the left to the size of the type.
 
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 426e2ba..6a5d1be 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,24 @@
+2013-07-27  Jie Zhang  <jie@codesourcery.com>
+	    Daniel Jacobowitz  <dan@codesourcery.com>
+	    Yao Qi  <yao@codesourcery.com>
+
+	* Makefile.in (SFILES): Add common/mips-linux-watch.c.
+	(mips-linux-watch.o): New rule.
+	(mips_linux_watch_h): New variable.
+	* configure.srv <mips*-*-linux*>: Add mips-linux-watch.o to
+	srv_tgtobj.
+	* linux-mips-low.c: Include mips-linux-watch.h.
+	(struct arch_process_info, struct arch_lwp_info): New.
+	(update_watch_registers_callback): New function.
+	(mips_linux_new_process, mips_linux_new_thread) New functions.
+	(mips_linux_prepare_to_resume, mips_insert_point): New
+	functions.
+	(mips_remove_point, mips_stopped_by_watchpoint): New
+	functions.
+	(rsp_bp_type_to_target_hw_bp_type): New function.
+	(mips_stopped_data_address): New function.
+	(the_low_target): Add watchpoint support functions.
+
 2013-07-27  Yao Qi  <yao@codesourcery.com>
 
 	* i386-low.c: Include break-common.h.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index b28f743..e541497 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -157,7 +157,8 @@ SFILES=	$(srcdir)/gdbreplay.c $(srcdir)/inferiors.c $(srcdir)/dll.c \
 	$(srcdir)/common/common-utils.c $(srcdir)/common/xml-utils.c \
 	$(srcdir)/common/linux-osdata.c $(srcdir)/common/ptid.c \
 	$(srcdir)/common/buffer.c $(srcdir)/common/linux-btrace.c \
-	$(srcdir)/common/filestuff.c $(srcdir)/common/target-common.c
+	$(srcdir)/common/filestuff.c $(srcdir)/common/target-common.c \
+    $(srcdir)/common/mips-linux-watch.c
 
 DEPFILES = @GDBSERVER_DEPFILES@
 
@@ -456,6 +457,8 @@ lynx_low_h = $(srcdir)/lynx-low.h $(srcdir)/server.h
 
 nto_low_h = $(srcdir)/nto-low.h
 
+mips_linux_watch_h = $(srcdir)/../common/mips-linux-watch.h
+
 UST_CFLAGS = $(ustinc) -DCONFIG_UST_GDB_INTEGRATION
 
 # Note, we only build the IPA if -fvisibility=hidden is supported in
@@ -554,6 +557,9 @@ target-common.o: ../common/target-common.c
 linux-btrace.o: ../common/linux-btrace.c $(linux_btrace_h) $(server_h)
 	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
 
+mips-linux-watch.o: ../common/mips-linux-watch.c $(mips_linux_watch_h) $(server_h)
+	$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $<
+
 # We build vasprintf with -DHAVE_CONFIG_H because we want that unit to
 # include our config.h file.  Otherwise, some system headers do not get
 # included, and the compiler emits a warning about implicitly defined
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 879d0de..b9dfd6c 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -184,6 +184,7 @@ case "${target}" in
 			srv_regobj="${srv_regobj} mips64-dsp-linux.o"
 			srv_tgtobj="linux-low.o linux-osdata.o linux-mips-low.o linux-procfs.o"
 			srv_tgtobj="${srv_tgtobj} linux-ptrace.o"
+			srv_tgtobj="${srv_tgtobj} mips-linux-watch.o"
 			srv_xmlfiles="mips-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-dsp-linux.xml"
 			srv_xmlfiles="${srv_xmlfiles} mips-cpu.xml"
diff --git a/gdb/gdbserver/linux-mips-low.c b/gdb/gdbserver/linux-mips-low.c
index 1010528..8ba1096 100644
--- a/gdb/gdbserver/linux-mips-low.c
+++ b/gdb/gdbserver/linux-mips-low.c
@@ -22,6 +22,7 @@
 #include <sys/ptrace.h>
 #include <endian.h>
 
+#include "mips-linux-watch.h"
 #include "gdb_proc_service.h"
 
 /* Defined in auto-generated file mips-linux.c.  */
@@ -159,6 +160,39 @@ get_usrregs_info (void)
   return regs_info->usrregs;
 }
 
+/* Per-process arch-specific data we want to keep.  */
+
+struct arch_process_info
+{
+  /* -1 if the kernel and/or CPU do not support watch registers.
+      1 if watch_readback is valid and we can read style, num_valid
+	and the masks.
+      0 if we need to read the watch_readback.  */
+
+  int watch_readback_valid;
+
+  /* Cached watch register read values.  */
+
+  struct pt_watch_regs watch_readback;
+
+  /* Current watchpoint requests for this process.  */
+
+  struct mips_watchpoint *current_watches;
+
+  /* The current set of watch register values for writing the
+     registers.  */
+
+  struct pt_watch_regs watch_mirror;
+};
+
+/* 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 watch_registers_changed;
+};
+
 /* From mips-linux-nat.c.  */
 
 /* Pseudo registers can not be read.  ptrace does not provide a way to
@@ -257,6 +291,327 @@ mips_breakpoint_at (CORE_ADDR where)
   return 0;
 }
 
+/* Mark the watch registers of lwp, represented by ENTRY, as changed,
+   if the lwp's process id is *PID_P.  */
+
+static int
+update_watch_registers_callback (struct inferior_list_entry *entry,
+				 void *pid_p)
+{
+  struct lwp_info *lwp = (struct lwp_info *) entry;
+  int pid = *(int *) pid_p;
+
+  /* Only update the threads of this process.  */
+  if (pid_of (lwp) == pid)
+    {
+      /* The actual update is done later just before resuming the lwp,
+	 we just mark that the registers need updating.  */
+      lwp->arch_private->watch_registers_changed = 1;
+
+      /* If the lwp isn't stopped, force it to momentarily pause, so
+	 we can update its watch registers.  */
+      if (!lwp->stopped)
+	linux_stop_lwp (lwp);
+    }
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   new_process.  */
+
+static struct arch_process_info *
+mips_linux_new_process (void)
+{
+  struct arch_process_info *info = xcalloc (1, sizeof (*info));
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method new_thread.
+   Mark the watch registers as changed, so the threads' copies will
+   be updated.  */
+
+static struct arch_lwp_info *
+mips_linux_new_thread (void)
+{
+  struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+
+  info->watch_registers_changed = 1;
+
+  return info;
+}
+
+/* This is the implementation of linux_target_ops method
+   prepare_to_resume.  If the watch regs have changed, update the
+   thread's copies.  */
+
+static void
+mips_linux_prepare_to_resume (struct lwp_info *lwp)
+{
+  ptid_t ptid = ptid_of (lwp);
+  struct process_info *proc = find_process_pid (ptid_get_pid (ptid));
+  struct arch_process_info *private = proc->private->arch_private;
+
+  if (lwp->arch_private->watch_registers_changed)
+    {
+      /* Only update the watch registers if we have set or unset a
+	 watchpoint already.  */
+      if (mips_linux_watch_get_num_valid (&private->watch_mirror) > 0)
+	{
+	  /* Write the mirrored watch register values.  */
+	  int tid = ptid_get_lwp (ptid);
+
+	  if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
+			    &private->watch_mirror))
+	    perror_with_name ("Couldn't write watch register");
+	}
+
+      lwp->arch_private->watch_registers_changed = 0;
+    }
+}
+
+/* Translate breakpoint type TYPE in rsp to 'enum target_hw_bp_type'.  */
+
+static enum target_hw_bp_type
+rsp_bp_type_to_target_hw_bp_type (char type)
+{
+  switch (type)
+    {
+    case '2':
+      return hw_write;
+    case '3':
+      return hw_read;
+    case '4':
+      return hw_access;
+    }
+
+  gdb_assert_not_reached ("unhandled RSP breakpoint type");
+}
+
+/* This is the implementation of linux_target_ops method
+   insert_point.  */
+
+static int
+mips_insert_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  struct pt_watch_regs regs;
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+  int pid;
+  long lwpid;
+  enum target_hw_bp_type watch_type;
+  uint32_t irw;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  lwpid = lwpid_of (get_thread_lwp (current_inferior));
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = private->watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (private->current_watches, &regs);
+
+  /* Now try to add the new watch.  */
+  watch_type = rsp_bp_type_to_target_hw_bp_type (type);
+  irw = mips_linux_watch_type_to_irw (watch_type);
+  if (!mips_linux_watch_try_one_watch (&regs, addr, len, irw))
+    return -1;
+
+  /* It fit.  Stick it on the end of the list.  */
+  new_watch = xmalloc (sizeof (struct mips_watchpoint));
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = watch_type;
+  new_watch->next = NULL;
+
+  pw = &private->current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+
+  private->watch_mirror = regs;
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_watch_registers_callback, &pid);
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   remove_point.  */
+
+static int
+mips_remove_point (char type, CORE_ADDR addr, int len)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+
+  int deleted_one;
+  int pid;
+  enum target_hw_bp_type watch_type;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  /* Breakpoint/watchpoint types:
+       '0' - software-breakpoint (not supported)
+       '1' - hardware-breakpoint (not supported)
+       '2' - write watchpoint (supported)
+       '3' - read watchpoint (supported)
+       '4' - access watchpoint (supported).  */
+
+  if (type < '2' || type > '4')
+    {
+      /* Unsupported.  */
+      return 1;
+    }
+
+  /* Search for a known watch that matches.  Then unlink and free it.  */
+  watch_type = rsp_bp_type_to_target_hw_bp_type (type);
+  deleted_one = 0;
+  pw = &private->current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == watch_type)
+	{
+	  *pw = w->next;
+	  free (w);
+	  deleted_one = 1;
+	  break;
+	}
+      pw = &(w->next);
+    }
+
+  if (!deleted_one)
+    return -1;  /* We don't know about it, fail doing nothing.  */
+
+  /* At this point watch_readback is known to be valid because we
+     could not have added the watch without reading it.  */
+  gdb_assert (private->watch_readback_valid == 1);
+
+  private->watch_mirror = private->watch_readback;
+  mips_linux_watch_populate_regs (private->current_watches,
+				  &private->watch_mirror);
+
+  /* Only update the threads of this process.  */
+  pid = pid_of (proc);
+  find_inferior (&all_lwps, update_watch_registers_callback, &pid);
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_by_watchpoint.  The watchhi R and W bits indicate
+   the watch register triggered. */
+
+static int
+mips_stopped_by_watchpoint (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					1))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      return 1;
+
+  return 0;
+}
+
+/* This is the implementation of linux_target_ops method
+   stopped_data_address.  */
+
+static CORE_ADDR
+mips_stopped_data_address (void)
+{
+  struct process_info *proc = current_process ();
+  struct arch_process_info *private = proc->private->arch_private;
+  int n;
+  int num_valid;
+  long lwpid = lwpid_of (get_thread_lwp (current_inferior));
+
+  /* On MIPS we don't know the low order 3 bits of the data address.
+     GDB does not support remote targets that can't report the
+     watchpoint address.  So, make our best guess; return the starting
+     address of a watchpoint request which overlaps the one that
+     triggered.  */
+
+  if (!mips_linux_read_watch_registers (lwpid,
+					&private->watch_readback,
+					&private->watch_readback_valid,
+					0))
+    return 0;
+
+  num_valid = mips_linux_watch_get_num_valid (&private->watch_readback);
+
+  for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
+    if (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+	& (R_MASK | W_MASK))
+      {
+	CORE_ADDR t_low, t_hi;
+	int t_irw;
+	struct mips_watchpoint *watch;
+
+	t_low = mips_linux_watch_get_watchlo (&private->watch_readback, n);
+	t_irw = t_low & IRW_MASK;
+	t_hi = (mips_linux_watch_get_watchhi (&private->watch_readback, n)
+		| IRW_MASK);
+	t_low &= ~(CORE_ADDR)t_hi;
+
+	for (watch = private->current_watches;
+	     watch != NULL;
+	     watch = watch->next)
+	  {
+	    CORE_ADDR addr = watch->addr;
+	    CORE_ADDR last_byte = addr + watch->len - 1;
+
+	    if ((t_irw & mips_linux_watch_type_to_irw (watch->type)) == 0)
+	      {
+		/* Different type.  */
+		continue;
+	      }
+	    /* Check for overlap of even a single byte.  */
+	    if (last_byte >= t_low && addr <= t_low + t_hi)
+	      return addr;
+	  }
+      }
+
+  /* Shouldn't happen.  */
+  return 0;
+}
+
 /* Fetch the thread-local storage pointer for libthread_db.  */
 
 ps_err_e
@@ -506,6 +861,16 @@ struct linux_target_ops the_low_target = {
   mips_reinsert_addr,
   0,
   mips_breakpoint_at,
+  mips_insert_point,
+  mips_remove_point,
+  mips_stopped_by_watchpoint,
+  mips_stopped_data_address,
+  NULL,
+  NULL,
+  NULL, /* siginfo_fixup */
+  mips_linux_new_process,
+  mips_linux_new_thread,
+  mips_linux_prepare_to_resume
 };
 
 void
-- 
1.7.7.6


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

end of thread, other threads:[~2013-07-28  0:49 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-30  2:44 [PATCH 0/3] mips hardware watchpoint support in gdbserver Yao Qi
2013-05-30  2:44 ` [PATCH 1/3] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
2013-06-13 17:49   ` Maciej W. Rozycki
2013-06-14  6:53     ` Yao Qi
2013-06-14 12:53       ` Maciej W. Rozycki
2013-06-20 19:40         ` Pedro Alves
2013-06-20 20:45           ` Maciej W. Rozycki
2013-06-21 14:58             ` Pedro Alves
2013-06-17 16:04     ` Maciej W. Rozycki
2013-05-30  2:44 ` [PATCH 3/3] MIPS h/w watchpoint in GDBserver Yao Qi
2013-06-13  8:20   ` Yao Qi
2013-06-13 13:09     ` Eli Zaretskii
2013-06-13 16:56     ` Pedro Alves
2013-06-19 22:22     ` Maciej W. Rozycki
2013-06-21 15:00       ` Pedro Alves
2013-05-30  2:44 ` [PATCH 2/3] Move mips hardware watchpoint stuff to common/ Yao Qi
2013-06-13  4:12   ` Yao Qi
2013-06-19 22:05     ` Maciej W. Rozycki
2013-06-20 14:21       ` Yao Qi
2013-06-20 15:27         ` Maciej W. Rozycki
2013-06-20 17:50           ` Joel Brobecker
2013-06-21  8:03             ` Maciej W. Rozycki
2013-06-21 15:55               ` Joel Brobecker
2013-05-30 12:29 ` [PATCH 0/3] mips hardware watchpoint support in gdbserver Maciej W. Rozycki
2013-05-30 18:06 ` Pedro Alves
2013-05-30 18:08   ` Pedro Alves
2013-06-29  3:11 ` [PATCH v2 0/5] " Yao Qi
2013-06-29  3:11   ` [PATCH 2/5] Include asm/ptrace.h in mips-linux-nat.c Yao Qi
2013-07-24  0:26     ` Maciej W. Rozycki
2013-07-28  0:43       ` Yao Qi
2013-06-29  3:11   ` [PATCH 3/5] Refactor " Yao Qi
2013-07-24  0:27     ` Maciej W. Rozycki
2013-07-28  0:44       ` Yao Qi
2013-06-29  3:11   ` [PATCH 5/5] MIPS GDBserver watchpoint Yao Qi
2013-06-29 15:20     ` Eli Zaretskii
2013-07-24  0:35     ` Maciej W. Rozycki
2013-07-25  0:17       ` Yao Qi
2013-07-25 21:20         ` Maciej W. Rozycki
2013-07-28  0:49           ` Yao Qi
2013-07-24 18:11     ` Pedro Alves
2013-06-29  3:11   ` [PATCH 1/5] Share 'enum target_hw_bp_type' in GDB and GDBserver Yao Qi
2013-07-24  0:26     ` Maciej W. Rozycki
2013-07-24 14:04       ` Tom Tromey
2013-07-28  0:41         ` Yao Qi
2013-06-29  8:01   ` [PATCH 4/5] Move mips hardware watchpoint stuff to common/ Yao Qi
2013-07-24  0:31     ` Maciej W. Rozycki
2013-07-24  2:08       ` Yao Qi
2013-07-24 18:09         ` Pedro Alves
2013-07-25  0:07       ` Yao Qi
2013-07-25 21:17         ` Maciej W. Rozycki
2013-07-28  0:47           ` Yao Qi
2013-07-22  1:11   ` [PATCH v2 0/5] mips hardware watchpoint support in gdbserver Yao Qi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox