1# Copyright 2017-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# Test multi-target features.
17
18load_lib gdbserver-support.exp
19
20if { [skip_gdbserver_tests] } {
21    return 0
22}
23
24standard_testfile
25
26# The plain remote target can't do multiple inferiors.
27if {[target_info gdb_protocol] != ""} {
28    return
29}
30
31if { [prepare_for_testing "failed to prepare" ${binfile} "${srcfile}" \
32	  {debug pthreads}] } {
33    return
34}
35
36# Keep a list of (inferior ID, spawn ID).
37set server_spawn_ids [list]
38
39proc connect_target_extended_remote {binfile num} {
40    set res [gdbserver_start "--multi" ""]
41    global server_spawn_ids server_spawn_id
42    lappend server_spawn_ids $num $server_spawn_id
43    set gdbserver_gdbport [lindex $res 1]
44    return [gdb_target_cmd "extended-remote" $gdbserver_gdbport]
45}
46
47# Add and start inferior number NUM.  Returns true on success, false
48# otherwise.
49proc add_inferior {num target binfile {gcorefile ""}} {
50    # Start another inferior.
51    gdb_test "add-inferior -no-connection" "Added inferior $num" \
52	"add empty inferior $num"
53    gdb_test "inferior $num" "Switching to inferior $num.*" \
54	"switch to inferior $num"
55    gdb_test "file ${binfile}" ".*" "load file in inferior $num"
56    gdb_test_no_output "set remote exec-file ${binfile}" \
57	"set remote-exec file in inferior $num"
58
59    if {$target == "core"} {
60	gdb_test "core $gcorefile" "Core was generated by.*" \
61	    "core [file tail $gcorefile], inf $num"
62	return 1
63    }
64
65    if {$target == "extended-remote"} {
66	if {[connect_target_extended_remote $binfile $num]} {
67	    return 0
68	}
69    }
70    if ![runto "all_started"] then {
71	return 0
72    }
73    delete_breakpoints
74
75    return 1
76}
77
78proc prepare_core {} {
79    global gcorefile gcore_created
80    global binfile
81
82    clean_restart ${binfile}
83
84    if ![runto all_started] then {
85	return -1
86    }
87
88    global testfile
89    set gcorefile [standard_output_file $testfile.gcore]
90    set gcore_created [gdb_gcore_cmd $gcorefile "save a core file"]
91}
92
93proc next_live_inferior {inf} {
94    incr inf
95    if {$inf == 3} {
96	# 3 is a core.
97	return 4
98    }
99    if {$inf > 5} {
100	# 6 is a core.
101	return 1
102    }
103
104    return $inf
105}
106
107# Clean up the server_spawn_ids.
108proc cleanup_gdbservers { } {
109    global server_spawn_id
110    global server_spawn_ids
111    foreach { inferior_id spawn_id } $server_spawn_ids {
112	set server_spawn_id $spawn_id
113	gdb_test "inferior $inferior_id"
114	gdbserver_exit 0
115    }
116    set server_spawn_ids [list]
117}
118
119# Return true on success, false otherwise.
120
121proc setup {non-stop} {
122    global gcorefile gcore_created
123    global binfile
124
125    cleanup_gdbservers
126    clean_restart ${binfile}
127
128    # multi-target depends on target running in non-stop mode.  Force
129    # it on for remote targets, until this is the default.
130    gdb_test_no_output "maint set target-non-stop on"
131
132    gdb_test_no_output "set non-stop ${non-stop}"
133
134    if ![runto all_started] then {
135	return 0
136    }
137
138    delete_breakpoints
139
140    # inferior 1 -> native
141    # inferior 2 -> extended-remote
142    # inferior 3 -> core
143    # inferior 4 -> native
144    # inferior 5 -> extended-remote
145    # inferior 6 -> core
146    if {![add_inferior 2 "extended-remote" $binfile]} {
147	return 0
148    }
149    if {![add_inferior 3 "core" $binfile $gcorefile]} {
150	return 0
151    }
152    if {![add_inferior 4 "native" $binfile]} {
153	return 0
154    }
155    if {![add_inferior 5 "extended-remote" $binfile]} {
156	return 0
157    }
158    if {![add_inferior 6 "core" $binfile $gcorefile]} {
159	return 0
160    }
161
162    # For debugging.
163    gdb_test "info threads" ".*"
164
165    # Make "continue" resume all inferiors.
166    if {${non-stop} == "off"} {
167	gdb_test_no_output "set schedule-multiple on"
168    }
169
170    return 1
171}
172
173# Test "continue" to breakpoints in different targets.  In non-stop
174# mode, also tests "interrupt -a".
175proc test_continue {non-stop} {
176    if {![setup ${non-stop}]} {
177	untested "setup failed"
178	return
179    }
180
181    proc set_break {inf} {
182	gdb_test "break function${inf} thread ${inf}.1" \
183	"Breakpoint .* function${inf}\\..*"
184    }
185
186    # Select inferior INF, and then run to a breakpoint on inferior
187    # INF+1.
188    proc test_continue_inf {inf} {
189	upvar 1 non-stop non-stop
190
191	global gdb_prompt
192	delete_breakpoints
193
194	set next_inf [next_live_inferior $inf]
195
196	gdb_test "inferior $inf" "Switching to inferior $inf.*"
197	set_break $next_inf
198
199	if {${non-stop} == "off"} {
200	    gdb_test "continue" "hit Breakpoint .* function${next_inf}.*"
201	} else {
202	    set msg "continue"
203	    gdb_test_multiple "continue -a&" $msg {
204		-re "Continuing.*$gdb_prompt " {
205		    pass $msg
206		}
207	    }
208
209	    set msg "hit bp"
210	    gdb_test_multiple "" $msg {
211		-re "hit Breakpoint .* function${next_inf}" {
212		    pass $msg
213		}
214	    }
215
216	    set msg "stop all threads"
217	    gdb_test_multiple "interrupt -a" $msg {
218		-re "$gdb_prompt " {
219		    for {set i 0} {$i < 7} {incr i} {
220			set ok 0
221			gdb_test_multiple "" $msg {
222			    -re "Thread\[^\r\n\]*stopped\\." {
223				set ok 1
224			    }
225			}
226			if {!$ok} {
227			    break
228			}
229		    }
230		    gdb_assert $ok $msg
231		}
232	    }
233	}
234    }
235
236    for {set i 1} {$i <= 5} {incr i} {
237	if {$i == 3} {
238	    # This is a core inferior.
239	    continue
240	}
241
242	with_test_prefix "inf$i" {
243	    test_continue_inf $i
244	}
245    }
246}
247
248# Test interrupting multiple targets with Ctrl-C.
249
250proc test_ctrlc {} {
251    if {![setup "off"]} {
252	untested "setup failed"
253	return
254    }
255
256    delete_breakpoints
257
258    # Select inferior INF, continue all inferiors, and then Ctrl-C.
259    proc test_ctrlc_inf {inf} {
260	global gdb_prompt
261
262	gdb_test "inferior $inf" "Switching to inferior $inf.*"
263
264	set msg "continue"
265	gdb_test_multiple "continue" $msg {
266	    -re "Continuing" {
267		pass $msg
268	    }
269	}
270
271	after 200 { send_gdb "\003" }
272
273	set msg "send_gdb control C"
274	gdb_test_multiple "" $msg {
275	    -re "received signal SIGINT.*$gdb_prompt $" {
276		pass $msg
277	    }
278	}
279
280	set msg "all threads stopped"
281	gdb_test_multiple "info threads" "$msg" {
282	    -re "\\\(running\\\).*$gdb_prompt $" {
283		fail $msg
284	    }
285	    -re "$gdb_prompt $" {
286		pass $msg
287	    }
288	}
289    }
290
291    for {set i 1} {$i <= 5} {incr i} {
292	if {$i == 3} {
293	    # This is a core inferior.
294	    continue
295	}
296
297	with_test_prefix "inf$i" {
298	    test_ctrlc_inf $i
299	}
300    }
301}
302
303# Test "next" bouncing between two breakpoints in two threads running
304# in different targets.
305proc test_ping_pong_next {} {
306    global srcfile
307
308    if {![setup "off"]} {
309	untested "setup failed"
310	return
311    }
312
313    # block/unblock inferiors 1 and 2 according to INF1 and INF2.
314    proc block {inf1 inf2} {
315	gdb_test "thread apply 1.1 p wait_for_gdb = $inf1" " = $inf1"
316	gdb_test "thread apply 2.1 p wait_for_gdb = $inf2" " = $inf2"
317    }
318
319    # We're use inferiors 1 and 2.  Make sure they're really connected
320    # to different targets.
321    gdb_test "thread apply 1.1 maint print target-stack" \
322	"- native.*"
323    gdb_test "thread apply 2.1 maint print target-stack" \
324	"- extended-remote.*"
325
326    # Set two breakpoints, one for each of inferior 1 and 2.  Inferior
327    # 1 is running on the native target, and inferior 2 is running on
328    # extended-gdbserver.  Run to breakpoint 1 to gets things started.
329    set line1 [gdb_get_line_number "set break 1 here"]
330    set line2 [gdb_get_line_number "set break 2 here"]
331
332    gdb_test "thread 1.1" "Switching to thread 1.1 .*"
333
334    gdb_test "break $srcfile:$line1 thread 1.1" \
335	"Breakpoint .*$srcfile:$line1\\..*"
336
337    gdb_test "continue" "hit Breakpoint .*"
338
339    gdb_test "break $srcfile:$line2 thread 2.1" \
340	"Breakpoint .*$srcfile:$line2\\..*"
341
342    # Now block inferior 1 and issue "next".  We should stop at the
343    # breakpoint for inferior 2, given schedlock off.
344    with_test_prefix "next inf 1" {
345	block 1 0
346	gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*"
347    }
348
349    # Now unblock inferior 2 and block inferior 1.  "next" should run
350    # into the breakpoint in inferior 1.
351    with_test_prefix "next inf 2" {
352	block 0 1
353	gdb_test "next" "Thread 1.1 .*hit Breakpoint .*$srcfile:$line1.*"
354    }
355
356    # Try nexting inferior 1 again.
357    with_test_prefix "next inf 1 again" {
358	block 1 0
359	gdb_test "next" "Thread 2.1 .*hit Breakpoint .*$srcfile:$line2.*"
360    }
361}
362
363# Test "info inferiors" and "info connections".  MULTI_PROCESS
364# indicates whether the multi-process feature of remote targets is
365# turned off or on.
366proc test_info_inferiors {multi_process} {
367    setup "off"
368
369    gdb_test_no_output \
370	"set remote multiprocess-feature-packet $multi_process"
371
372    # Get the description for inferior INF for when the current
373    # inferior id is CURRENT.
374    proc inf_desc {inf current} {
375	set ws "\[ \t\]+"
376	global decimal
377	upvar multi_process multi_process
378
379	if {($multi_process == "off") && ($inf == 2 || $inf == 5)} {
380	    set desc "Remote target"
381	} else {
382	    set desc "process ${decimal}"
383	}
384
385	set desc "${inf}${ws}${desc}${ws}"
386	if {$inf == $current} {
387	    return "\\* $desc"
388	} else {
389	    return "  $desc"
390	}
391    }
392
393    # Get the "Num" column for CONNECTION for when the current
394    # inferior id is CURRENT_INF.
395    proc connection_num {connection current_inf} {
396	switch $current_inf {
397	    "4" { set current_connection "1"}
398	    "5" { set current_connection "4"}
399	    "6" { set current_connection "5"}
400	    default { set current_connection $current_inf}
401	}
402	if {$connection == $current_connection} {
403	    return "\\* $connection"
404	} else {
405	    return "  $connection"
406	}
407    }
408
409    set ws "\[ \t\]+"
410    global decimal binfile
411
412    # Test "info connections" and "info inferior" by switching to each
413    # inferior one by one.
414    for {set inf 1} {$inf <= 6} {incr inf} {
415	with_test_prefix "inferior $inf" {
416	    gdb_test "inferior $inf" "Switching to inferior $inf.*"
417
418	    gdb_test "info connections" \
419		[multi_line \
420		     "Num${ws}What${ws}Description${ws}" \
421		     "[connection_num 1 $inf]${ws}native${ws}Native process${ws}" \
422		     "[connection_num 2 $inf]${ws}extended-remote localhost:$decimal${ws}Extended remote serial target in gdb-specific protocol${ws}" \
423		     "[connection_num 3 $inf]${ws}core${ws}Local core dump file${ws}" \
424		     "[connection_num 4 $inf]${ws}extended-remote localhost:$decimal${ws}Extended remote serial target in gdb-specific protocol${ws}" \
425		     "[connection_num 5 $inf]${ws}core${ws}Local core dump file${ws}" \
426		    ]
427
428	    gdb_test "info inferiors" \
429		[multi_line \
430		     "Num${ws}Description${ws}Connection${ws}Executable${ws}" \
431		     "[inf_desc 1 $inf]1 \\(native\\)${ws}${binfile}${ws}" \
432		     "[inf_desc 2 $inf]2 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \
433		     "[inf_desc 3 $inf]3 \\(core\\)${ws}${binfile}${ws}" \
434		     "[inf_desc 4 $inf]1 \\(native\\)${ws}${binfile}${ws}" \
435		     "[inf_desc 5 $inf]4 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \
436		     "[inf_desc 6 $inf]5 \\(core\\)${ws}${binfile}${ws}" \
437		    ]
438	}
439    }
440}
441
442# Test that when there's a foreground execution command in progress, a
443# TARGET_WAITKIND_NO_RESUMED for a particular target is ignored when
444# other targets are still resumed.
445
446proc test_no_resumed {} {
447    proc test_no_resumed_infs {inf_A inf_B} {
448	global gdb_prompt
449
450	if {![setup "off"]} {
451	    untested "setup failed"
452	    return
453	}
454
455	gdb_test "thread $inf_A.2" "Switching to thread $inf_A\.2 .*" \
456	    "select thread of target A"
457
458	gdb_test_no_output "set scheduler-locking on"
459
460	gdb_test_multiple "continue &" "" {
461	    -re "Continuing.*$gdb_prompt " {
462		pass $gdb_test_name
463	    }
464	}
465
466	gdb_test "thread $inf_B.2" "Switching to thread $inf_B\.2 .*" \
467	    "select thread of target B"
468	gdb_test "p exit_thread = 1" " = 1" \
469	    "set the thread to exit on resumption"
470
471	# Wait 3 seconds.  If we see any response from GDB, such as
472	# "No unwaited-for children left." it's a bug.
473	gdb_test_multiple "continue" "continue" {
474	    -timeout 3
475	    timeout {
476		pass $gdb_test_name
477	    }
478	}
479
480	# Now stop the program (all targets).
481	send_gdb "\003"
482	gdb_test_multiple "" "send_gdb control C" {
483	    -re "received signal SIGINT.*$gdb_prompt $" {
484		pass $gdb_test_name
485	    }
486	}
487
488	gdb_test_multiple "info threads" "all threads stopped" {
489	    -re "\\\(running\\\).*$gdb_prompt $" {
490		fail $gdb_test_name
491	    }
492	    -re "$gdb_prompt $" {
493		pass $gdb_test_name
494	    }
495	}
496    }
497
498    # inferior 1 -> native
499    # inferior 2 -> extended-remote 1
500    # inferior 5 -> extended-remote 2
501    set inferiors {1 2 5}
502    foreach_with_prefix inf_A $inferiors {
503	foreach_with_prefix inf_B $inferiors {
504	    if {$inf_A == $inf_B} {
505		continue
506	    }
507	    test_no_resumed_infs $inf_A $inf_B
508	}
509    }
510}
511
512
513# Make a core file with two threads upfront.  Several tests load the
514# same core file.
515prepare_core
516
517# Some basic "continue" + breakpoints tests.
518with_test_prefix "continue" {
519    foreach_with_prefix non-stop {"off" "on"} {
520	test_continue ${non-stop}
521    }
522}
523
524# Some basic all-stop Ctrl-C tests.
525with_test_prefix "interrupt" {
526    test_ctrlc
527}
528
529# Test ping-ponging between two targets with "next".
530with_test_prefix "ping-pong" {
531    test_ping_pong_next
532}
533
534# Test "info inferiors" and "info connections" commands.
535with_test_prefix "info-inferiors" {
536    foreach_with_prefix multi_process {"on" "off"} {
537	test_info_inferiors $multi_process
538    }
539}
540
541# Test TARGET_WAITKIND_NO_RESUMED handling with multiple targets.
542with_test_prefix "no-resumed" {
543    test_no_resumed
544}
545
546cleanup_gdbservers
547