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