From patchwork Wed Feb 28 01:46:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baldwin X-Patchwork-Id: 26112 Received: (qmail 112962 invoked by alias); 28 Feb 2018 01:48:44 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 112907 invoked by uid 89); 28 Feb 2018 01:48:37 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.8 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_HELO_PASS, SPF_SOFTFAIL autolearn=ham version=3.3.2 spammy=trusting, 2936 X-HELO: mail.baldwin.cx Received: from bigwig.baldwin.cx (HELO mail.baldwin.cx) (96.47.65.170) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 28 Feb 2018 01:48:35 +0000 Received: from ralph.com (ralph.baldwin.cx [66.234.199.215]) by mail.baldwin.cx (Postfix) with ESMTPSA id 7984E10A8BE for ; Tue, 27 Feb 2018 20:48:32 -0500 (EST) From: John Baldwin To: gdb-patches@sourceware.org Subject: [PATCH 1/3] Implement "to_stopped_by_hw_breakpoint" for x86 debug registers. Date: Tue, 27 Feb 2018 17:46:54 -0800 Message-Id: <20180228014656.32372-2-jhb@FreeBSD.org> In-Reply-To: <20180228014656.32372-1-jhb@FreeBSD.org> References: <20180228014656.32372-1-jhb@FreeBSD.org> X-IsSubscribed: yes 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_breakpoint): New function. * nat/x86-dregs.h (x86_dr_stopped_by_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 | 8 ++++++++ gdb/nat/x86-dregs.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ gdb/nat/x86-dregs.h | 4 ++++ gdb/x86-nat.c | 13 +++++++++++++ 4 files changed, 70 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8ab6381add..0b4a308ef5 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2018-02-28 John Baldwin + + * nat/x86-dregs.c (x86_dr_stopped_by_breakpoint): New function. + * nat/x86-dregs.h (x86_dr_stopped_by_breakpoint): New prototype. + * x86-nat.c (x86_stopped_by_hw_breakpoint): New function. + (x86_use_watchpoints): Set "stopped_by_hw_breakpoint" target + method. + 2018-02-28 John Baldwin * fbsd-nat.c (fbsd_resume): Use PT_SETSTEP for stepping and a diff --git a/gdb/nat/x86-dregs.c b/gdb/nat/x86-dregs.c index c816473628..514fde0253 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 breakpoint that triggered. + Otherwise return zero. */ + +int +x86_dr_stopped_by_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 dd6242eda9..84d710c34e 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 breakpoint that triggered. + Otherwise return false. */ +extern int x86_dr_stopped_by_breakpoint (struct x86_debug_reg_state *state); + #endif /* X86_DREGS_H */ diff --git a/gdb/x86-nat.c b/gdb/x86-nat.c index b126c47c94..e32450afdf 100644 --- a/gdb/x86-nat.c +++ b/gdb/x86-nat.c @@ -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_breakpoint (state); +} + static void add_show_debug_regs_command (void) { @@ -293,6 +305,7 @@ x86_use_watchpoints (struct target_ops *t) t->to_region_ok_for_hw_watchpoint = x86_region_ok_for_watchpoint; t->to_stopped_by_watchpoint = x86_stopped_by_watchpoint; t->to_stopped_data_address = x86_stopped_data_address; + t->to_stopped_by_hw_breakpoint = x86_stopped_by_hw_breakpoint; t->to_insert_watchpoint = x86_insert_watchpoint; t->to_remove_watchpoint = x86_remove_watchpoint; t->to_insert_hw_breakpoint = x86_insert_hw_breakpoint;