1 # Copyright 2023-2024 Free Software Foundation, Inc.
2 # This program is free software; you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation; either version 3 of the License, or
5 # (at your option) any later version.
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # This test checks that GDB correctly handles several cases that can
16 # occur when GDB attempts to detach an inferior process. The process
17 # can exit or be terminated (e.g. via SIGKILL) prior to GDB's event
18 # loop getting a chance to remove it from GDB's internal data
19 # structures. To complicate things even more, detach works differently
20 # when a checkpoint (created via GDB's "checkpoint" command) exists for
21 # the inferior. This test checks all four possibilities: process exit
22 # with no checkpoint, process termination with no checkpoint, process
23 # exit with a checkpoint, and process termination with a checkpoint.
27 # This test requires python.
28 require allow_python_tests
30 # This test attempts to kill a process on the host running GDB, so
31 # disallow remote targets. (Setting --target_board to
32 # native-gdbserver or native-extended-gdbserver should still work.)
33 require {!is_remote target}
35 # Checkpoint support only works on native Linux:
36 if { [istarget "*-*-linux*"] && [target_info gdb_protocol] == ""} {
37 set has_checkpoint true
39 set has_checkpoint false
44 lappend flags additional_flags=-DBINFILE=$binfile
46 if {[build_executable "failed to prepare" $testfile $srcfile $flags] == -1} {
50 set checkpoint_line [gdb_get_line_number "Checkpoint here"]
52 # Start an inferior, which blocks in a spin loop. Setup a Python
53 # function that performs an action based on EXIT_P that will cause the
54 # inferior to exit, and then, within the same Python function, ask GDB
55 # to detach from the inferior. Use 'continue&' to run the inferior in
56 # the background, and then invoke the Python function. Note, too, that
57 # non-stop mode is enabled during the restart; if this is not done,
58 # remote_target::putpkt_binary in remote.c will disallow some of the
59 # operations necessary for this test.
61 # The idea is that GDB's event loop will not get a chance to handle
62 # the inferior exiting, so it will only be at the point that we try to
63 # detach that we notice that the inferior has exited.
65 # When EXIT_P is true the action we perform to terminate the inferior
66 # is to set a flag in the inferior, which allows the inferior to break
67 # out of its spin loop.
69 # When EXIT_P is false the action we perform is to send SIGKILL to the
72 # When CHECKPOINT_P is true, before issuing 'continue&' we use the
73 # 'checkpoint' command to create a checkpoint of GDB.
75 # When CHECKPOINT_P is false we don't use the 'checkpoint' command.
76 proc run_test { exit_p checkpoint_p } {
77 save_vars { ::GDBFLAGS } {
78 append ::GDBFLAGS " -ex \"set non-stop on\""
79 clean_restart $::binfile
86 if { $checkpoint_p } {
87 # Active checkpoint-specific code in $srcfile.
88 gdb_test_no_output "set var with_checkpoint=1"
90 # Run to line where we want to set the checkpoint.
91 gdb_breakpoint "$::srcfile:$::checkpoint_line"
92 gdb_continue_to_breakpoint "checkpoint line"
95 gdb_test "checkpoint" \
96 "checkpoint 1: fork returned pid $::decimal\\."
99 # Must get the PID before we resume the inferior.
100 set inf_pid [get_inferior_pid]
102 # Put the PID in a python variable so that a numerical PID won't
103 # appear in the PASS/FAIL output.
104 gdb_test_no_output "python inf_pid=$inf_pid" "assign inf_pid"
106 gdb_test "continue &"
109 set action_line "gdb.execute(\"set variable dont_exit_just_yet=0\")"
111 set action_line "os.kill(inf_pid, signal.SIGKILL)"
114 gdb_test_multiline "Create worker function" \
119 "def kill_and_detach():" "" \
121 " time.sleep(1)" "" \
122 " gdb.execute(\"detach\")" "" \
125 if { $checkpoint_p } {
126 # NOTE: The 'checkpoint' system in GDB appears to be a little
127 # iffy. This detach does seem to restore the checkpoint, but
128 # it leaves the inferior stuck in a running state.
129 gdb_test_no_output "python kill_and_detach()"
131 gdb_test "python kill_and_detach()" \
132 "\\\[Inferior $::decimal \[^\r\n\]+ detached\\\]"
136 if { $has_checkpoint } {
137 set checkpoint_iters { true false }
139 set checkpoint_iters { false }
142 foreach_with_prefix exit_p { true false } {
143 foreach_with_prefix checkpoint_p $checkpoint_iters {
144 run_test $exit_p $checkpoint_p