aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/testsuite/gdb.base')
-rw-r--r--gdb/testsuite/gdb.base/kill-during-detach.c32
-rw-r--r--gdb/testsuite/gdb.base/kill-during-detach.exp132
2 files changed, 164 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.base/kill-during-detach.c b/gdb/testsuite/gdb.base/kill-during-detach.c
new file mode 100644
index 0000000..2d9cca9
--- /dev/null
+++ b/gdb/testsuite/gdb.base/kill-during-detach.c
@@ -0,0 +1,32 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2023 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 dont_exit_just_yet = 1;
+
+int
+main ()
+{
+ alarm (300);
+
+ /* Spin until GDB releases us. */
+ while (dont_exit_just_yet)
+ usleep (100000);
+
+ _exit (0);
+}
diff --git a/gdb/testsuite/gdb.base/kill-during-detach.exp b/gdb/testsuite/gdb.base/kill-during-detach.exp
new file mode 100644
index 0000000..26028d5
--- /dev/null
+++ b/gdb/testsuite/gdb.base/kill-during-detach.exp
@@ -0,0 +1,132 @@
+# Copyright 2023 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 test checks that GDB correctly handles several cases that can
+# occur when GDB attempts to detach an inferior process. The process
+# can exit or be terminated (e.g. via SIGKILL) prior to GDB's event
+# loop getting a chance to remove it from GDB's internal data
+# structures. To complicate things even more, detach works differently
+# when a checkpoint (created via GDB's "checkpoint" command) exists for
+# the inferior. This test checks all four possibilities: process exit
+# with no checkpoint, process termination with no checkpoint, process
+# exit with a checkpoint, and process termination with a checkpoint.
+
+standard_testfile
+
+# This test requires python.
+require allow_python_tests
+
+# This test attempts to kill a process on the host running GDB, so
+# disallow remote targets. (Setting --target_board to
+# native-gdbserver or native-extended-gdbserver should still work.)
+require {!is_remote target}
+
+# Checkpoint support only works on native Linux:
+if { [istarget "*-*-linux*"] && [target_info gdb_protocol] == ""} {
+ set has_checkpoint true
+} else {
+ set has_checkpoint false
+}
+
+if {[build_executable "failed to prepare" $testfile $srcfile] == -1} {
+ return -1
+}
+
+# Start an inferior, which blocks in a spin loop. Setup a Python
+# function that performs an action based on EXIT_P that will cause the
+# inferior to exit, and then, within the same Python function, ask GDB
+# to detach from the inferior. Use 'continue&' to run the inferior in
+# the background, and then invoke the Python function. Note, too, that
+# non-stop mode is enabled during the restart; if this is not done,
+# remote_target::putpkt_binary in remote.c will disallow some of the
+# operations necessary for this test.
+#
+# The idea is that GDB's event loop will not get a chance to handle
+# the inferior exiting, so it will only be at the point that we try to
+# detach that we notice that the inferior has exited.
+#
+# When EXIT_P is true the action we perform to terminate the inferior
+# is to set a flag in the inferior, which allows the inferior to break
+# out of its spin loop.
+#
+# When EXIT_P is false the action we perform is to send SIGKILL to the
+# inferior.
+#
+# When CHECKPOINT_P is true, before issuing 'continue&' we use the
+# 'checkpoint' command to create a checkpoint of GDB.
+#
+# When CHECKPOINT_P is false we don't use the 'checkpoint' command.
+proc run_test { exit_p checkpoint_p } {
+ save_vars { ::GDBFLAGS } {
+ append ::GDBFLAGS " -ex \"set non-stop on\""
+ clean_restart $::binfile
+ }
+
+ if {![runto_main]} {
+ return -1
+ }
+
+ if { $checkpoint_p } {
+ gdb_test "checkpoint" \
+ "checkpoint 1: fork returned pid $::decimal\\."
+ }
+
+ # Must get the PID before we resume the inferior.
+ set inf_pid [get_inferior_pid]
+
+ # Put the PID in a python variable so that a numerical PID won't
+ # appear in the PASS/FAIL output.
+ gdb_test_no_output "python inf_pid=$inf_pid" "assign inf_pid"
+
+ gdb_test "continue &"
+
+ if { $exit_p } {
+ set action_line "gdb.execute(\"set variable dont_exit_just_yet=0\")"
+ } else {
+ set action_line "os.kill(inf_pid, signal.SIGKILL)"
+ }
+
+ gdb_test_multiline "Create worker function" \
+ "python" "" \
+ "import time" "" \
+ "import os" "" \
+ "import signal" "" \
+ "def kill_and_detach():" "" \
+ " $action_line" "" \
+ " time.sleep(1)" "" \
+ " gdb.execute(\"detach\")" "" \
+ "end" ""
+
+ if { $checkpoint_p } {
+ # NOTE: The 'checkpoint' system in GDB appears to be a little
+ # iffy. This detach does seem to restore the checkpoint, but
+ # it leaves the inferior stuck in a running state.
+ gdb_test_no_output "python kill_and_detach()"
+ } else {
+ gdb_test "python kill_and_detach()" \
+ "\\\[Inferior $::decimal \[^\r\n\]+ detached\\\]"
+ }
+}
+
+if { $has_checkpoint } {
+ set checkpoint_iters { true false }
+} else {
+ set checkpoint_iters { false }
+}
+
+foreach_with_prefix exit_p { true false } {
+ foreach_with_prefix checkpoint_p $checkpoint_iters {
+ run_test $exit_p $checkpoint_p
+ }
+}