1# Copyright (C) 2016-2020 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License
14# along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16# Regression test for PR gdb/18360.  Test that "interrupt -a" while
17# some thread is stepping over a breakpoint behaves as expected.
18
19standard_testfile
20
21if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
22	 {debug pthreads}] == -1} {
23    return -1
24}
25
26if {![runto_main]} {
27    fail "can't run to main"
28    return -1
29}
30
31# Read the number of threads out of the inferior.
32set NUM_THREADS [get_integer_valueof "num_threads" -1]
33
34# Account for the main thread.
35incr NUM_THREADS
36
37# Run command and wait for the prompt, without end anchor.
38
39proc gdb_test_no_anchor {cmd} {
40    global gdb_prompt
41
42    gdb_test_multiple $cmd $cmd {
43	-re "$gdb_prompt " {
44	    pass $cmd
45	}
46	-re "infrun:" {
47	    exp_continue
48	}
49    }
50}
51
52# Enable/disable debugging.
53
54proc enable_debug {enable} {
55
56    # Comment out to debug problems with the test.
57    return
58
59    gdb_test_no_anchor "set debug infrun $enable"
60    gdb_test_no_anchor "set debug displaced $enable"
61}
62
63# If RESULT is not zero, make the caller return RESULT.
64
65proc return_if_nonzero { result } {
66    if {$result != 0} {
67	return -code return $result
68    }
69}
70
71# Do one iteration of "c -a& -> interrupt -a".  Return zero on sucess,
72# and non-zero if some test fails.
73
74proc test_one_iteration {} {
75    global gdb_prompt
76    global NUM_THREADS
77    global decimal
78
79    set saw_continuing 0
80    set test "continue -a &"
81    return_if_nonzero [gdb_test_multiple $test $test {
82	-re "Continuing.\r\n" {
83	    set saw_continuing 1
84	    exp_continue
85	}
86	-re "$gdb_prompt " {
87	    if ![gdb_assert $saw_continuing $test] {
88		return 1
89	    }
90	}
91	-re "infrun:" {
92	    exp_continue
93	}
94    }]
95
96    set running_count 0
97    set test "all threads are running"
98    return_if_nonzero [gdb_test_multiple "info threads" $test {
99	-re "Thread \[^\r\n\]* \\(running\\)" {
100	    incr running_count
101	    exp_continue
102	}
103	-re "$gdb_prompt " {
104	    if ![gdb_assert {$running_count == $NUM_THREADS} $test] {
105		return 1
106	    }
107	}
108	-re "infrun:" {
109	    exp_continue
110	}
111    }]
112
113    set test "interrupt -a"
114    return_if_nonzero [gdb_test_multiple $test $test {
115	-re "$gdb_prompt " {
116	    pass $test
117	}
118	-re "infrun:" {
119	    exp_continue
120	}
121    }]
122
123    set stopped_count 0
124    set test "wait for stops"
125    # Don't return on failure here, in order to let "info threads" put
126    # useful info in gdb.log.
127    gdb_test_multiple "" $test {
128	-re "Thread $decimal \[^\r\n\]*stopped" {
129	    incr stopped_count
130	    if {$stopped_count != $NUM_THREADS} {
131		exp_continue
132	    }
133	}
134	-re "$gdb_prompt " {
135	    gdb_assert {$stopped_count == $NUM_THREADS} $test
136	}
137	-re "infrun:" {
138	    exp_continue
139	}
140    }
141
142    # Check if all threads are seen as stopped with "info
143    # threads".  It's a bit redundant with the test above, but
144    # it's useful to have this in the gdb.log if the above ever
145    # happens to fail.
146    set running_count 0
147    set test "all threads are stopped"
148    return_if_nonzero [gdb_test_multiple "info threads" $test {
149	-re "Thread \[^\r\n\]* \\(running\\)" {
150	    incr running_count
151	    exp_continue
152	}
153	-re "$gdb_prompt " {
154	    if ![gdb_assert {$running_count == 0} $test] {
155		return 1
156	    }
157	}
158    }]
159
160    return 0
161}
162
163# The test driver proper.  If DISPLACED is "on", turn on displaced
164# stepping.  If "off", turn it off.
165
166proc testdriver {displaced} {
167    global binfile
168    global GDBFLAGS
169
170    save_vars { GDBFLAGS } {
171	append GDBFLAGS " -ex \"set non-stop on\""
172	clean_restart $binfile
173    }
174
175    gdb_test_no_output "set displaced-stepping $displaced"
176
177    if ![runto all_started] {
178	fail "couldn't run to all_started"
179	return
180    }
181    set break_line [gdb_get_line_number "set breakpoint here"]
182
183    gdb_test "break $break_line if always_zero" "Breakpoint .*" "set breakpoint"
184
185    enable_debug 1
186
187    for {set iter 0} {$iter < 20} {incr iter} {
188	with_test_prefix "iter=$iter" {
189	    # Return early if some test fails, to avoid cascading
190	    # timeouts if something goes wrong.
191	    if {[test_one_iteration] != 0} {
192		return
193	    }
194	}
195    }
196}
197
198foreach_with_prefix displaced-stepping {"on" "off"} {
199    if { ${displaced-stepping} != "off" && ![support_displaced_stepping] } {
200	continue
201    }
202
203    testdriver ${displaced-stepping}
204}
205