From patchwork Thu Feb 26 00:17:31 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pedro Alves X-Patchwork-Id: 5298 Received: (qmail 17412 invoked by alias); 26 Feb 2015 00:43:10 -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 17338 invoked by uid 89); 26 Feb 2015 00:43:09 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 26 Feb 2015 00:43:07 +0000 Received: from int-mx13.intmail.prod.int.phx2.redhat.com (int-mx13.intmail.prod.int.phx2.redhat.com [10.5.11.26]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t1Q0Hf0o019555 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Wed, 25 Feb 2015 19:17:41 -0500 Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx13.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t1Q0HXwJ000814 for ; Wed, 25 Feb 2015 19:17:40 -0500 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [PATCH 7/8] gdbserver/Linux: Use TRAP_BRKPT/TRAP_HWBPT Date: Thu, 26 Feb 2015 00:17:31 +0000 Message-Id: <1424909852-25917-8-git-send-email-palves@redhat.com> In-Reply-To: <1424909852-25917-1-git-send-email-palves@redhat.com> References: <1424909852-25917-1-git-send-email-palves@redhat.com> This patch adjusts gdbserver's Linux backend to tell gdbserver core (and ultimately GDB) whether a trap was caused by a breakpoint. It teaches the backend to get that information out of the si_code of the SIGTRAP siginfo. gdb/gdbserver/ChangeLog: 2015-02-25 Pedro Alves * linux-low.c (check_stopped_by_breakpoint) [USE_SIGTRAP_SIGINFO]: Decide whether a breakpoint triggered based on the SIGTRAP's siginfo.si_code. (thread_still_has_status_pending_p) [USE_SIGTRAP_SIGINFO]: Don't check whether a breakpoint is inserted if relying on SIGTRAP's siginfo.si_code. (linux_low_filter_event): Check for breakpoints before checking watchpoints. (linux_wait_1): Don't re-increment the PC if relying on SIGTRAP's siginfo.si_code. (linux_stopped_by_sw_breakpoint) (linux_supports_stopped_by_sw_breakpoint) (linux_stopped_by_hw_breakpoint) (linux_supports_stopped_by_hw_breakpoint): New functions. (linux_target_ops): Install new target methods. --- gdb/gdbserver/linux-low.c | 122 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 6 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index e24739f..81641ac 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -493,6 +493,9 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) CORE_ADDR pc; CORE_ADDR sw_breakpoint_pc; struct thread_info *saved_thread; +#if USE_SIGTRAP_SIGINFO + siginfo_t siginfo; +#endif if (the_low_target.get_pc == NULL) return 0; @@ -504,6 +507,54 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) saved_thread = current_thread; current_thread = get_lwp_thread (lwp); +#if USE_SIGTRAP_SIGINFO + if (ptrace (PTRACE_GETSIGINFO, lwpid_of (current_thread), + (PTRACE_TYPE_ARG3) 0, &siginfo) == 0) + { + if (siginfo.si_signo == SIGTRAP) + { + if (siginfo.si_code == GDB_ARCH_TRAP_BRKPT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: Push back software breakpoint for %s\n", + target_pid_to_str (ptid_of (thr))); + } + + /* Back up the PC if necessary. */ + if (pc != sw_breakpoint_pc) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + (*the_low_target.set_pc) (regcache, sw_breakpoint_pc); + } + + lwp->stop_pc = sw_breakpoint_pc; + lwp->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT; + current_thread = saved_thread; + return 1; + } + else if (siginfo.si_code == TRAP_HWBKPT) + { + if (debug_threads) + { + struct thread_info *thr = get_lwp_thread (lwp); + + debug_printf ("CSBB: Push back hardware " + "breakpoint/watchpoint for %s\n", + target_pid_to_str (ptid_of (thr))); + } + + lwp->stop_pc = pc; + lwp->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT; + current_thread = saved_thread; + return 1; + } + } + } +#else /* We may have just stepped a breakpoint instruction. E.g., in non-stop mode, GDB first tells the thread A to step a range, and then the user inserts a breakpoint inside the range. In that @@ -548,6 +599,7 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) current_thread = saved_thread; return 1; } +#endif current_thread = saved_thread; return 0; @@ -1242,6 +1294,8 @@ thread_still_has_status_pending_p (struct thread_info *thread) lwpid_of (thread)); discard = 1; } + +#if !USE_SIGTRAP_SIGINFO else if (lp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT && !(*the_low_target.breakpoint_at) (pc)) { @@ -1258,6 +1312,7 @@ thread_still_has_status_pending_p (struct thread_info *thread) lwpid_of (thread)); discard = 1; } +#endif current_thread = saved_thread; @@ -1875,15 +1930,24 @@ linux_low_filter_event (int lwpid, int wstat) return NULL; } - if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP - && check_stopped_by_watchpoint (child)) - ; - else if (WIFSTOPPED (wstat) && linux_wstatus_maybe_breakpoint (wstat)) + /* Check first whether this was a SW/HW breakpoint before checking + watchpoints, because at least s390 can't tell the data address of + hardware watchpoint hits, and returns stopped-by-watchpoint as + long as there's a watchpoint set. */ + if (WIFSTOPPED (wstat) && linux_wstatus_maybe_breakpoint (wstat)) { if (check_stopped_by_breakpoint (child)) have_stop_pc = 1; } + /* Note that TRAP_HWBKPT can indicate either a hardware breakpoint + or hardware watchpoint. Check which is which if we got + TARGET_STOPPED_BY_HW_BREAKPOINT. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP + && (child->stop_reason == TARGET_STOPPED_BY_NO_REASON + || child->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT)) + check_stopped_by_watchpoint (child); + if (!have_stop_pc) child->stop_pc = get_pc (child); @@ -2943,8 +3007,10 @@ linux_wait_1 (ptid_t ptid, ourstatus->kind = TARGET_WAITKIND_STOPPED; /* Now that we've selected our final event LWP, un-adjust its PC if - it was a software breakpoint. */ - if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT) + it was a software breakpoint, and the client doesn't know we can + adjust the breakpoint ourselves. */ + if (event_child->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT + && !swbreak_feature) { int decr_pc = the_low_target.decr_pc_after_break; @@ -4906,6 +4972,46 @@ linux_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, return 1; } +/* Implement the to_stopped_by_sw_breakpoint target_ops + method. */ + +static int +linux_stopped_by_sw_breakpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return (lwp->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT); +} + +/* Implement the to_supports_stopped_by_sw_breakpoint target_ops + method. */ + +static int +linux_supports_stopped_by_sw_breakpoint (void) +{ + return USE_SIGTRAP_SIGINFO; +} + +/* Implement the to_stopped_by_hw_breakpoint target_ops + method. */ + +static int +linux_stopped_by_hw_breakpoint (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + return (lwp->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT); +} + +/* Implement the to_supports_stopped_by_hw_breakpoint target_ops + method. */ + +static int +linux_supports_stopped_by_hw_breakpoint (void) +{ + return USE_SIGTRAP_SIGINFO; +} + static int linux_stopped_by_watchpoint (void) { @@ -6092,6 +6198,10 @@ static struct target_ops linux_target_ops = { linux_supports_z_point_type, linux_insert_point, linux_remove_point, + linux_stopped_by_sw_breakpoint, + linux_supports_stopped_by_sw_breakpoint, + linux_stopped_by_hw_breakpoint, + linux_supports_stopped_by_hw_breakpoint, linux_stopped_by_watchpoint, linux_stopped_data_address, #if defined(__UCLIBC__) && defined(HAS_NOMMU) \