Commit | Line | Data |
---|---|---|
1dadb1dd PA |
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 | ||
18 | load_lib gdbserver-support.exp | |
19 | ||
44f6938e TV |
20 | if { [skip_gdbserver_tests] } { |
21 | return 0 | |
22 | } | |
23 | ||
1dadb1dd PA |
24 | standard_testfile |
25 | ||
26 | # The plain remote target can't do multiple inferiors. | |
27 | if {[target_info gdb_protocol] != ""} { | |
28 | return | |
29 | } | |
30 | ||
31 | if { [prepare_for_testing "failed to prepare" ${binfile} "${srcfile}" \ | |
32 | {debug pthreads}] } { | |
33 | return | |
34 | } | |
35 | ||
f32682ea TV |
36 | # Keep a list of (inferior ID, spawn ID). |
37 | set server_spawn_ids [list] | |
38 | ||
39 | proc connect_target_extended_remote {binfile num} { | |
1dadb1dd | 40 | set res [gdbserver_start "--multi" ""] |
f32682ea TV |
41 | global server_spawn_ids server_spawn_id |
42 | lappend server_spawn_ids $num $server_spawn_id | |
1dadb1dd PA |
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. | |
49 | proc 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"} { | |
f32682ea | 66 | if {[connect_target_extended_remote $binfile $num]} { |
1dadb1dd PA |
67 | return 0 |
68 | } | |
69 | } | |
70 | if ![runto "all_started"] then { | |
71 | return 0 | |
72 | } | |
73 | delete_breakpoints | |
74 | ||
75 | return 1 | |
76 | } | |
77 | ||
78 | proc 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 | ||
93 | proc 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 | ||
f32682ea TV |
107 | # Clean up the server_spawn_ids. |
108 | proc 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 | ||
1dadb1dd PA |
119 | # Return true on success, false otherwise. |
120 | ||
121 | proc setup {non-stop} { | |
122 | global gcorefile gcore_created | |
123 | global binfile | |
124 | ||
f32682ea | 125 | cleanup_gdbservers |
1dadb1dd PA |
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. | |
1dadb1dd PA |
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". | |
175 | proc 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 | ||
250 | proc 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. | |
305 | proc 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 | ||
d9ebdab7 TBA |
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. | |
366 | proc 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 | ||
1fcb3bd3 PA |
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 | ||
446 | proc 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 | ||
1dadb1dd PA |
513 | # Make a core file with two threads upfront. Several tests load the |
514 | # same core file. | |
515 | prepare_core | |
516 | ||
517 | # Some basic "continue" + breakpoints tests. | |
518 | with_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. | |
525 | with_test_prefix "interrupt" { | |
526 | test_ctrlc | |
527 | } | |
528 | ||
529 | # Test ping-ponging between two targets with "next". | |
530 | with_test_prefix "ping-pong" { | |
531 | test_ping_pong_next | |
532 | } | |
d9ebdab7 TBA |
533 | |
534 | # Test "info inferiors" and "info connections" commands. | |
535 | with_test_prefix "info-inferiors" { | |
536 | foreach_with_prefix multi_process {"on" "off"} { | |
537 | test_info_inferiors $multi_process | |
538 | } | |
539 | } | |
f32682ea | 540 | |
1fcb3bd3 PA |
541 | # Test TARGET_WAITKIND_NO_RESUMED handling with multiple targets. |
542 | with_test_prefix "no-resumed" { | |
543 | test_no_resumed | |
544 | } | |
545 | ||
f32682ea | 546 | cleanup_gdbservers |