|  | # Copyright (C) 2016-2022 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/>. | 
|  |  | 
|  | # Regression test for PR gdb/18360.  Test that "interrupt -a" while | 
|  | # some thread is stepping over a breakpoint behaves as expected. | 
|  |  | 
|  | standard_testfile | 
|  |  | 
|  | if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ | 
|  | {debug pthreads}] == -1} { | 
|  | return -1 | 
|  | } | 
|  |  | 
|  | if {![runto_main]} { | 
|  | return -1 | 
|  | } | 
|  |  | 
|  | # Read the number of threads out of the inferior. | 
|  | set NUM_THREADS [get_integer_valueof "num_threads" -1] | 
|  |  | 
|  | # Account for the main thread. | 
|  | incr NUM_THREADS | 
|  |  | 
|  | # Run command and wait for the prompt, without end anchor. | 
|  |  | 
|  | proc gdb_test_no_anchor {cmd} { | 
|  | global gdb_prompt | 
|  |  | 
|  | gdb_test_multiple $cmd $cmd { | 
|  | -re "$gdb_prompt " { | 
|  | pass $cmd | 
|  | } | 
|  | -re "infrun:" { | 
|  | exp_continue | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | # Enable/disable debugging. | 
|  |  | 
|  | proc enable_debug {enable} { | 
|  |  | 
|  | # Comment out to debug problems with the test. | 
|  | return | 
|  |  | 
|  | gdb_test_no_anchor "set debug infrun $enable" | 
|  | gdb_test_no_anchor "set debug displaced $enable" | 
|  | } | 
|  |  | 
|  | # If RESULT is not zero, make the caller return RESULT. | 
|  |  | 
|  | proc return_if_nonzero { result } { | 
|  | if {$result != 0} { | 
|  | return -code return $result | 
|  | } | 
|  | } | 
|  |  | 
|  | # Do one iteration of "c -a& -> interrupt -a".  Return zero on sucess, | 
|  | # and non-zero if some test fails. | 
|  |  | 
|  | proc test_one_iteration {} { | 
|  | global gdb_prompt | 
|  | global NUM_THREADS | 
|  | global decimal | 
|  |  | 
|  | set saw_continuing 0 | 
|  | set test "continue -a &" | 
|  | return_if_nonzero [gdb_test_multiple $test $test { | 
|  | -re "Continuing.\r\n" { | 
|  | set saw_continuing 1 | 
|  | exp_continue | 
|  | } | 
|  | -re "$gdb_prompt " { | 
|  | if ![gdb_assert $saw_continuing $test] { | 
|  | return 1 | 
|  | } | 
|  | } | 
|  | -re "infrun:" { | 
|  | exp_continue | 
|  | } | 
|  | }] | 
|  |  | 
|  | set running_count 0 | 
|  | set test "all threads are running" | 
|  | return_if_nonzero [gdb_test_multiple "info threads" $test { | 
|  | -re "Thread \[^\r\n\]* \\(running\\)" { | 
|  | incr running_count | 
|  | exp_continue | 
|  | } | 
|  | -re "$gdb_prompt " { | 
|  | if ![gdb_assert {$running_count == $NUM_THREADS} $test] { | 
|  | return 1 | 
|  | } | 
|  | } | 
|  | -re "infrun:" { | 
|  | exp_continue | 
|  | } | 
|  | }] | 
|  |  | 
|  | set test "interrupt -a" | 
|  | return_if_nonzero [gdb_test_multiple $test $test { | 
|  | -re "$gdb_prompt " { | 
|  | pass $test | 
|  | } | 
|  | -re "infrun:" { | 
|  | exp_continue | 
|  | } | 
|  | }] | 
|  |  | 
|  | set stopped_count 0 | 
|  | set test "wait for stops" | 
|  | # Don't return on failure here, in order to let "info threads" put | 
|  | # useful info in gdb.log. | 
|  | gdb_test_multiple "" $test { | 
|  | -re "Thread $decimal \[^\r\n\]*stopped" { | 
|  | incr stopped_count | 
|  | if {$stopped_count != $NUM_THREADS} { | 
|  | exp_continue | 
|  | } | 
|  | } | 
|  | -re "$gdb_prompt " { | 
|  | gdb_assert {$stopped_count == $NUM_THREADS} $test | 
|  | } | 
|  | -re "infrun:" { | 
|  | exp_continue | 
|  | } | 
|  | } | 
|  |  | 
|  | # Check if all threads are seen as stopped with "info | 
|  | # threads".  It's a bit redundant with the test above, but | 
|  | # it's useful to have this in the gdb.log if the above ever | 
|  | # happens to fail. | 
|  | set running_count 0 | 
|  | set test "all threads are stopped" | 
|  | return_if_nonzero [gdb_test_multiple "info threads" $test { | 
|  | -re "Thread \[^\r\n\]* \\(running\\)" { | 
|  | incr running_count | 
|  | exp_continue | 
|  | } | 
|  | -re "$gdb_prompt " { | 
|  | if ![gdb_assert {$running_count == 0} $test] { | 
|  | return 1 | 
|  | } | 
|  | } | 
|  | }] | 
|  |  | 
|  | return 0 | 
|  | } | 
|  |  | 
|  | # The test driver proper.  If DISPLACED is "on", turn on displaced | 
|  | # stepping.  If "off", turn it off. | 
|  |  | 
|  | proc testdriver {displaced} { | 
|  | global binfile | 
|  | global GDBFLAGS | 
|  |  | 
|  | save_vars { GDBFLAGS } { | 
|  | append GDBFLAGS " -ex \"set non-stop on\"" | 
|  | clean_restart $binfile | 
|  | } | 
|  |  | 
|  | gdb_test_no_output "set displaced-stepping $displaced" | 
|  |  | 
|  | if ![runto all_started] { | 
|  | return | 
|  | } | 
|  | set break_line [gdb_get_line_number "set breakpoint here"] | 
|  |  | 
|  | gdb_test "break $break_line if always_zero" "Breakpoint .*" "set breakpoint" | 
|  |  | 
|  | enable_debug 1 | 
|  |  | 
|  | for {set iter 0} {$iter < 20} {incr iter} { | 
|  | with_test_prefix "iter=$iter" { | 
|  | # Return early if some test fails, to avoid cascading | 
|  | # timeouts if something goes wrong. | 
|  | if {[test_one_iteration] != 0} { | 
|  | return | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | foreach_with_prefix displaced-stepping {"on" "off"} { | 
|  | if { ${displaced-stepping} != "off" && ![support_displaced_stepping] } { | 
|  | continue | 
|  | } | 
|  |  | 
|  | testdriver ${displaced-stepping} | 
|  | } |