4c49642963272ca3a79a426256961c49786201ae
[binutils-gdb.git] / gdb / testsuite / gdb.threads / stepi-over-clone.exp
1 # Copyright 2021-2023 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 # Test performing a 'stepi' over a clone syscall instruction.
17
18 # This test relies on us being able to spot syscall instructions in
19 # disassembly output. For now this is only implemented for x86-64.
20 require {istarget x86_64-*-*}
21
22 standard_testfile
23
24 if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
25 {debug pthreads additional_flags=-static}] } {
26 return
27 }
28
29 if {![runto_main]} {
30 return
31 }
32
33 # Arrange to catch the 'clone' syscall, run until we catch the
34 # syscall, and try to figure out the address of the actual syscall
35 # instruction so we can place a breakpoint at this address.
36
37 gdb_test_multiple "catch syscall group:process" "catch process syscalls" {
38 -re "The feature \'catch syscall\' is not supported.*\r\n$gdb_prompt $" {
39 unsupported $gdb_test_name
40 return
41 }
42 -re ".*$gdb_prompt $" {
43 pass $gdb_test_name
44 }
45 }
46
47 gdb_test "continue" \
48 "Catchpoint $decimal \\(call to syscall clone\[23\]\\), .*"
49
50 # Return true if INSN is a syscall instruction.
51
52 proc is_syscall_insn { insn } {
53 if [istarget x86_64-*-* ] {
54 return { $insn == "syscall" }
55 } else {
56 error "port me"
57 }
58 }
59
60 # A list of addresses with syscall instructions.
61 set syscall_addrs {}
62
63 # Get list of addresses with syscall instructions.
64 gdb_test_multiple "disassemble" "" {
65 -re "Dump of assembler code for function \[^\r\n\]+:\r\n" {
66 exp_continue
67 }
68 -re "^(?:=>)?\\s+(${hex})\\s+<\\+${decimal}>:\\s+(\[^\r\n\]+)\r\n" {
69 set addr $expect_out(1,string)
70 set insn [string trim $expect_out(2,string)]
71 if [is_syscall_insn $insn] {
72 verbose -log "Found a syscall at: $addr"
73 lappend syscall_addrs $addr
74 }
75 exp_continue
76 }
77 -re "^End of assembler dump\\.\r\n$gdb_prompt $" {
78 if { [llength $syscall_addrs] == 0 } {
79 unsupported "no syscalls found"
80 return -1
81 }
82 }
83 }
84
85 # The test proc. NON_STOP and DISPLACED are either 'on' or 'off', and are
86 # used to configure how GDB starts up. THIRD_THREAD is either true or false,
87 # and is used to configure the inferior.
88 proc test {non_stop displaced third_thread} {
89 global binfile srcfile
90 global syscall_addrs
91 global GDBFLAGS
92 global gdb_prompt hex decimal
93
94 for { set i 0 } { $i < 3 } { incr i } {
95 with_test_prefix "i=$i" {
96
97 # Arrange to start GDB in the correct mode.
98 save_vars { GDBFLAGS } {
99 append GDBFLAGS " -ex \"set non-stop $non_stop\""
100 append GDBFLAGS " -ex \"set displaced $displaced\""
101 clean_restart $binfile
102 }
103
104 runto_main
105
106 # Setup breakpoints at all the syscall instructions we
107 # might hit. Only issue one pass/fail to make tests more
108 # comparable between systems.
109 set test "break at syscall insns"
110 foreach addr $syscall_addrs {
111 if {[gdb_test -nopass "break *$addr" \
112 ".*" \
113 $test] != 0} {
114 return
115 }
116 }
117 # If we got here, all breakpoints were set successfully.
118 # We used -nopass above, so issue a pass now.
119 pass $test
120
121 # Continue until we hit the syscall.
122 gdb_test "continue"
123
124 if { $third_thread } {
125 gdb_test_no_output "set start_third_thread=1"
126 }
127
128 set stepi_error_count 0
129 set stepi_new_thread_count 0
130 set thread_1_stopped false
131 set thread_2_stopped false
132 set seen_prompt false
133 set hello_first_thread false
134
135 # The program is now stopped at main, but if testing
136 # against GDBserver, inferior_spawn_id is GDBserver's
137 # spawn_id, and the GDBserver output emitted before the
138 # program stopped isn't flushed unless we explicitly do
139 # so, because it is on a different spawn_id. We could try
140 # flushing it now, to avoid confusing the following tests,
141 # but that would have to be done under a timeout, and
142 # would thus slow down the testcase. Instead, if inferior
143 # output goes to a different spawn id, then we don't need
144 # to wait for the first message from the inferior with an
145 # anchor, as we know consuming inferior output won't
146 # consume GDB output. OTOH, if inferior output is coming
147 # out on GDB's terminal, then we must use an anchor,
148 # otherwise matching inferior output without one could
149 # consume GDB output that we are waiting for in regular
150 # expressions that are written after the inferior output
151 # regular expression match.
152 if {$::inferior_spawn_id != $::gdb_spawn_id} {
153 set anchor ""
154 } else {
155 set anchor "^"
156 }
157
158 gdb_test_multiple "stepi" "" {
159 -re "^stepi\r\n" {
160 verbose -log "XXX: Consume the initial command"
161 exp_continue
162 }
163 -re "^\\\[New Thread\[^\r\n\]+\\\]\r\n" {
164 verbose -log "XXX: Consume new thread line"
165 incr stepi_new_thread_count
166 exp_continue
167 }
168 -re "^\\\[Switching to Thread\[^\r\n\]+\\\]\r\n" {
169 verbose -log "XXX: Consume switching to thread line"
170 exp_continue
171 }
172 -re "^\\s*\r\n" {
173 verbose -log "XXX: Consume blank line"
174 exp_continue
175 }
176
177 -i $::inferior_spawn_id
178
179 -re "${anchor}Hello from the first thread\\.\r\n" {
180 set hello_first_thread true
181
182 verbose -log "XXX: Consume first worker thread message"
183 if { $third_thread } {
184 # If we are going to start a third thread then GDB
185 # should hit the breakpoint in clone before printing
186 # this message.
187 incr stepi_error_count
188 }
189 if { !$seen_prompt } {
190 exp_continue
191 }
192 }
193 -re "^Hello from the third thread\\.\r\n" {
194 # We should never see this message.
195 verbose -log "XXX: Consume third worker thread message"
196 incr stepi_error_count
197 if { !$seen_prompt } {
198 exp_continue
199 }
200 }
201
202 -i $::gdb_spawn_id
203
204 -re "^$hex in clone\[23\]? \\(\\)\r\n" {
205 verbose -log "XXX: Consume stop location line"
206 set thread_1_stopped true
207 if { !$seen_prompt } {
208 verbose -log "XXX: Continuing to look for the prompt"
209 exp_continue
210 }
211 }
212 -re "^$gdb_prompt " {
213 verbose -log "XXX: Consume the final prompt"
214 gdb_assert { $stepi_error_count == 0 }
215 gdb_assert { $stepi_new_thread_count == 1 }
216 set seen_prompt true
217 if { $third_thread } {
218 if { $non_stop } {
219 # In non-stop mode if we are trying to start a
220 # third thread (from the second thread), then the
221 # second thread should hit the breakpoint in clone
222 # before actually starting the third thread. And
223 # so, at this point both thread 1, and thread 2
224 # should now be stopped.
225 if { !$thread_1_stopped || !$thread_2_stopped } {
226 verbose -log "XXX: Continue looking for an additional stop event"
227 exp_continue
228 }
229 } else {
230 # All stop mode. Something should have stoppped
231 # by now otherwise we shouldn't have a prompt, but
232 # we can't know which thread will have stopped as
233 # that is a race condition.
234 gdb_assert { $thread_1_stopped || $thread_2_stopped }
235 }
236 }
237
238 if {$non_stop && !$hello_first_thread} {
239 exp_continue
240 }
241
242 }
243 -re "^Thread 2\[^\r\n\]+ hit Breakpoint $decimal, $hex in clone\[23\]? \\(\\)\r\n" {
244 verbose -log "XXX: Consume thread 2 hit breakpoint"
245 set thread_2_stopped true
246 if { !$seen_prompt } {
247 verbose -log "XXX: Continuing to look for the prompt"
248 exp_continue
249 }
250 }
251 -re "^PC register is not available\r\n" {
252 # This is the error we'd see for remote targets.
253 verbose -log "XXX: Consume error line"
254 incr stepi_error_count
255 exp_continue
256 }
257 -re "^Couldn't get registers: No such process\\.\r\n" {
258 # This is the error we see'd for native linux
259 # targets.
260 verbose -log "XXX: Consume error line"
261 incr stepi_error_count
262 exp_continue
263 }
264 }
265
266 # Ensure we are back at a GDB prompt, resynchronise.
267 verbose -log "XXX: Have completed scanning the 'stepi' output"
268 gdb_test "p 1 + 2 + 3" " = 6"
269
270 # Check the number of threads we have, it should be exactly two.
271 set thread_count 0
272 set bad_threads 0
273
274 # Build up our expectations for what the current thread state
275 # should be. Thread 1 is the easiest, this is the thread we are
276 # stepping, so this thread should always be stopped, and should
277 # always still be in clone.
278 set match_code {}
279 lappend match_code {
280 -re "\\*?\\s+1\\s+Thread\[^\r\n\]+clone\[23\]? \\(\\)\r\n" {
281 incr thread_count
282 exp_continue
283 }
284 }
285
286 # What state should thread 2 be in?
287 if { $non_stop == "on" } {
288 if { $third_thread } {
289 # With non-stop mode on, and creation of a third thread
290 # having been requested, we expect Thread 2 to exist, and
291 # be stopped at the breakpoint in clone (just before the
292 # third thread is actually created).
293 lappend match_code {
294 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+$hex in clone\[23\]? \\(\\)\r\n" {
295 incr thread_count
296 exp_continue
297 }
298 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+\\(running\\)\r\n" {
299 incr thread_count
300 incr bad_threads
301 exp_continue
302 }
303 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+\r\n" {
304 verbose -log "XXX: thread 2 is bad, unknown state"
305 incr thread_count
306 incr bad_threads
307 exp_continue
308 }
309 }
310
311 } else {
312 # With non-stop mode on, and no third thread having been
313 # requested, then we expect Thread 2 to exist, and still
314 # be running.
315 lappend match_code {
316 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+\\(running\\)\r\n" {
317 incr thread_count
318 exp_continue
319 }
320 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+\r\n" {
321 verbose -log "XXX: thread 2 is bad, unknown state"
322 incr thread_count
323 incr bad_threads
324 exp_continue
325 }
326 }
327 }
328 } else {
329 # With non-stop mode off then we expect Thread 2 to exist, and
330 # be stopped. We don't have any guarantee about where the
331 # thread will have stopped though, so we need to be vague.
332 lappend match_code {
333 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+\\(running\\)\r\n" {
334 verbose -log "XXX: thread 2 is bad, unexpectedly running"
335 incr thread_count
336 incr bad_threads
337 exp_continue
338 }
339 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+_start\[^\r\n\]+\r\n" {
340 # We know that the thread shouldn't be stopped
341 # at _start, though. This is the location of
342 # the scratch pad on Linux at the time of
343 # writting.
344 verbose -log "XXX: thread 2 is bad, stuck in scratchpad"
345 incr thread_count
346 incr bad_threads
347 exp_continue
348 }
349 -re "\\*?\\s+2\\s+Thread\[^\r\n\]+\r\n" {
350 incr thread_count
351 exp_continue
352 }
353 }
354 }
355
356 # We don't expect to ever see a thread 3. Even when we are
357 # requesting that this third thread be created, thread 2, the
358 # thread that creates thread 3, should stop before executing the
359 # clone syscall. So, if we do ever see this then something has
360 # gone wrong.
361 lappend match_code {
362 -re "\\s+3\\s+Thread\[^\r\n\]+\r\n" {
363 incr thread_count
364 incr bad_threads
365 exp_continue
366 }
367 }
368
369 lappend match_code {
370 -re "$gdb_prompt $" {
371 gdb_assert { $thread_count == 2 }
372 gdb_assert { $bad_threads == 0 }
373 }
374 }
375
376 set match_code [join $match_code]
377 gdb_test_multiple "info threads" "" $match_code
378 }
379 }
380 }
381
382 # Run the test in all suitable configurations.
383 foreach_with_prefix third_thread { false true } {
384 foreach_with_prefix non-stop { "on" "off" } {
385 foreach_with_prefix displaced { "off" "on" } {
386 test ${non-stop} ${displaced} ${third_thread}
387 }
388 }
389 }