Implement "to_stopped_by_hw_breakpoint" for x86 debug registers.
authorJohn Baldwin <jhb@FreeBSD.org>
Sun, 4 Mar 2018 05:25:33 +0000 (21:25 -0800)
committerJohn Baldwin <jhb@FreeBSD.org>
Sun, 4 Mar 2018 05:25:33 +0000 (21:25 -0800)
Report that a thread is stopped by a hardware breakpoint if a non-data
watchpoint is set in DR6.  This change should be a no-op since a target
still needs to implement the "to_supports_stopped_by_hw_breakpoint"
method before this function is used.

gdb/ChangeLog:

* nat/x86-dregs.c (x86_dr_stopped_by_hw_breakpoint): New function.
* nat/x86-dregs.h (x86_dr_stopped_by_hw_breakpoint): New
prototype.
* x86-nat.c (x86_stopped_by_hw_breakpoint): New function.
(x86_use_watchpoints): Set "stopped_by_hw_breakpoint" target
method.

gdb/ChangeLog
gdb/nat/x86-dregs.c
gdb/nat/x86-dregs.h
gdb/x86-nat.c

index 074bf08..f548461 100644 (file)
@@ -1,3 +1,12 @@
+2018-03-04  John Baldwin  <jhb@FreeBSD.org>
+
+       * nat/x86-dregs.c (x86_dr_stopped_by_hw_breakpoint): New function.
+       * nat/x86-dregs.h (x86_dr_stopped_by_hw_breakpoint): New
+       prototype.
+       * x86-nat.c (x86_stopped_by_hw_breakpoint): New function.
+       (x86_use_watchpoints): Set "stopped_by_hw_breakpoint" target
+       method.
+
 2018-03-02  Simon Marchi  <simon.marchi@polymtl.ca>
 
        * common/gdb_vecs.c (free_char_ptr_vec): Remove.
index c816473..f11a708 100644 (file)
@@ -649,3 +649,48 @@ x86_dr_stopped_by_watchpoint (struct x86_debug_reg_state *state)
   CORE_ADDR addr = 0;
   return x86_dr_stopped_data_address (state, &addr);
 }
+
+/* Return non-zero if the inferior has some hardware breakpoint that
+   triggered.  Otherwise return zero.  */
+
+int
+x86_dr_stopped_by_hw_breakpoint (struct x86_debug_reg_state *state)
+{
+  CORE_ADDR addr = 0;
+  int i;
+  int rc = 0;
+  /* The current thread's DR_STATUS.  We always need to read this to
+     check whether some watchpoint caused the trap.  */
+  unsigned status;
+  /* We need DR_CONTROL as well, but only iff DR_STATUS indicates a
+     breakpoint trap.  Only fetch it when necessary, to avoid an
+     unnecessary extra syscall when no watchpoint triggered.  */
+  int control_p = 0;
+  unsigned control = 0;
+
+  /* As above, always read the current thread's debug registers rather
+     than trusting dr_mirror.  */
+  status = x86_dr_low_get_status ();
+
+  ALL_DEBUG_ADDRESS_REGISTERS (i)
+    {
+      if (!X86_DR_WATCH_HIT (status, i))
+       continue;
+
+      if (!control_p)
+       {
+         control = x86_dr_low_get_control ();
+         control_p = 1;
+       }
+
+      if (X86_DR_GET_RW_LEN (control, i) == 0)
+       {
+         addr = x86_dr_low_get_addr (i);
+         rc = 1;
+         if (show_debug_regs)
+           x86_show_dr (state, "watchpoint_hit", addr, -1, hw_execute);
+       }
+    }
+
+  return rc;
+}
index dd6242e..e86e83a 100644 (file)
@@ -128,4 +128,8 @@ extern int x86_dr_stopped_data_address (struct x86_debug_reg_state *state,
    Otherwise return false.  */
 extern int x86_dr_stopped_by_watchpoint (struct x86_debug_reg_state *state);
 
+/* Return true if the inferior has some hardware breakpoint that
+   triggered.  Otherwise return false.  */
+extern int x86_dr_stopped_by_hw_breakpoint (struct x86_debug_reg_state *state);
+
 #endif /* X86_DREGS_H */
index b126c47..bec5137 100644 (file)
@@ -260,6 +260,18 @@ x86_can_use_hw_breakpoint (struct target_ops *self,
   return 1;
 }
 
+/* Return non-zero if the inferior has some breakpoint that triggered.
+   Otherwise return zero.  */
+
+static int
+x86_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+  struct x86_debug_reg_state *state
+    = x86_debug_reg_state (ptid_get_pid (inferior_ptid));
+
+  return x86_dr_stopped_by_hw_breakpoint (state);
+}
+
 static void
 add_show_debug_regs_command (void)
 {
@@ -297,6 +309,11 @@ x86_use_watchpoints (struct target_ops *t)
   t->to_remove_watchpoint = x86_remove_watchpoint;
   t->to_insert_hw_breakpoint = x86_insert_hw_breakpoint;
   t->to_remove_hw_breakpoint = x86_remove_hw_breakpoint;
+
+  /* A target must provide an implementation of the
+     "to_supports_stopped_by_hw_breakpoint" target method before this
+     callback will be used.  */
+  t->to_stopped_by_hw_breakpoint = x86_stopped_by_hw_breakpoint;
 }
 
 void