From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 105323 invoked by alias); 23 Feb 2015 20:27:45 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 105314 invoked by uid 89); 23 Feb 2015 20:27:45 -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,SPF_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; Mon, 23 Feb 2015 20:27:44 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id t1NKRgWE017082 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL) for ; Mon, 23 Feb 2015 15:27:42 -0500 Received: from brno.lan (ovpn01.gateway.prod.ext.ams2.redhat.com [10.39.146.11]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t1NKRfbt004930 for ; Mon, 23 Feb 2015 15:27:42 -0500 From: Pedro Alves To: gdb-patches@sourceware.org Subject: [pushed] gdbserver: redo stepping over breakpoint that was on top of a permanent breakpoint Date: Mon, 23 Feb 2015 20:27:00 -0000 Message-Id: <1424723261-15719-1-git-send-email-palves@redhat.com> X-SW-Source: 2015-02/txt/msg00679.txt.bz2 I'm going to add an alternate mechanism of breakpoint trap identification to 'check_stopped_by_breakpoint' that does not rely on checking the instruction at PC. The mechanism currently used to tell whether we're stepping over a permanent breakpoint doesn't fit in that new method. This patch redoes the whole logic in a different way that works with both old and new methods, in essence moving the "stepped permanent breakpoint" detection "one level up". It makes lower level check_stopped_by_breakpoint always the adjust the PC, and then has linux_wait_1 advance the PC past the breakpoint if necessary. This ends up being better also because this now handles non-decr_pc_after_break targets too. Before, such targets would get stuck forever reexecuting the breakpoint instruction. Tested on x86_64 Fedora 20. gdb/gdbserver/ChangeLog: 2015-02-23 Pedro Alves * linux-low.c (check_stopped_by_breakpoint): Don't check if the thread was doing a step-over; always adjust the PC if we stepped over a permanent breakpoint. (linux_wait_1): If we stepped over breakpoint that was on top of a permanent breakpoint, manually advance the PC past it. --- gdb/gdbserver/ChangeLog | 8 ++++++++ gdb/gdbserver/linux-low.c | 45 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index d724e6c..a130aab 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,5 +1,13 @@ 2015-02-23 Pedro Alves + * linux-low.c (check_stopped_by_breakpoint): Don't check if the + thread was doing a step-over; always adjust the PC if + we stepped over a permanent breakpoint. + (linux_wait_1): If we stepped over breakpoint that was on top of a + permanent breakpoint, manually advance the PC past it. + +2015-02-23 Pedro Alves + * linux-x86-low.c (REGSIZE): Define in both 32-bit and 64-bit modes. (x86_fill_gregset, x86_store_gregset): Use it when handling diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index a6e1e3d..1c66985 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -507,14 +507,8 @@ check_stopped_by_breakpoint (struct lwp_info *lwp) /* 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 - case, we need to report the breakpoint PC. But, when we're - trying to step past one of our own breakpoints, that happens to - have been placed on top of a permanent breakpoint instruction, we - shouldn't adjust the PC, otherwise the program would keep - trapping the permanent breakpoint forever. */ - if ((!lwp->stepping - || (!ptid_equal (ptid_of (current_thread), step_over_bkpt) - && lwp->stop_pc == sw_breakpoint_pc)) + case we need to report the breakpoint PC. */ + if ((!lwp->stepping || lwp->stop_pc == sw_breakpoint_pc) && (*the_low_target.breakpoint_at) (sw_breakpoint_pc)) { if (debug_threads) @@ -2552,6 +2546,41 @@ linux_wait_1 (ptid_t ptid, return ptid_of (current_thread); } + /* If step-over executes a breakpoint instruction, it means a + gdb/gdbserver breakpoint had been planted on top of a permanent + breakpoint. The PC has been adjusted by + check_stopped_by_breakpoint to point at the breakpoint address. + Advance the PC manually past the breakpoint, otherwise the + program would keep trapping the permanent breakpoint forever. */ + if (!ptid_equal (step_over_bkpt, null_ptid) + && event_child->stop_reason == LWP_STOPPED_BY_SW_BREAKPOINT) + { + unsigned int increment_pc; + + if (the_low_target.breakpoint_len > the_low_target.decr_pc_after_break) + increment_pc = the_low_target.breakpoint_len; + else + increment_pc = the_low_target.decr_pc_after_break; + + if (debug_threads) + { + debug_printf ("step-over for %s executed software breakpoint\n", + target_pid_to_str (ptid_of (current_thread))); + } + + if (increment_pc != 0) + { + struct regcache *regcache + = get_thread_regcache (current_thread, 1); + + event_child->stop_pc += increment_pc; + (*the_low_target.set_pc) (regcache, event_child->stop_pc); + + if (!(*the_low_target.breakpoint_at) (event_child->stop_pc)) + event_child->stop_reason = LWP_STOPPED_BY_NO_REASON; + } + } + /* If this event was not handled before, and is not a SIGTRAP, we report it. SIGILL and SIGSEGV are also treated as traps in case a breakpoint is inserted at the current PC. If this target does -- 1.9.3