diff options
Diffstat (limited to 'gdb/testsuite/gdb.multi')
36 files changed, 1020 insertions, 54 deletions
diff --git a/gdb/testsuite/gdb.multi/attach-no-multi-process.exp b/gdb/testsuite/gdb.multi/attach-no-multi-process.exp index 28aabaf..2813fa9 100644 --- a/gdb/testsuite/gdb.multi/attach-no-multi-process.exp +++ b/gdb/testsuite/gdb.multi/attach-no-multi-process.exp @@ -44,7 +44,7 @@ proc test {target_non_stop} { "${::GDBFLAGS} -ex \"set remote multiprocess-feature-packet off\"" set ::GDBFLAGS \ "${::GDBFLAGS} -ex \"maint set target-non-stop ${target_non_stop}\"" - clean_restart ${binfile} + clean_restart ${::testfile} } # Start the first inferior. @@ -59,7 +59,10 @@ proc test {target_non_stop} { "switch to inferior 2" set res [gdbserver_start "--multi" ""] set gdbserver_gdbport [lindex $res 1] - gdb_target_cmd "extended-remote" $gdbserver_gdbport + if { [gdb_target_cmd_ext "extended-remote" $gdbserver_gdbport] == 2 } { + unsupported "non-stop RSP" + return + } # Start a program, then attach to it. set spawn_id_list [spawn_wait_for_attach [list $binfile]] diff --git a/gdb/testsuite/gdb.multi/attach-while-running.exp b/gdb/testsuite/gdb.multi/attach-while-running.exp index 5b63030..4eb500e 100644 --- a/gdb/testsuite/gdb.multi/attach-while-running.exp +++ b/gdb/testsuite/gdb.multi/attach-while-running.exp @@ -37,6 +37,7 @@ standard_testfile require can_spawn_for_attach +require allow_multi_inferior_tests if { [build_executable "failed to prepare" ${testfile} ${srcfile}] } { return @@ -45,11 +46,11 @@ if { [build_executable "failed to prepare" ${testfile} ${srcfile}] } { proc do_test {} { save_vars { ::GDBFLAGS } { append ::GDBFLAGS " -ex \"maint set target-non-stop on\"" - clean_restart $::binfile + clean_restart $::testfile } gdb_test -no-prompt-anchor "run &" - gdb_test "add-inferior" "Added inferior 2 on connection 1 .*" + gdb_test -no-prompt-anchor "add-inferior" "Added inferior 2 on connection 1 .*" gdb_test "inferior 2" "Switching to inferior 2 .*" set spawn_id [spawn_wait_for_attach $::binfile] diff --git a/gdb/testsuite/gdb.multi/bp-thread-specific.exp b/gdb/testsuite/gdb.multi/bp-thread-specific.exp index 32b7602..3fe4c20 100644 --- a/gdb/testsuite/gdb.multi/bp-thread-specific.exp +++ b/gdb/testsuite/gdb.multi/bp-thread-specific.exp @@ -19,6 +19,8 @@ # Also check that the correct thread-ids are used in the saved # breakpoints file. +require allow_multi_inferior_tests + # The plain remote target can't do multiple inferiors. require !use_gdb_stub diff --git a/gdb/testsuite/gdb.multi/checkpoint-multi.exp b/gdb/testsuite/gdb.multi/checkpoint-multi.exp index 8439b8d..54fd3ca 100644 --- a/gdb/testsuite/gdb.multi/checkpoint-multi.exp +++ b/gdb/testsuite/gdb.multi/checkpoint-multi.exp @@ -781,7 +781,7 @@ with_test_prefix "background execution" { gdb_test "info checkpoints" \ [multi_line \ "$checkpoints_header_re" \ - "\\* 1\\.0 y +$proc_re +at $::hex,.*" \ + "\\* 1\\.0 y +$proc_re +at $::hex.*" \ " 1\\.1 n +$proc_re +at $::hex, file.*?$hello_c.*?" \ " 2\\.0 y +$proc_re +at $::hex, file.*?$goodbye_c.*?" \ " 2\\.1 n +$proc_re +at $::hex, file.*?$goodbye_c.*?"] @@ -792,7 +792,7 @@ with_test_prefix "background execution" { gdb_test "info checkpoints" \ [multi_line \ "$checkpoints_header_re" \ - " 1\\.0 y +$proc_re +at $::hex,.*" \ + " 1\\.0 y +$proc_re +at $::hex.*" \ " 1\\.1 n +$proc_re +at $::hex, file.*?$hello_c.*?" \ " 2\\.0 n +$proc_re +at $::hex, file.*?$goodbye_c.*?" \ "\\* 2\\.1 y +$proc_re +at $::hex, file.*?$goodbye_c.*?"] diff --git a/gdb/testsuite/gdb.multi/dummy-frame-restore.exp b/gdb/testsuite/gdb.multi/dummy-frame-restore.exp index 1a9d413..4119e3f 100644 --- a/gdb/testsuite/gdb.multi/dummy-frame-restore.exp +++ b/gdb/testsuite/gdb.multi/dummy-frame-restore.exp @@ -19,6 +19,8 @@ set executable ${testfile} # The plain remote target can't do multiple inferiors. require !use_gdb_stub +require allow_multi_inferior_tests + if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug}]} { return -1 } diff --git a/gdb/testsuite/gdb.multi/gdb-settings.exp b/gdb/testsuite/gdb.multi/gdb-settings.exp index b1acca0..97961f5 100644 --- a/gdb/testsuite/gdb.multi/gdb-settings.exp +++ b/gdb/testsuite/gdb.multi/gdb-settings.exp @@ -44,7 +44,7 @@ set run [expr {![use_gdb_stub]}] set inferiors {1 2} # Start all the inferiors. -clean_restart $binfile +clean_restart $::testfile foreach_with_prefix inf $inferiors { if { $inf > 1 } { gdb_test "add-inferior -exec $binfile" "Added inferior 2.*" \ @@ -71,6 +71,7 @@ foreach_with_prefix inf $inferiors { gdb_test_no_output "set args inf${inf}-args" gdb_test_no_output "set cwd /inf${inf}-cwd" gdb_test_no_output "set inferior-tty /inf${inf}-tty" + gdb_test_no_output "set remote exec-file /inf${inf}-remote-exec" } # Check settings are still correct for each inferior. @@ -88,6 +89,9 @@ foreach_with_prefix inf $inferiors { gdb_test "with inferior-tty tmp-value -- print 1" " = 1" gdb_test "show inferior-tty" "/inf${inf}-tty.*" + gdb_test "with remote exec-file tmp-value -- print 1" " = 1" + gdb_test "show remote exec-file" "/inf${inf}-remote-exec.*" + # If the inferiors are running check $_gdb_setting_str and # $_gdb_setting return the correct values. if { $run } { @@ -101,6 +105,11 @@ foreach_with_prefix inf $inferiors { "\"/inf${inf}-tty\"" gdb_test {print $_gdb_setting("inferior-tty")} \ "\"/inf${inf}-tty\"" + + gdb_test {print $_gdb_setting_str("remote exec-file")} \ + "\"/inf${inf}-remote-exec\"" + gdb_test {print $_gdb_setting("remote exec-file")} \ + "\"/inf${inf}-remote-exec\"" } # Check the settings can be read from Python. @@ -109,6 +118,8 @@ foreach_with_prefix inf $inferiors { gdb_test "python print(gdb.parameter('cwd'))" "/inf${inf}-cwd" gdb_test "python print(gdb.parameter('inferior-tty'))" \ "/inf${inf}-tty" + gdb_test "python print(gdb.parameter('remote exec-file'))" \ + "/inf${inf}-remote-exec" } # Check the settings can be read from Guile. @@ -119,5 +130,7 @@ foreach_with_prefix inf $inferiors { "/inf${inf}-cwd" gdb_test "guile (print (parameter-value \"inferior-tty\"))" \ "/inf${inf}-tty" + gdb_test "guile (print (parameter-value \"remote exec-file\"))" \ + "/inf${inf}-remote-exec" } } diff --git a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp index db09095..6d2fc9e 100644 --- a/gdb/testsuite/gdb.multi/inferior-specific-bp.exp +++ b/gdb/testsuite/gdb.multi/inferior-specific-bp.exp @@ -22,8 +22,10 @@ if {[use_gdb_stub]} { } set srcfile1 ${srcfile} -set binfile1 ${binfile}-1 -set binfile2 ${binfile}-2 +set testfile1 $testfile-1 +set testfile2 $testfile-2 +set binfile1 [standard_output_file $testfile1] +set binfile2 [standard_output_file $testfile2] if {[build_executable ${testfile}.exp ${binfile1} "${srcfile1}"] != 0} { return -1 @@ -34,7 +36,7 @@ if {[build_executable ${testfile}.exp ${binfile2} "${srcfile2}"] != 0} { } # Start the first inferior. -clean_restart ${binfile1} +clean_restart $testfile1 if {![runto_main]} { return } diff --git a/gdb/testsuite/gdb.multi/interrupt-bg-exec.c b/gdb/testsuite/gdb.multi/interrupt-bg-exec.c new file mode 100644 index 0000000..b5fa568 --- /dev/null +++ b/gdb/testsuite/gdb.multi/interrupt-bg-exec.c @@ -0,0 +1,47 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +volatile int wait_for_gdb = 1; + +void +breakpt (void) +{ + /* Nothing. */ +} + +void +all_started (void) +{ + /* Nothing. */ +} + +int +main (void) +{ + alarm (360); + + all_started (); + + while (wait_for_gdb) + sleep (1); + + breakpt (); + + return 0; +} diff --git a/gdb/testsuite/gdb.multi/interrupt-bg-exec.exp b/gdb/testsuite/gdb.multi/interrupt-bg-exec.exp new file mode 100644 index 0000000..065a112 --- /dev/null +++ b/gdb/testsuite/gdb.multi/interrupt-bg-exec.exp @@ -0,0 +1,143 @@ +# Copyright 2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# In all-stop mode, set one inferior running in the background, then +# continue a second inferior. When the second inferior hits a breakpoint, +# both inferiors should be stopped. + +# This tests the use of native and remote targets. If we try to run +# it with a board that forces native targets to become remote, then +# this doesn't really make sense (for this test). +require {string equal [target_info gdb_protocol] ""} + +source $srcdir/$subdir/multi-target.exp.tcl + +load_lib gdbserver-support.exp + +require allow_gdbserver_tests + +# This overrides the call in multi-target.exp.tcl. +standard_testfile + +if { [build_executable "failed to build" $testfile $srcfile] } { + return +} + +# Start two inferiors, TARGET_TYPE_1 and TARGET_TYPE_2 are strings, either +# 'extended-remote' or 'native', and control the connection type of each +# inferior. +# +# Set the first inferior running in the background, then continue theA +# second inferior allowing it to hit a breakpoint. +# +# Once the breakpoint is hit, both inferiors should be stopped. +proc run_test { target_type_1 target_type_2 } { + cleanup_gdbservers + + clean_restart + + gdb_test "disconnect" ".*" + + gdb_test_no_output "set sysroot" + + # multi-target depends on target running in non-stop mode. Force it + # on for remote targets, until this is the default. + gdb_test_no_output "maint set target-non-stop on" + + # Run in all-stop mode. + gdb_test_no_output "set non-stop off" + + if {![add_inferior 2 $target_type_1 $::binfile]} { + return 0 + } + + if {![add_inferior 3 $target_type_2 $::binfile]} { + return 0 + } + + # Check we see all the expected threads. + gdb_test "info threads" \ + [multi_line \ + "\\s+Id\\s+Target Id\\s+Frame\\s*" \ + "\\s+2\\.1\\s+\[^\r\n\]+" \ + "\\*\\s+3\\.1\\s+\[^\r\n\]+"] \ + "check expected threads exist" + + # The breakpoint will be set in both inferiors, but only inferior 3 + # will hit it as 'wait_for_gdb' is cleared only in that inferior. + gdb_breakpoint breakpt + gdb_test "thread apply 3.1 set wait_for_gdb = 0" + + # Let inferior 2 run in the background. + gdb_test "thread 2.1" + gdb_test -no-prompt-anchor "continue&" + + # Run inferior 3 until it hits a breakpoint. + gdb_test "thread 3.1" + gdb_test "continue" \ + [multi_line \ + "Thread 3\\.1 \[^\r\n\]+ hit Breakpoint \[^\r\n\]+, breakpt \\(\\) \[^\r\n\]+" \ + "$::decimal\\s+\[^\r\n\]+"] \ + "continue to breakpt function" + + # Check the state of all threads. None should be running. + set saw_inferior_2 false + set saw_inferior_3 false + gdb_test_multiple "info threads" "check threads after stop" { + -re "^info threads\r\n" { + exp_continue + } + + -re "^\\s+Id\\s+Target Id\\s+Frame\\s*\r\n" { + exp_continue + } + + -re "^\\s+2\\.1\\s+\[^\r\n\]+\\s+\\(running\\)\\s*\r\n" { + # Don't count this as seeing inferior 2 as the thread is + # incorrectly still marked as running. By not setting the + # SAW_INFERIOR_2 flag this test will now fail. + exp_continue + } + + -re "^\\s+2\\.1\\s+\[^\r\n\]+\r\n" { + set saw_inferior_2 true + exp_continue + } + + -re "^\\*\\s+3\\.1\\s+\[^\r\n\]+\r\n" { + set saw_inferior_3 true + exp_continue + } + + -re "^$::gdb_prompt $" { + gdb_assert { $saw_inferior_2 && $saw_inferior_3 } \ + $gdb_test_name + } + + -re "^\[^\r\n\]*\r\n" { + exp_continue + } + } +} + +set all_target_types { extended-remote native } + +foreach_with_prefix target_type_1 $all_target_types { + foreach_with_prefix target_type_2 $all_target_types { + run_test $target_type_1 $target_type_2 + } +} + +multi_target_cleanup diff --git a/gdb/testsuite/gdb.multi/multi-arch-exec.exp b/gdb/testsuite/gdb.multi/multi-arch-exec.exp index 69c6b13..435efc5 100644 --- a/gdb/testsuite/gdb.multi/multi-arch-exec.exp +++ b/gdb/testsuite/gdb.multi/multi-arch-exec.exp @@ -23,7 +23,7 @@ require !use_gdb_stub # The 64-bit compile may succeed for i386-linux, but gdb won't be able # to load the file. -if [istarget "i?86-*linux*"] { +if {[istarget "i?86-*linux*"]} { return } @@ -69,9 +69,9 @@ proc append_arch2_options {options_var} { } } - if [istarget "powerpc64*-*-*"] { + if {[istarget "powerpc64*-*-*"]} { set march "-m64" - } elseif [istarget "s390*-*-*"] { + } elseif {[istarget "s390*-*-*"]} { set march "-m31" } else { set march "-m32" diff --git a/gdb/testsuite/gdb.multi/multi-arch.exp b/gdb/testsuite/gdb.multi/multi-arch.exp index d0ae511..02c26ba 100644 --- a/gdb/testsuite/gdb.multi/multi-arch.exp +++ b/gdb/testsuite/gdb.multi/multi-arch.exp @@ -18,12 +18,14 @@ set testfile "multi-arch" +require allow_multi_inferior_tests + # The plain remote target can't do multiple inferiors. require !use_gdb_stub # The 64-bit compile may succeed for i386-linux, but gdb won't be able # to load the file. -if [istarget "i?86-*linux*"] { +if {[istarget "i?86-*linux*"]} { return } @@ -39,7 +41,7 @@ set binfile2 [standard_output_file ${exec2}] # Build two executables, one for each arch. -if [istarget "s390*-*-*"] { +if {[istarget "s390*-*-*"]} { set march1 "-m64" set march2 "-m31" } elseif { [istarget "aarch64*-*-*"] } { @@ -51,11 +53,11 @@ if [istarget "s390*-*-*"] { } if { $march1 != "" } { - require "have_compile_and_link_flag $march1" + require {have_compile_and_link_flag $march1} } if { $march2 != "" } { - require "have_compile_and_link_flag $march2" + require {have_compile_and_link_flag $march2} } if { [build_executable "failed to prepare" ${exec1} "${srcfile1}" \ @@ -65,7 +67,7 @@ if { [build_executable "failed to prepare" ${exec1} "${srcfile1}" \ set options [list debug] -if [istarget "aarch64*-*-*"] { +if {[istarget "aarch64*-*-*"]} { if {[arm_cc_for_target] != ""} { lappend options "compiler=[arm_cc_for_target]" } else { diff --git a/gdb/testsuite/gdb.multi/multi-attach.exp b/gdb/testsuite/gdb.multi/multi-attach.exp index 2d702ee..210c8ca 100644 --- a/gdb/testsuite/gdb.multi/multi-attach.exp +++ b/gdb/testsuite/gdb.multi/multi-attach.exp @@ -17,6 +17,8 @@ # Test attaching to multiple threaded programs. +require allow_multi_inferior_tests + standard_testfile require can_spawn_for_attach diff --git a/gdb/testsuite/gdb.multi/multi-core-files-1.c b/gdb/testsuite/gdb.multi/multi-core-files-1.c new file mode 100644 index 0000000..5d24367 --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-core-files-1.c @@ -0,0 +1,37 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> + +int +bar () +{ + abort (); + return 0; +} + +int +baz () +{ + return bar (); +} + +int +main () +{ + return baz (); +} diff --git a/gdb/testsuite/gdb.multi/multi-core-files-2.c b/gdb/testsuite/gdb.multi/multi-core-files-2.c new file mode 100644 index 0000000..cc05dc6 --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-core-files-2.c @@ -0,0 +1,31 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022-2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> + +int +foo () +{ + abort (); + return 0; +} + +int +main () +{ + return foo (); +} diff --git a/gdb/testsuite/gdb.multi/multi-core-files.exp b/gdb/testsuite/gdb.multi/multi-core-files.exp new file mode 100644 index 0000000..ed83b81 --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-core-files.exp @@ -0,0 +1,171 @@ +# Copyright 2022-2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# This script runs some basic tests that GDB can support multiple +# inferiors each debugging different core files. +# +# We also check the behaviour of GDB if the user attempts to clone or +# duplicate an inferior that is debugging a core file. + +standard_testfile -1.c -2.c + +set testfile1 "${testfile}-1" +set testfile2 "${testfile}-2" + +set binfile1 [standard_output_file $testfile1] +set binfile2 [standard_output_file $testfile2] + +if {[build_executable "build first executable" $binfile1 $srcfile] == -1} { + return +} + +if {[build_executable "build second executable" $binfile2 $srcfile2] == -1} { + return +} + +set corefile1 [core_find $binfile1] +set corefile2 [core_find $binfile2] +if { $corefile1 == "" || $corefile2 == "" } { + untested "Can't generate core files" + return +} + +# Start GDB, and load the first executable and corefile into the first +# inferior. +clean_restart ${testfile1} +gdb_test "core-file $corefile1" "Program terminated with .*" \ + "load core file" +gdb_test "bt" "bar \\(\\) at .*" \ + "check backtrace in inferior 1" + +# The native-extended-remote board connects to the remote target as +# soon as GDB is started, this means that connection 1 is to the +# remote target, and the core target we create below will be +# connection 2. +# +# In all other cases, the core target gets to be connection 1. +if { [target_info gdb_protocol] == "extended-remote"} { + set conn_num 2 +} else { + set conn_num 1 +} + +# Try to use add-inferior and clone-inferior to create new +# inferiors. In both cases this will try to share the core_target +# between inferior 1 and the new inferior. As the core_target can't +# be shared we should get a warning, and the inferior should be +# created without a connection. +gdb_test "add-inferior" \ + [multi_line \ + "\\\[New inferior 2\\\]" \ + "warning: can't share connection ${conn_num} \\(core\\) between inferiors" \ + "Added inferior 2"] +gdb_test "clone-inferior" \ + [multi_line \ + "\\\[New inferior 3\\\]" \ + "warning: can't share connection ${conn_num} \\(core\\) between inferiors" \ + "Added inferior 3"] + +# Check the MI -add-inferior command. Do this using interpreter-exec. +# We're not doing a full MI test here, just checking this one command. +gdb_test "interpreter-exec mi \"-add-inferior\"" \ + [multi_line \ + "~\"\\\[New inferior 4\\\]..\"" \ + "&\"warning: can't share connection ${conn_num} \\(core\\) between inferiors..\"" \ + "~\"Added inferior 4..\"" \ + "\\^done,inferior=\"\[^\"\]+\""] + +# Now check that none of the new inferiors have a connection. +gdb_test "info inferiors" \ + [multi_line \ + "\\*\\s+1\\s+\[^\r\n\]+\\s+${conn_num} \\(core\\)\\s+\[^\r\n\]+.*" \ + "\\s+2\\s+<null>\\s+" \ + "\\s+3\\s+<null>\\s+\[^\r\n\]+" \ + "\\s+4\\s+<null>\\s+"] \ + "first info inferiors call" + +# Now use add-inferior and clone-inferior but this time with the +# -no-connection option, this should avoid issuing the warning. We +# also use interpreter-exec to test the MI version of this command. +gdb_test "add-inferior -no-connection" \ + [multi_line \ + "\\\[New inferior 5\\\]" \ + "Added inferior 5"] +gdb_test "clone-inferior -no-connection" \ + [multi_line \ + "\\\[New inferior 6\\\]" \ + "Added inferior 6"] +gdb_test "interpreter-exec mi \"-add-inferior --no-connection\"" \ + "\\\[New inferior 7\\\].*Added inferior 7.*" + +# Now check that none of the new inferiors have a connection. +gdb_test "info inferiors" \ + [multi_line \ + "\\*\\s+1\\s+\[^\r\n\]+\\s+${conn_num} \\(core\\)\\s+\[^\r\n\]+.*" \ + "\\s+2\\s+<null>\\s+" \ + "\\s+3\\s+<null>\\s+\[^\r\n\]+" \ + "\\s+4\\s+<null>\\s+" \ + "\\s+5\\s+<null>\\s+" \ + "\\s+6\\s+<null>\\s+\[^\r\n\]+" \ + "\\s+7\\s+<null>\\s+"] \ + "second info inferiors call" + +# Check after all the new inferiors have been created that we still +# only have a single connection. +gdb_test "info connections" \ + "\\*\\s+${conn_num}\\s+\\s+core\\s+Local core dump file\\s*" + +# Now switch to inferior 2 and load the second executable and core +# file. Check the backtrace for the presence of function 'foo', this +# indicates we are seeing the correct core file. +gdb_test "inferior 2" "Switching to inferior 2 .*" +gdb_test "file $binfile2" \ + "Reading symbols from .*" \ + "Loaded second test binary" +gdb_test "core-file $corefile2" \ + "Program terminated with signal SIGABRT, Aborted.*" \ + "Loaded second core file" +gdb_test "bt" "foo \\(\\) at .*" \ + "check backtrace in inferior 2" + +# Switch to inferior 3, this one was cloned from inferior 1, so is +# already debugging the first binary file. Check its backtrace for +# 'bar', which indicates we are debugging the correct core file. +gdb_test "inferior 3" "Switching to inferior 3 .*" +gdb_test "core-file $corefile1" \ + "Program terminated with signal SIGABRT, Aborted.*" \ + "Loaded first core file into inferior 3" +gdb_test "bt" "bar \\(\\) at .*" \ + "check backtrace in inferior 3" + +# Detach from some of the core files and delete some of the inferiors. +gdb_test "detach" "No core file now\\." \ + "detach from inferior 3 core file" +gdb_test "inferior 2" "Switching to inferior 2 .*" \ + "switch back to inferior 2" +gdb_test_no_output "remove-inferiors 3 4" + +# Now detach in inferior 2, and delete the inferior. +gdb_test "detach" "No core file now\\." \ + "detach from inferior 2 core file" +gdb_test "inferior 1" "Switching to inferior 1 .*" \ + "switch back to inferior 1" +gdb_test_no_output "remove-inferiors 2" + +# Finally, check that inferior 1 backtrace is still working. +gdb_test "bt" "bar \\(\\) at .*" \ + "check backtrace in inferior 1 again" +gdb_test "detach" "No core file now\\." \ + "detach from inferior 1 core file" diff --git a/gdb/testsuite/gdb.multi/multi-exit.exp b/gdb/testsuite/gdb.multi/multi-exit.exp index 71236c1..fcd7cd2 100644 --- a/gdb/testsuite/gdb.multi/multi-exit.exp +++ b/gdb/testsuite/gdb.multi/multi-exit.exp @@ -24,6 +24,8 @@ standard_testfile +require allow_multi_inferior_tests + require !use_gdb_stub if {[build_executable "failed to prepare" $testfile $srcfile]} { @@ -34,7 +36,7 @@ if {[build_executable "failed to prepare" $testfile $srcfile]} { # Hence, go with the all-stop-on-top-of-non-stop mode. save_vars { GDBFLAGS } { append GDBFLAGS " -ex \"maint set target-non-stop on\"" - clean_restart ${binfile} + clean_restart ${::testfile} } # Start inferior NUM. diff --git a/gdb/testsuite/gdb.multi/multi-kill.exp b/gdb/testsuite/gdb.multi/multi-kill.exp index 48a2534..1473372 100644 --- a/gdb/testsuite/gdb.multi/multi-kill.exp +++ b/gdb/testsuite/gdb.multi/multi-kill.exp @@ -24,6 +24,8 @@ standard_testfile +require allow_multi_inferior_tests + require !use_gdb_stub if {[build_executable "failed to prepare" $testfile $srcfile {debug}]} { @@ -34,7 +36,7 @@ if {[build_executable "failed to prepare" $testfile $srcfile {debug}]} { # Hence, go with the all-stop-on-top-of-non-stop mode. save_vars { GDBFLAGS } { append GDBFLAGS " -ex \"maint set target-non-stop on\"" - clean_restart ${binfile} + clean_restart ${::testfile} } # Wrap the entire test in a namespace to avoid contaminating other tests. diff --git a/gdb/testsuite/gdb.multi/multi-re-run.exp b/gdb/testsuite/gdb.multi/multi-re-run.exp index 002de57..bf83043 100644 --- a/gdb/testsuite/gdb.multi/multi-re-run.exp +++ b/gdb/testsuite/gdb.multi/multi-re-run.exp @@ -20,25 +20,27 @@ # misbehave, including failing to load libthread_db.so. See PR # gdb/25410. +require allow_multi_inferior_tests + # Build two executables, with different symbols. -set exec1 "multi-re-run-1" +set testfile1 "multi-re-run-1" set srcfile1 multi-re-run-1.c -set binfile1 [standard_output_file ${exec1}] +set binfile1 [standard_output_file $testfile1] -set exec2 "multi-re-run-2" +set testfile2 "multi-re-run-2" set srcfile2 multi-re-run-2.c -set binfile2 [standard_output_file ${exec2}] +set binfile2 [standard_output_file $testfile2] with_test_prefix "exec1" { - if { [build_executable "failed to prepare" ${exec1} "${srcfile1}" \ + if { [build_executable "failed to prepare" $testfile1 $srcfile1 \ [list pthreads debug]] } { return -1 } } with_test_prefix "exec2" { - if { [build_executable "failed to prepare" ${exec2} "${srcfile2}" \ + if { [build_executable "failed to prepare" $testfile2 $srcfile2 \ [list pthreads debug]] } { return -1 } @@ -53,7 +55,7 @@ proc test_re_run {re_run_inf} { global gdb_prompt global last_loaded_file - clean_restart ${binfile1} + clean_restart $::testfile1 delete_breakpoints @@ -94,7 +96,7 @@ proc test_re_run {re_run_inf} { foreach_with_prefix iter {1 2} { delete_breakpoints - if ![runto all_started] { + if {![runto all_started]} { return 0 } diff --git a/gdb/testsuite/gdb.multi/multi-remote-target.c b/gdb/testsuite/gdb.multi/multi-remote-target.c new file mode 100644 index 0000000..6702a88 --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-remote-target.c @@ -0,0 +1,71 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <assert.h> + +/* This is a simple, empty function designed to be a stable target + for a GDB breakpoint. Both the parent and child processes will + call this function after the fork. */ + +void +breakpt (void) +{ + /* Nothing. */ +} + +int +main (void) +{ + pid_t child_pid; + + /* Create a new process. */ + child_pid = fork (); + + assert (child_pid >= 0); + + if (child_pid == 0) + { + /* This is the child process. Call the breakpoint function. */ + breakpt (); + + exit (0); + } + else + { + /* This is the parent process. */ + int child_status; + + /* Call the breakpoint function. */ + breakpt (); + + /* Wait for the child process to terminate. */ + waitpid (child_pid, &child_status, 0); + + assert (WIFEXITED (child_status)); + assert (WEXITSTATUS (child_status) == 0); + + exit (0); + } + + /* This line should not be reached. */ + return 1; +} diff --git a/gdb/testsuite/gdb.multi/multi-remote-target.exp b/gdb/testsuite/gdb.multi/multi-remote-target.exp new file mode 100644 index 0000000..bcd5395 --- /dev/null +++ b/gdb/testsuite/gdb.multi/multi-remote-target.exp @@ -0,0 +1,89 @@ +# Copyright 2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Check that an attempt to share a 'remote' (not 'extended-remote') +# will be prevented. But also make sure that the remote connection +# can be shared after the inferior does a 'fork'. + +load_lib gdbserver-support.exp + +require allow_gdbserver_tests + +standard_testfile + +save_vars { GDBFLAGS } { + # If GDB and GDBserver are both running locally, set the sysroot to avoid + # reading files via the remote protocol (the `is_remote target` check is + # already done above). + if { ![is_remote host] && ![is_remote target] } { + set GDBFLAGS "$GDBFLAGS -ex \"set sysroot\"" + } + if {[prepare_for_testing "prepare" $testfile $srcfile] == -1} { + return + } +} + +set target_binfile [gdb_remote_download target $binfile] + +# Make sure we're disconnected, in case we're testing with an +# extended-remote board, therefore already connected. +gdb_test "disconnect" ".*" + +# Start gdbserver and connect. +set res [gdbserver_start "" $target_binfile] +set gdbserver_addr [lindex $res 1] +if { [gdb_target_cmd "remote" $gdbserver_addr] != 0 } { + unsupported "start gdbserver" + return +} + +# The inferior will fork. The following commands force GDB to create +# a new inferior to follow the child process. This ensures that GDB +# is able to share the remote connection between inferiors after a +# fork. +gdb_test_no_output "set follow-fork-mode parent" +gdb_test_no_output "set detach-on-fork off" +gdb_breakpoint breakpt +gdb_continue_to_breakpoint "runto breakpt function" + +# If we are using an extended-remote board, then an extended-remote +# connection will have been setup when GDB initially started. We then +# disconnected, and setup a basic 'remote' connection above. However, +# the 'remote' connection will now be connection 2. +# +# For all other boards, the 'remote' connection will be number 1. +if { [target_info gdb_protocol] == "extended-remote"} { + set conn_num 2 +} else { + set conn_num 1 +} + +# But as this is only a 'remote' (not 'extended-remote') connection, +# then new inferiors cannot be started by the user. This means that +# when the user does 'add-inferior' there is no point sharing the +# remote connection with the new inferior, it can never run anything. +gdb_test "add-inferior" \ + [multi_line \ + "warning: can't share connection $conn_num \\(remote \[^\r\n\]+\\) between inferiors" \ + "Added inferior 3"] \ + "connection is dropped when adding a new inferior" + +# Ensure the new inferior shows no connection. +gdb_test "info inferiors" \ + [multi_line \ + "\\*\\s+1\\s+\[^\r\n\]+\\s+${conn_num} \\(remote \[^\r\n\]+\\)\\s+\[^\r\n\]+" \ + "\\s+2\\s+\[^\r\n\]+\\s+${conn_num} \\(remote \[^\r\n\]+\\)\\s+\[^\r\n\]+" \ + "\\s+3\\s+<null>\\s+"] \ + "third inferior has no connection" diff --git a/gdb/testsuite/gdb.multi/multi-target-info-inferiors.exp b/gdb/testsuite/gdb.multi/multi-target-info-inferiors.exp index e03dc60..b9cd212 100644 --- a/gdb/testsuite/gdb.multi/multi-target-info-inferiors.exp +++ b/gdb/testsuite/gdb.multi/multi-target-info-inferiors.exp @@ -75,7 +75,7 @@ proc test_info_inferiors {multi_process} { } set ws "\[ \t\]+" - global decimal binfile + global decimal binfile gcorefile # Test "info connections" and "info inferior" by switching to each # inferior one by one. @@ -105,15 +105,19 @@ proc test_info_inferiors {multi_process} { ] } + set gcorefile_re [string_to_regexp $gcorefile] + gdb_test "info inferiors" \ [multi_line \ "Num${ws}Description${ws}Connection${ws}Executable${ws}" \ "[inf_desc 1 $inf]1 \\(native\\)${ws}${binfile}${ws}" \ "[inf_desc 2 $inf]2 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \ "[inf_desc 3 $inf]3 \\(core\\)${ws}${binfile}${ws}" \ + "${ws}core file ${gcorefile_re}" \ "[inf_desc 4 $inf]1 \\(native\\)${ws}${binfile}${ws}" \ "[inf_desc 5 $inf]4 \\(extended-remote localhost:$decimal\\)${ws}${binfile}${ws}" \ "[inf_desc 6 $inf]5 \\(core\\)${ws}${binfile}${ws}" \ + "${ws}core file ${gcorefile_re}" ] if { $::run_python_tests } { diff --git a/gdb/testsuite/gdb.multi/multi-target.exp.tcl b/gdb/testsuite/gdb.multi/multi-target.exp.tcl index 8c24602..1963db5 100644 --- a/gdb/testsuite/gdb.multi/multi-target.exp.tcl +++ b/gdb/testsuite/gdb.multi/multi-target.exp.tcl @@ -53,7 +53,7 @@ proc add_inferior {num target binfile {gcorefile ""}} { return 0 } } - if ![runto "all_started"] then { + if { ![runto "all_started"] } { return 0 } delete_breakpoints @@ -65,9 +65,9 @@ proc prepare_core {} { global gcorefile gcore_created global binfile - clean_restart ${binfile} + clean_restart ${::testfile} - if ![runto all_started] then { + if { ![runto all_started] } { return -1 } @@ -114,7 +114,7 @@ proc setup {non-stop {multi_process ""}} { # Make GDB read files from the local file system, not through the # remote targets, to speed things up. set ::GDBFLAGS "${::GDBFLAGS} -ex \"set sysroot\"" - clean_restart ${binfile} + clean_restart ${::testfile} } # multi-target depends on target running in non-stop mode. Force @@ -123,13 +123,13 @@ proc setup {non-stop {multi_process ""}} { gdb_test_no_output "set non-stop ${non-stop}" - if {${multi_process} ne ""} then { + if {${multi_process} ne ""} { gdb_test \ "set remote multiprocess-feature-packet $multi_process" \ "Support for the 'multiprocess-feature' packet on future remote targets is set to \"${multi_process}\"." } - if ![runto all_started] then { + if { ![runto all_started] } { return 0 } @@ -175,12 +175,16 @@ proc multi_target_prepare {} { return 0 } + if {![allow_multi_inferior_tests]} { + return 0 + } + # The plain remote target can't do multiple inferiors. if {[target_info gdb_protocol] != ""} { return 0 } - if { [prepare_for_testing "failed to prepare" ${binfile} "${srcfile}" \ + if { [prepare_for_testing "failed to prepare" $::testfile $srcfile \ {debug pthreads}] } { return 0 } diff --git a/gdb/testsuite/gdb.multi/multi-term-settings.exp b/gdb/testsuite/gdb.multi/multi-term-settings.exp index 2f8b3b8..2893d36 100644 --- a/gdb/testsuite/gdb.multi/multi-term-settings.exp +++ b/gdb/testsuite/gdb.multi/multi-term-settings.exp @@ -25,9 +25,11 @@ standard_testfile +require allow_multi_inferior_tests + require can_spawn_for_attach -if [build_executable "failed to prepare" $testfile $srcfile {debug}] { +if {[build_executable "failed to prepare" $testfile $srcfile {debug}]} { return -1 } @@ -54,7 +56,7 @@ proc create_inferior {which_inf inf_how} { # Run to main and delete breakpoints. proc my_runto_main {} { - if ![runto_main] { + if {![runto_main]} { return 0 } else { # Delete breakpoints otherwise GDB would try to step over @@ -67,7 +69,7 @@ proc create_inferior {which_inf inf_how} { } if {$inf_how == "run"} { - if [my_runto_main] { + if {[my_runto_main]} { global inferior_spawn_id return $inferior_spawn_id } @@ -78,7 +80,7 @@ proc create_inferior {which_inf inf_how} { set inf_tty_name $spawn_out(slave,name) gdb_test_no_output "tty $inf_tty_name" "tty TTY" - if [my_runto_main] { + if {[my_runto_main]} { return $inf_spawn_id } } elseif {$inf_how == "attach"} { @@ -136,7 +138,7 @@ proc coretest {inf1_how inf2_how} { global gdb_spawn_id global decimal - clean_restart $binfile + clean_restart $::testfile with_test_prefix "inf1" { set inf1_spawn_id [create_inferior 1 $inf1_how] diff --git a/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp b/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp index a7055d7..781937d 100644 --- a/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp +++ b/gdb/testsuite/gdb.multi/pending-bp-del-inferior.exp @@ -37,7 +37,7 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { # # Return true after a successful setup, otherwise, return false. proc test_setup {} { - clean_restart $::binfile + clean_restart $::testfile if {![runto_main]} { return 0 diff --git a/gdb/testsuite/gdb.multi/pending-bp.exp b/gdb/testsuite/gdb.multi/pending-bp.exp index 1cd1cfb..30a75b9 100644 --- a/gdb/testsuite/gdb.multi/pending-bp.exp +++ b/gdb/testsuite/gdb.multi/pending-bp.exp @@ -45,7 +45,7 @@ if { [build_executable "failed to prepare" $testfile $srcfile \ # 'breakpoint pending' flag is enabled, so pending breakpoints can be created # without GDB prompting the user. proc do_test_setup { inf_1_stop inf_2_stop } { - clean_restart ${::binfile} + clean_restart ${::testfile} gdb_locate_shlib $::binfile_lib @@ -328,5 +328,7 @@ proc_with_prefix py_test_clear_thread {} { # Run all the tests. test_no_inf_display test_pending_toggle -py_test_toggle_thread -py_test_clear_thread +if { [allow_python_tests] } { + py_test_toggle_thread + py_test_clear_thread +} diff --git a/gdb/testsuite/gdb.multi/remote-with-running-inferior.c b/gdb/testsuite/gdb.multi/remote-with-running-inferior.c new file mode 100644 index 0000000..a610eda --- /dev/null +++ b/gdb/testsuite/gdb.multi/remote-with-running-inferior.c @@ -0,0 +1,38 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +int global_var = 123; + +void +breakpt (void) +{ + /* Nothing. */ +} + +int +main (void) +{ + for (int i = 0; i < 30; ++i) + { + sleep (1); + breakpt (); + } + + return 0; +} diff --git a/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp b/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp new file mode 100644 index 0000000..43842ba --- /dev/null +++ b/gdb/testsuite/gdb.multi/remote-with-running-inferior.exp @@ -0,0 +1,171 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Set an inferior running in the background (using "run&"), then +# connect to gdbserver in a second inferior. When this test was added +# there were two bugs in GDB. First, just connecting to gdbserver +# while an inferior was running on a different connection type +# (e.g. inferior 1 was native, and inferior 2 was gdbserver) would +# trigger an assertion. +# +# Then, once the assertion was fixed, GDB would stop the thread from +# the first inferior, but would fail to update it's state in GDB core, +# this would leave the thread stopped, but GDB core thinking the +# thread was running. Check this is fixed by looking at the 'info +# threads' output after connecting to the remote target. + +# This tests the use of native and remote targets, and also depends on use +# of the 'run' command. If we try to run it with a board that forces native +# targets to become remote, then this test isn't going to work, especially +# for 'remote' targets where 'run' is not supported. +require {string equal [target_info gdb_protocol] ""} + +load_lib gdbserver-support.exp + +require allow_gdbserver_tests + +standard_testfile + +if { [build_executable "failed to build" $testfile $srcfile] } { + return +} + +# Set non-stop mode based on NON_STOP. Start a native inferior running in +# the background, then start a second, remote inferior. Based on the value +# of NON_STOP we might expect the inferior thread to have been stopped. +# Confirm inferior one is in the correct state, and that it can be +# interrupted and/or resumed. +proc run_test { target_non_stop non_stop } { + clean_restart $::testfile + + # Setup non-stop settings. + gdb_test_no_output "maint set target-non-stop $target_non_stop" + gdb_test_no_output "set non-stop $non_stop" + + # Start the first inferior running in the background. + gdb_test -no-prompt-anchor "run&" "Starting program: .*" "start background inferior" + + # Add a second inferior. + gdb_test "add-inferior" "Added inferior 2.*" + gdb_test "inferior 2" "Switching to inferior 2.*" + + # Setup the sysroot if possible. This will make connecting to + # gdbserver quicker. + if { ![is_remote host] && ![is_remote target] } { + gdb_test "set sysroot" + } + + # Setup, and connect to, a remote target. + set target_exec [gdbserver_download_current_prog] + set res [gdbserver_start "" $target_exec] + set gdbserver_protocol [lindex $res 0] + set gdbserver_gdbport [lindex $res 1] + set res [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] + gdb_assert {$res == 0} "connect to remote target" + + # Check the info threads output. We're checking that we see the two + # threads we expect, that the correct thread (inferior two's thread) + # is current, and that none of the threads are running. + set state_inferior_1 "" + set state_inferior_2 "" + gdb_test_multiple "info threads" "" { + -re "^info threads\r\n" { + exp_continue + } + + -re "^\\s+Id\\s+Target Id\\s+Frame\\s*\r\n" { + exp_continue + } + + -re "^\\s+1\\.1\\s+\[^\r\n\]+\\(running\\)\r\n" { + set state_inferior_1 "running" + exp_continue + } + + -re "^\\*\\s+2\\.1\\s+\[^\r\n\]+\\(running\\)\r\n" { + set state_inferior_2 "running" + exp_continue + } + + -re "^\\s+1\\.1\\s+\[^\r\n\]+\r\n" { + set state_inferior_1 "stopped" + exp_continue + } + + -re "^\\*\\s+2\\.1\\s+\[^\r\n\]+\r\n" { + set state_inferior_2 "stopped" + exp_continue + } + + -re "^$::gdb_prompt $" { + if { $non_stop } { + gdb_assert { $state_inferior_1 == "running" \ + && $state_inferior_2 == "stopped" } \ + $gdb_test_name + } else { + gdb_assert { $state_inferior_1 == "stopped" \ + && $state_inferior_2 == "stopped" } \ + $gdb_test_name + } + } + } + + # Allow inferior 2 to reach main. The confirms that inferior 2 can be + # set running again. + gdb_breakpoint main + gdb_continue_to_breakpoint "breakpoint in main" + gdb_test "bt 1" \ + "#0\\s+main \\(\\) at\[^\r\n\]+" \ + "check inferior 2 is in main" + + # Switch to inferior 1 and allow it to continue. This is a + # critical part of the test. When the test was added a bug (in + # all-stop mode) would leave inferior 1 stopped, but GDB code + # would think the thread was running. As such. the thread + # couldn't be resumed again. + gdb_test "inferior 1" "Switching to inferior 1.*" + + # In non-stop mode, thread 1.1 is correctly left running, so we + # need to stop it now. + if { $non_stop } { + gdb_test -no-prompt-anchor "interrupt" + gdb_test "p 1 + 1" " = 2" \ + "simple print to resync output" + } + + gdb_breakpoint breakpt + gdb_continue_to_breakpoint "continue to breakpoint in breakpt" + gdb_test "bt 1" \ + [multi_line \ + "#0\\s+breakpt \\(\\) at\[^\r\n\]+" \ + "\\(More stack frames follow\\.\\.\\.\\)"] \ + "check inferior 1 is in breakpt" + + # Switch back to inferior 2. The testing infrastructure will try to + # use 'monitor exit' to close gdbserver. It helps if we are in the + # gdbserver inferior when the script finishes. + gdb_test "inferior 2" "Switching to inferior 2.*" \ + "switch back to inferior 2" +} + +# Multi-inferior support requires non-stop targets. +foreach_with_prefix target_non_stop { auto on } { + # But it's OK if we're emulating all-stop mode on top of non-stop. + foreach_with_prefix non_stop { on off } { + run_test $target_non_stop $non_stop + } +} diff --git a/gdb/testsuite/gdb.multi/remove-inferiors.exp b/gdb/testsuite/gdb.multi/remove-inferiors.exp index 586d958..52e6cb0 100644 --- a/gdb/testsuite/gdb.multi/remove-inferiors.exp +++ b/gdb/testsuite/gdb.multi/remove-inferiors.exp @@ -32,7 +32,7 @@ proc add_inferior { expected_num message } { proc test_remove_inferiors { } { global binfile - clean_restart ${binfile} + clean_restart ${::testfile} # Add another inferior and switch to it. add_inferior 2 "add second inferior" diff --git a/gdb/testsuite/gdb.multi/run-only-second-inf.exp b/gdb/testsuite/gdb.multi/run-only-second-inf.exp index 7b6532c..3645962 100644 --- a/gdb/testsuite/gdb.multi/run-only-second-inf.exp +++ b/gdb/testsuite/gdb.multi/run-only-second-inf.exp @@ -31,7 +31,7 @@ if {[build_executable "failed to prepare" $testfile $srcfile {debug}]} { # So, start GDB with this setting. save_vars { GDBFLAGS } { append GDBFLAGS " -ex \"maint set target-non-stop on\"" - clean_restart ${binfile} + clean_restart ${::testfile} } # Add and start the second inferior. diff --git a/gdb/testsuite/gdb.multi/sched-multi-add-inferior.exp b/gdb/testsuite/gdb.multi/sched-multi-add-inferior.exp new file mode 100644 index 0000000..9344c80 --- /dev/null +++ b/gdb/testsuite/gdb.multi/sched-multi-add-inferior.exp @@ -0,0 +1,109 @@ +# Copyright 2025 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Start multiple inferiors while schedule-multiple is on. Make use of +# the multi-target.exp.tcl support library for the helper procs, but +# don't use its 'setup' proc as that only turns on schedule-multiple +# after starting all the inferiors, and that is too late for this test. +# +# The specific bug that this test guards against was that, when a +# native target starts and runs upto a breakpoint, the thread would +# have its last signal recorded as SIGTRAP. +# +# When starting a gdbserver inferior (with schedule-multiple on) the +# native target would also be resumed. +# +# However, GDBs 'run' command was failing to clear out the old signal +# state from the native inferior, and so GDB would deliver a SIGTRAP +# to that inferior, killing it. + +source $srcdir/$subdir/multi-target.exp.tcl + +if {![multi_target_prepare]} { + return +} + +# Some breakpoint locations. +set line1 [gdb_get_line_number "set break 1 here"] +set line2 [gdb_get_line_number "set break 2 here"] + +# Start two inferiors using TARGET_TYPE_1 and TARGET_TYPE_2 (either +# 'extended-remote' or 'native'). Due to the way that inferior 1 is +# special (existing once GDB starts up), we just use the existing +# helper functions to create inferiors 2 and 3 using these types, and +# we leave inferior 1 unused. +proc run_test { target_type_1 target_type_2 } { + cleanup_gdbservers + + clean_restart + + gdb_test_no_output "set sysroot" + + # The schedule-multiple setting relies on all targets running in + # non-stop mode. Force it on for remote targets, until this is + # the default. + gdb_test_no_output "maint set target-non-stop on" + + # Run in all-stop mode. + gdb_test_no_output "set non-stop off" + + # Turn on schedule-multiple before starting any inferiors. + gdb_test_no_output "set schedule-multiple on" + + if {![add_inferior 2 $target_type_1 $::binfile]} { + return 0 + } + + if {![add_inferior 3 $target_type_2 $::binfile]} { + return 0 + } + + # Check we see all the expected threads. + gdb_test "info threads" \ + [multi_line \ + "\\s+Id\\s+Target Id\\s+Frame\\s*" \ + "\\s+2\\.1\\s+\[^\r\n\]+" \ + "\\s+2\\.2\\s+\[^\r\n\]+" \ + "\\*\\s+3\\.1\\s+\[^\r\n\]+" \ + "\\s+3\\.2\\s+\[^\r\n\]+"] + + # Ensure that all inferiors can be set running again. + gdb_test "break ${::srcfile}:${::line1} thread 3.1" + gdb_test "break ${::srcfile}:${::line2} thread 2.1" + gdb_test "continue" \ + [multi_line \ + "Thread 3\\.1 \[^\r\n\]+, main \\(\[^\r\n\]+\\) at \[^\r\n\]+" \ + "$::decimal\\s+function1 \\(\\); /\\* set break 1 here \\*/"] \ + "continue to function1" + + # Unblock thread 2.1 and continue again. This time, thread 2.1 + # will hit a breakpoint. + gdb_test "thread apply 2.1 set wait_for_gdb = 0" ".*" + gdb_test "continue" \ + [multi_line \ + "Thread 2\\.1 \[^\r\n\]+, main \\(\[^\r\n\]+\\) at \[^\r\n\]+" \ + "$::decimal\\s+function2 \\(\\); /\\* set break 2 here \\*/"] \ + "continue to function2" +} + +set all_target_types { extended-remote native } + +foreach_with_prefix target_type_1 $all_target_types { + foreach_with_prefix target_type_2 $all_target_types { + run_test $target_type_1 $target_type_2 + } +} + +multi_target_cleanup diff --git a/gdb/testsuite/gdb.multi/start-inferior-specific.exp b/gdb/testsuite/gdb.multi/start-inferior-specific.exp index 819c1c3..39621f0 100644 --- a/gdb/testsuite/gdb.multi/start-inferior-specific.exp +++ b/gdb/testsuite/gdb.multi/start-inferior-specific.exp @@ -25,10 +25,13 @@ standard_testfile .c -other.c +require allow_multi_inferior_tests + require !use_gdb_stub set srcfile_other ${srcfile2} -set binfile_other ${binfile}-other +set testfile_other $testfile-other +set binfile_other [standard_output_file $testfile_other] if { [build_executable ${testfile}.exp ${binfile} "${srcfile}" {debug}] != 0 } { return -1 @@ -46,7 +49,7 @@ proc do_test {} { append ::GDBFLAGS " -ex \"maintenance set target-non-stop on\"" } - clean_restart ${::binfile_other} + clean_restart $::testfile_other } gdb_test -no-prompt-anchor "run&" "Starting program: .*" "start background inferior" diff --git a/gdb/testsuite/gdb.multi/stop-all-on-exit.exp b/gdb/testsuite/gdb.multi/stop-all-on-exit.exp index b4ff09c..47071f3 100644 --- a/gdb/testsuite/gdb.multi/stop-all-on-exit.exp +++ b/gdb/testsuite/gdb.multi/stop-all-on-exit.exp @@ -18,6 +18,8 @@ # Test that in all-stop mode with multiple inferiors, GDB stops all # threads upon receiving an exit event from one of the inferiors. +require allow_multi_inferior_tests + # This is a test specific for a native target, where we use the # "-exec" argument to "add-inferior" and we explicitly don't do # "maint set target-non-stop on". diff --git a/gdb/testsuite/gdb.multi/tids-gid-reset.exp b/gdb/testsuite/gdb.multi/tids-gid-reset.exp index 6cc27eb..1785ac2 100644 --- a/gdb/testsuite/gdb.multi/tids-gid-reset.exp +++ b/gdb/testsuite/gdb.multi/tids-gid-reset.exp @@ -54,6 +54,8 @@ with_test_prefix "single-inferior" { # non-extended gdbserver is not supported. require !use_gdb_stub +require allow_multi_inferior_tests + # Test with multiple inferiors. This time, since we restart inferior # 1 while inferior 2 still has threads, then the new thread 1.1 should # end up with GID == 3, since we won't be able to reset the global diff --git a/gdb/testsuite/gdb.multi/tids.exp b/gdb/testsuite/gdb.multi/tids.exp index b84f908..436a38a 100644 --- a/gdb/testsuite/gdb.multi/tids.exp +++ b/gdb/testsuite/gdb.multi/tids.exp @@ -124,6 +124,9 @@ with_test_prefix "single inferior" { gdb_test "print \$_inferior_thread_count" " = 1" } +# The rest of the tests require running multiple inferiors. +require allow_multi_inferior_tests + # "info threads" while there are multiple inferiors should show # qualified thread IDs. with_test_prefix "two inferiors" { @@ -290,7 +293,7 @@ with_test_prefix "two inferiors" { # Try both the convenience variable and the literal number. foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } { set expected [string_to_regexp $thr] - gdb_test "info threads $thr" "No threads match '${expected}'." + gdb_test "info threads $thr" "No threads matched\\." # "info threads" works like a filter. If there's any other # valid thread in the list, there's no error. info_threads "$thr 1.1" "1.1" @@ -412,7 +415,7 @@ with_test_prefix "two inferiors" { # Check that we do parse the inferior number and don't confuse it. gdb_test "info threads 3.1" \ - "No threads match '3.1'\." + "No threads matched\\." } if { [allow_python_tests] } { diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp index 70c3da9..a149407 100644 --- a/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp +++ b/gdb/testsuite/gdb.multi/watchpoint-multi-exit.exp @@ -17,6 +17,8 @@ # watchpoints don't end up with stale locations, preventing resumption # of other inferiors. +require allow_fork_tests + standard_testfile if {[build_executable "failed to build" $testfile $srcfile {debug}]} { @@ -29,12 +31,12 @@ if {[build_executable "failed to build" $testfile $srcfile {debug}]} { proc do_test {dispose} { global binfile bkptno_numopt_re - clean_restart $binfile + clean_restart $::testfile gdb_test_no_output "set follow-fork child" gdb_test_no_output "set detach-on-fork off" - if ![runto "child_function"] { + if {![runto "child_function"]} { return } diff --git a/gdb/testsuite/gdb.multi/watchpoint-multi.exp b/gdb/testsuite/gdb.multi/watchpoint-multi.exp index f448689..501f0a6 100644 --- a/gdb/testsuite/gdb.multi/watchpoint-multi.exp +++ b/gdb/testsuite/gdb.multi/watchpoint-multi.exp @@ -16,6 +16,8 @@ standard_testfile set executable ${testfile} +require allow_multi_inferior_tests + # Multiple inferiors are needed, therefore both native and extended gdbserver # modes are supported. Only non-extended gdbserver is not supported. require !use_gdb_stub @@ -36,7 +38,7 @@ gdb_test_no_output "set breakpoint always-inserted on" # displaced-stepping is also needed as other GDB sometimes still removes the # breakpoints, even with always-inserted on. # Without the support this test just is not as thorough as it could be. -if [support_displaced_stepping] { +if {[support_displaced_stepping]} { gdb_test_no_output "set displaced-stepping on" } |