[PATCH] MIPS: Introduce hardware breakpoint

Heiher r@hev.cc
Wed Jun 17 15:58:58 GMT 2020


gdb/ChangeLog:
2020-06-17  Heiher  <r@hev.cc>
	* mips-linux-nat.c (mips_linux_nat_target::can_use_hw_breakpoint):
	Handle case.
	(mips_linux_nat_target::stopped_by_watchpoint): Update.
	(mips_linux_nat_target::insert_hw_breakpoint): New methods.
	(mips_linux_nat_target::remove_hw_breakpoint): New methods.
	* nat/mips-linux-watch.c (mips_linux_watch_type_to_irw): Handle case.
---
 gdb/ChangeLog              |   8 +++
 gdb/mips-linux-nat.c       | 127 ++++++++++++++++++++++++++++++++++++-
 gdb/nat/mips-linux-watch.c |   2 +
 3 files changed, 136 insertions(+), 1 deletion(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index cb3761c1ba..7e913abcb5 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@
+2020-06-17  Heiher  <r@hev.cc>
+	* mips-linux-nat.c (mips_linux_nat_target::can_use_hw_breakpoint):
+	Handle case.
+	(mips_linux_nat_target::stopped_by_watchpoint): Update.
+	(mips_linux_nat_target::insert_hw_breakpoint): New methods.
+	(mips_linux_nat_target::remove_hw_breakpoint): New methods.
+	* nat/mips-linux-watch.c (mips_linux_watch_type_to_irw): Handle case.
+
 2020-06-16  Tom Tromey  <tom@tromey.com>
 
 	* python/py-tui.c (tui_py_window::~tui_py_window): Handle case
diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
index 38ff461a35..9b0a910861 100644
--- a/gdb/mips-linux-nat.c
+++ b/gdb/mips-linux-nat.c
@@ -52,6 +52,8 @@ class mips_linux_nat_target final : public linux_nat_trad_target
   void close () override;
 
   int can_use_hw_breakpoint (enum bptype, int, int) override;
+  int insert_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override;
+  int remove_hw_breakpoint (struct gdbarch *, struct bp_target_info *) override;
 
   int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
 			 struct expression *) override;
@@ -546,6 +548,9 @@ mips_linux_nat_target::can_use_hw_breakpoint (enum bptype type,
 
    switch (type)
     {
+    case bp_hardware_breakpoint:
+      wanted_mask = I_MASK;
+      break;
     case bp_hardware_watchpoint:
       wanted_mask = W_MASK;
       break;
@@ -588,7 +593,7 @@ mips_linux_nat_target::stopped_by_watchpoint ()
   num_valid = mips_linux_watch_get_num_valid (&watch_readback);
 
   for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
-    if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
+    if (mips_linux_watch_get_watchhi (&watch_readback, n) & IRW_MASK)
       return true;
 
   return false;
@@ -761,6 +766,126 @@ mips_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len,
   return retval;
 }
 
+/* Insert a hardware-assisted breakpoint at BP_TGT->reqstd_address.
+   Return 0 on success, -1 on failure.  */
+
+int
+mips_linux_nat_target::insert_hw_breakpoint (struct gdbarch *gdbarch,
+						struct bp_target_info *bp_tgt)
+{
+  struct pt_watch_regs regs;
+  struct mips_watchpoint *new_watch;
+  struct mips_watchpoint **pw;
+
+  const enum target_hw_bp_type type = hw_execute;
+  CORE_ADDR addr = bp_tgt->placed_address = bp_tgt->reqstd_address;
+  int retval;
+  int len;
+
+  gdbarch_breakpoint_from_pc (gdbarch, &addr, &len);
+
+  if (show_debug_regs)
+    fprintf_unfiltered
+      (gdb_stdlog,
+       "insert_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",
+       (unsigned long) addr, len);
+
+  if (!mips_linux_read_watch_registers (inferior_ptid.lwp (),
+					&watch_readback,
+					&watch_readback_valid, 0))
+    return -1;
+
+  if (len <= 0)
+    return -1;
+
+  regs = watch_readback;
+  /* Add the current watches.  */
+  mips_linux_watch_populate_regs (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 = XNEW (struct mips_watchpoint);
+  new_watch->addr = addr;
+  new_watch->len = len;
+  new_watch->type = type;
+  new_watch->next = NULL;
+
+  pw = &current_watches;
+  while (*pw != NULL)
+    pw = &(*pw)->next;
+  *pw = new_watch;
+
+  watch_mirror = regs;
+  retval = write_watchpoint_regs ();
+
+  if (show_debug_regs)
+    mips_show_dr ("insert_hw_breakpoint", addr, len, type);
+
+  return retval;
+}
+
+/* Remove a hardware-assisted breakpoint at BP_TGT->placed_address.
+   Return 0 on success, -1 on failure.  */
+
+int
+mips_linux_nat_target::remove_hw_breakpoint (struct gdbarch *gdbarch,
+						struct bp_target_info *bp_tgt)
+{
+  int retval;
+  int deleted_one;
+  int len = 4;
+
+  struct mips_watchpoint **pw;
+  struct mips_watchpoint *w;
+
+  const enum target_hw_bp_type type = hw_execute;
+  CORE_ADDR addr = bp_tgt->placed_address;
+
+  gdbarch_breakpoint_from_pc (gdbarch, &addr, &len);
+
+  if (show_debug_regs)
+    fprintf_unfiltered
+      (gdb_stdlog, "remove_hw_breakpoint on entry (addr=0x%08lx, len=%d))\n",
+       (unsigned long) addr, len);
+
+  /* Search for a known watch that matches.  Then unlink and free
+     it.  */
+  deleted_one = 0;
+  pw = &current_watches;
+  while ((w = *pw))
+    {
+      if (w->addr == addr && w->len == len && w->type == type)
+	{
+	  *pw = w->next;
+	  xfree (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 (watch_readback_valid == 1);
+
+  watch_mirror = watch_readback;
+  mips_linux_watch_populate_regs (current_watches, &watch_mirror);
+
+  retval = write_watchpoint_regs ();
+
+  if (show_debug_regs)
+    mips_show_dr ("remove_hw_watchpoint", addr, len, type);
+
+  return retval;
+}
+
 /* Target to_close implementation.  Free any watches and call the
    super implementation.  */
 
diff --git a/gdb/nat/mips-linux-watch.c b/gdb/nat/mips-linux-watch.c
index c975e2218a..74b95a9ac7 100644
--- a/gdb/nat/mips-linux-watch.c
+++ b/gdb/nat/mips-linux-watch.c
@@ -202,6 +202,8 @@ mips_linux_watch_type_to_irw (enum target_hw_bp_type type)
 {
   switch (type)
     {
+    case hw_execute:
+      return I_MASK;
     case hw_write:
       return W_MASK;
     case hw_read:
-- 
2.27.0



More information about the Gdb-patches mailing list