blob: a0e43add125b59e1e351c7f75a581d29919d13a7 [file]
# This testcase is part of GDB, the GNU debugger.
#
# Copyright 2025-2026 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. This confirms that inferior 2 can be
# set running again.
gdb_test "break main inferior 2" \
"Breakpoint $::decimal at .*"
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]+} \
[string_to_regexp "(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
}
}