1# This testcase is part of GDB, the GNU debugger. 2# 3# Copyright 2020-2023 Free Software Foundation, Inc. 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18# Test that GDB can handle receiving the W and X packets for a target 19# with multiple threads, but only a single inferior. 20# 21# Specifically, check GDB handles this case where multi-process 22# extensions are turned off. At one point this was causing GDB to 23# give a warning when the exit arrived that the remote needed to 24# include a thread-id, which was not correct. 25 26load_lib gdbserver-support.exp 27 28if { [skip_gdbserver_tests] } { 29 verbose "skipping gdbserver tests" 30 return -1 31} 32 33standard_testfile 34 35# Start up GDB and GDBserver debugging EXECUTABLE. When 36# DISABLE_MULTI_PROCESS is true then disable GDB's remote 37# multi-process support, otherwise, leave it enabled. 38# 39# Places a breakpoint in function 'breakpt' and then continues to the 40# breakpoint, at which point it runs 'info threads'. 41proc prepare_for_test { executable disable_multi_process } { 42 global GDBFLAGS 43 44 save_vars { GDBFLAGS } { 45 # If GDB and GDBserver are both running locally, set the sysroot to avoid 46 # reading files via the remote protocol. 47 if { ![is_remote host] && ![is_remote target] } { 48 set GDBFLAGS "$GDBFLAGS -ex \"set sysroot\"" 49 } 50 51 clean_restart ${executable} 52 } 53 54 # Make sure we're disconnected, in case we're testing with an 55 # extended-remote board, therefore already connected. 56 gdb_test "disconnect" ".*" 57 58 # Disable XML-based thread listing, and possible the multi-process 59 # extensions. 60 gdb_test_no_output "set remote threads-packet off" 61 if { $disable_multi_process } { 62 gdb_test_no_output "set remote multiprocess-feature-packet off" 63 } 64 65 # Start gdbserver and connect. 66 set res [gdbserver_start "" $executable] 67 set gdbserver_protocol [lindex $res 0] 68 set gdbserver_gdbport [lindex $res 1] 69 set res [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] 70 if ![gdb_assert {$res == 0} "connect"] { 71 return 72 } 73 74 # Run until we hit the breakpt function, then list all threads. 75 gdb_breakpoint "breakpt" 76 gdb_continue_to_breakpoint "breakpt" 77 gdb_test "info threads" ".*" 78} 79 80# Run the tests where the inferior exits normally (the W packet) while 81# we have multiple-threads. EXECUTABLE is the binary under test, and 82# DISABLE_MULTI_PROCESS indicates if we should disable GDB's remote 83# multi-process support. 84proc run_exit_test { executable disable_multi_process } { 85 global decimal 86 87 prepare_for_test ${executable} ${disable_multi_process} 88 89 # Finally, continue until the process exits, ensure we don't see 90 # any warnings between "Continuing." and the final process has 91 # exited message. 92 if { $disable_multi_process } { 93 set process_pattern "Remote target" 94 } else { 95 set process_pattern "process $decimal" 96 } 97 gdb_test "continue" \ 98 [multi_line \ 99 "Continuing\\." \ 100 "\\\[Inferior $decimal \\\(${process_pattern}\\\) exited normally\\\]" ] \ 101 "continue until process exits" 102} 103 104# Run the tests where the inferior exits with a signal (the X packet) 105# while we have multiple-threads. EXECUTABLE is the binary under 106# test, and DISABLE_MULTI_PROCESS indicates if we should disable GDB's 107# remote multi-process support. 108proc run_signal_test { executable disable_multi_process } { 109 global decimal gdb_prompt 110 111 prepare_for_test ${executable} ${disable_multi_process} 112 113 set inf_pid [get_valueof "/d" "global_pid" "unknown"] 114 gdb_assert ![string eq ${inf_pid} "unknown"] "read the pid" 115 116 # This sets the inferior running again, with all threads going 117 # into a long delay loop. 118 send_gdb "continue\n" 119 120 # Send the inferior a signal to kill it. 121 sleep 1 122 remote_exec target "kill -9 ${inf_pid}" 123 124 # Process the output from GDB. 125 gdb_test_multiple "" "inferior exited with signal" { 126 -re "Continuing\\.\r\n\r\nProgram terminated with signal SIGKILL, Killed.\r\nThe program no longer exists.\r\n$gdb_prompt $" { 127 pass $gdb_test_name 128 } 129 } 130} 131 132# Run all of the tests. 133foreach_with_prefix test { exit signal } { 134 set def "DO_[string toupper $test]_TEST" 135 set func "run_${test}_test" 136 137 set executable "$binfile-${test}" 138 if [build_executable "failed to prepare" $executable $srcfile \ 139 [list debug pthreads additional_flags=-D${def}]] { 140 return -1 141 } 142 143 foreach_with_prefix multi_process { 0 1 } { 144 $func ${executable} ${multi_process} 145 } 146} 147