b9f437de50
Consider the case of the user doing "step" in thread 2, while thread 1 had previously stopped for a breakpoint. In order to make progress, GDB makes thread 1 step over its breakpoint first (with all other threads stopped), and once that is over, thread 2 then starts stepping (with thread 1 and all others running free, by default). If GDB didn't do that, thread 1 would just trip on the same breakpoint immediately again. This is what the prepare_to_proceed / deferred_step_ptid code is all about. However, deferred_step_ptid code resumes the target with: resume (1, GDB_SIGNAL_0); prepare_to_wait (ecs); return; Recall we were just stepping over a breakpoint when we get here. That means that _nothing_ had installed breakpoints yet! If there's another breakpoint just after the breakpoint that was just stepped, we'll miss it. The fix for that would be to use keep_going instead. However, there are more problems. What if the instruction that was just single-stepped triggers a watchpoint? Currently, GDB just happily resumes the thread, losing that too... Missed watchpoints will need yet further fixes, but we should keep those in mind. So the fix must be to let the trap fall through the regular bpstat handling, and only if no breakpoint, watchpoint, etc. claims the trap, shall we switch back to the stepped thread. Now, nowadays, we have code at the tail end of trap handling that does exactly that -- switch back to the stepped thread (switch_back_to_the_stepped_thread). So the deferred_step_ptid code is just standing in the way, and can simply be eliminated, fixing bugs in the process. Sweet. The comment about spurious "Switching to ..." made me pause, but is actually stale nowadays. That isn't needed anymore. previous_inferior_ptid used to be re-set at each (internal) event, but now it's only touched in proceed and normal stop. The two tests added by this patch fail without the fix. Tested on x86_64 Fedora 17 (also against my software single-stepping on x86 branch). gdb/ 2014-03-20 Pedro Alves <palves@redhat.com> * infrun.c (previous_inferior_ptid): Adjust comment. (deferred_step_ptid): Delete. (infrun_thread_ptid_changed, prepare_to_proceed) (init_wait_for_inferior): Adjust. (handle_signal_stop): Delete deferred_step_ptid handling. gdb/testsuite/ 2014-03-20 Pedro Alves <palves@redhat.com> * gdb.threads/step-over-lands-on-breakpoint.c: New file. * gdb.threads/step-over-lands-on-breakpoint.exp: New file.
63 lines
2.2 KiB
Plaintext
63 lines
2.2 KiB
Plaintext
# Copyright (C) 2014 Free Software Foundation, Inc.
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# Test that when a step-over lands on a breakpoint, that breakpoint
|
|
# hit is reported.
|
|
|
|
standard_testfile
|
|
set executable ${testfile}
|
|
|
|
if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
|
|
executable [list debug "incdir=${objdir}"]] != "" } {
|
|
return -1
|
|
}
|
|
|
|
# Cover both stepping and non-stepping execution commands.
|
|
foreach command {"step" "next" "continue" } {
|
|
with_test_prefix $command {
|
|
clean_restart $executable
|
|
|
|
if ![runto_main] {
|
|
continue
|
|
}
|
|
|
|
gdb_breakpoint [gdb_get_line_number "set wait-thread breakpoint here"]
|
|
gdb_continue_to_breakpoint "run to wait-thread breakpoint"
|
|
gdb_test "info threads" "2 .*\\\* 1.*" "info threads shows all threads"
|
|
|
|
gdb_test_no_output "set scheduler-locking on"
|
|
|
|
delete_breakpoints
|
|
|
|
gdb_breakpoint [gdb_get_line_number "set breakpoint child here"]
|
|
gdb_test "thread 2" "Switching to .*"
|
|
gdb_continue_to_breakpoint "run to breakpoint in thread 2"
|
|
gdb_test "p counter = 0" " = 0" "unbreak loop in thread 2"
|
|
|
|
# Set a breakpoint exactly where the step-over will land.
|
|
gdb_breakpoint [gdb_get_line_number "breakpoint after step-over here"]
|
|
|
|
# Switch back to thread 1 and disable scheduler locking.
|
|
gdb_test "thread 1" "Switching to .*"
|
|
gdb_test_no_output "set scheduler-locking off"
|
|
|
|
# Thread 2 is still stopped at a breakpoint that needs to be
|
|
# stepped over before proceeding thread 1. However, right
|
|
# where the step-over lands there's another breakpoint
|
|
# installed, which should trap and be reported to the user.
|
|
gdb_test "$command" "step-over here.*"
|
|
}
|
|
}
|