mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-03 04:12:10 +08:00
gdbserver: redo stepping over breakpoint that was on top of a permanent breakpoint
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 <palves@redhat.com> * 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.
This commit is contained in:
parent
d8b901edd1
commit
8090aef2bf
@ -1,3 +1,11 @@
|
||||
2015-02-23 Pedro Alves <palves@redhat.com>
|
||||
|
||||
* 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 <palves@redhat.com>
|
||||
|
||||
* linux-x86-low.c (REGSIZE): Define in both 32-bit and 64-bit
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user