aboutsummaryrefslogtreecommitdiff
path: root/gdb/nat
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2018-03-03 21:25:33 -0800
committerJohn Baldwin <jhb@FreeBSD.org>2018-03-03 21:25:33 -0800
commit12279366d71627bfbdd74d1a6675dca825d8feca (patch)
treee15692d8fa4694fb384cd0ef3c19d2b1c5a1dcc0 /gdb/nat
parent72f53f22dfc1bb79ae0141a91b8f9786e1964f41 (diff)
downloadbinutils-12279366d71627bfbdd74d1a6675dca825d8feca.zip
binutils-12279366d71627bfbdd74d1a6675dca825d8feca.tar.gz
binutils-12279366d71627bfbdd74d1a6675dca825d8feca.tar.bz2
Implement "to_stopped_by_hw_breakpoint" for x86 debug registers.
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.
Diffstat (limited to 'gdb/nat')
-rw-r--r--gdb/nat/x86-dregs.c45
-rw-r--r--gdb/nat/x86-dregs.h4
2 files changed, 49 insertions, 0 deletions
diff --git a/gdb/nat/x86-dregs.c b/gdb/nat/x86-dregs.c
index c816473..f11a708 100644
--- a/gdb/nat/x86-dregs.c
+++ b/gdb/nat/x86-dregs.c
@@ -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;
+}
diff --git a/gdb/nat/x86-dregs.h b/gdb/nat/x86-dregs.h
index dd6242e..e86e83a 100644
--- a/gdb/nat/x86-dregs.h
+++ b/gdb/nat/x86-dregs.h
@@ -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 */