aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/gdbserver/ChangeLog8
-rw-r--r--gdb/gdbserver/linux-low.c45
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 <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
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