diff --git a/gdb/NEWS b/gdb/NEWS
index a6ea7c9f98f..cb576edd203 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -71,6 +71,13 @@
For both /r and /b GDB is now better at using whitespace in order to
align the disassembled instruction text.
+* The add-inferior, clone-inferior, and MI -add-inferior commands will
+ now give a warning, and create the new inferior without a
+ connection, when the current inferior, at the time the command is
+ given, is a core-file target. The core-file target could never
+ really be shared between inferiors, GDB is now more vocal about what
+ is going on.
+
* New commands
maintenance set ignore-prologue-end-flag on|off
diff --git a/gdb/corelow.c b/gdb/corelow.c
index 293bc8d4f59..4d8393a3587 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -128,6 +128,11 @@ class core_target final : public process_stratum_target
/* See definition. */
void info_proc_mappings (struct gdbarch *gdbarch);
+ /* The core_target only works for the inferior in which it was initially
+ opened, and can't be copied to some other inferior's target_stack. */
+ bool is_shareable () override
+ { return false; }
+
private: /* per-core data */
/* Get rid of the core inferior. */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 107df84d108..a5009c85e09 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3358,8 +3358,31 @@
remote} command to connect to some other @code{gdbserver} instance,
use @code{run} to spawn a local program, etc.
+Not all connections can be shared between inferiors. For example, the
+@code{target core} target is unique for each inferior. That is,
+multiple inferiors can use @code{target core} at the same time, but
+each @code{target core} is different. If you try to
+@code{add-inferior}, and the current inferior is @code{target core},
+then @value{GDBN} will give a warning and create the new inferior
+without a connection, like this:
+
+@smallexample
+(@value{GDBP}) file test1
+Reading symbols from test1...
+(@value{GDBP}) target core core.test1.433190
+[New LWP 433190]
+Core was generated by `./test1'.
+Program terminated with signal SIGSEGV, Segmentation fault.
+#0 0x0000000000401111 in foo () at test1.c:6
+6 return *global_ptr;
+(@value{GDBP}) add-inferior
+[New inferior 2]
+warning: can't share connection 1 (core) between inferiors
+Added inferior 2
+@end smallexample
+
@kindex clone-inferior
-@item clone-inferior [ -copies @var{n} ] [ @var{infno} ]
+@item clone-inferior [ -copies @var{n} ] [ -no-connection ] [ @var{infno} ]
Adds @var{n} inferiors ready to execute the same program as inferior
@var{infno}; @var{n} defaults to 1, and @var{infno} defaults to the
number of the current inferior. This command copies the values of the
@@ -3384,6 +3407,13 @@
You can now simply switch focus to inferior 2 and run it.
+Like @code{add-inferior}, @code{clone-inferior} shares the connection
+with the inferior @var{infno}. If the @var{-no-connection} option is
+given, then the new inferior will be created without a connection. If
+the connection of inferior @var{infno} can't be shared, then
+@value{GDBN} will give a warning, and the new inferior will be created
+without a connection.
+
@kindex remove-inferiors
@item remove-inferiors @var{infno}@dots{}
Removes the inferior or inferiors @var{infno}@dots{}. It is not
@@ -37786,6 +37816,11 @@
@code{gdbserver} instance, use @code{-exec-run} to spawn a local
program, etc.
+If the connection of the current inferior cannot be shared, e.g.@: the
+@code{-target-select core} target cannot be shared between inferiors,
+then @value{GDBN} will give a warning and create the new inferior
+without a connection.
+
The command response always has a field, @var{inferior}, whose value
is the identifier of the thread group corresponding to the new
inferior.
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 26b242ed1bc..ccc4d451e2f 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -817,6 +817,22 @@ switch_to_inferior_and_push_target (inferior *new_inf,
symbols. */
switch_to_inferior_no_thread (new_inf);
+ if (!no_connection && proc_target != nullptr
+ && !proc_target->is_shareable ())
+ {
+ if (proc_target->connection_string () != nullptr)
+ warning (_("can't share connection %d (%s %s) between inferiors"),
+ proc_target->connection_number,
+ proc_target->shortname (),
+ proc_target->connection_string ());
+ else
+ warning (_("can't share connection %d (%s) between inferiors"),
+ proc_target->connection_number,
+ proc_target->shortname ());
+
+ proc_target = nullptr;
+ }
+
/* Reuse the target for new inferior. */
if (!no_connection && proc_target != NULL)
{
diff --git a/gdb/inferior.h b/gdb/inferior.h
index ab6a209a448..7aa5f157034 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -762,9 +762,9 @@ extern struct inferior *add_inferior_with_spaces (void);
/* Print the current selected inferior. */
extern void print_selected_inferior (struct ui_out *uiout);
-/* Switch to inferior NEW_INF, a new inferior, and unless
- NO_CONNECTION is true, push the process_stratum_target of ORG_INF
- to NEW_INF. */
+/* Switch to inferior NEW_INF, a new inferior, and unless NO_CONNECTION is
+ true, or the process_stratum_target of ORG_INF is not shareable, push
+ the process_stratum_target of ORG_INF to NEW_INF. */
extern void switch_to_inferior_and_push_target
(inferior *new_inf, bool no_connection, inferior *org_inf);
diff --git a/gdb/target.c b/gdb/target.c
index 1e447f604d9..65bc0e7246e 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -1188,6 +1188,12 @@ target_stack::push (target_ops *t)
if (m_stack[stratum].get () != nullptr)
unpush (m_stack[stratum].get ());
+ /* If this target can't be shared, then check that the target doesn't
+ already appear on some other target stack. */
+ if (!t->is_shareable ())
+ for (inferior *inf : all_inferiors ())
+ gdb_assert (!inf->target_is_pushed (t));
+
/* Now add the new one. */
m_stack[stratum] = std::move (ref);
@@ -3226,6 +3232,14 @@ target_ops::fileio_readlink (struct inferior *inf, const char *filename,
/* See target.h. */
+bool
+target_ops::is_shareable ()
+{
+ return true;
+}
+
+/* See target.h. */
+
int
target_fileio_open (struct inferior *inf, const char *filename,
int flags, int mode, bool warn_if_slow, fileio_error *target_errno)
diff --git a/gdb/target.h b/gdb/target.h
index 547ee8a3bbd..30e5085a543 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1321,6 +1321,14 @@ struct target_ops
virtual bool store_memtags (CORE_ADDR address, size_t len,
const gdb::byte_vector &tags, int type)
TARGET_DEFAULT_NORETURN (tcomplain ());
+
+ /* Return true if this target can be shared on multiple target_stacks,
+ or false if this target should only appear on a single target_stack.
+ When this function returns false multiple separate instances of the
+ same target_ops sub-class can still appear on different
+ target_stacks, but the same concrete instance can only appear on a
+ single target_stack. */
+ virtual bool is_shareable ();
};
/* Deleter for std::unique_ptr. See comments in
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 00000000000..f996973023e
--- /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 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 . */
+
+#include
+
+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 00000000000..fb99e137c3f
--- /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 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 . */
+
+#include
+
+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 00000000000..22a56c07ceb
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/multi-core-files.exp
@@ -0,0 +1,160 @@
+# Copyright 2022 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 .
+
+# 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 binfile1 "${binfile}-1"
+set binfile2 "${binfile}-2"
+
+if {[build_executable "build first executable" $binfile1 $srcfile \
+ debug] == -1} {
+ untested "failed to compile first executable"
+ return -1
+}
+
+if {[build_executable "build second executable" $binfile2 $srcfile2 \
+ debug] == -1} {
+ untested "failed to compile second executable"
+ return -1
+}
+
+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 ${binfile1}
+gdb_test "core-file $corefile1" "Program terminated with .*" \
+ "load core file"
+gdb_test "bt" "bar \\(\\) at .*" \
+ "check backtrace in inferior 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 1 \\(core\\) between inferiors" \
+ "Added inferior 2"]
+gdb_test "clone-inferior" \
+ [multi_line \
+ "\\\[New inferior 3\\\]" \
+ "warning: can't share connection 1 \\(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 1 \\(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+1 \\(core\\)\\s+\[^\r\n\]+.*" \
+ "\\s+2\\s+\\s+" \
+ "\\s+3\\s+\\s+\[^\r\n\]+" \
+ "\\s+4\\s+\\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+1 \\(core\\)\\s+\[^\r\n\]+.*" \
+ "\\s+2\\s+\\s+" \
+ "\\s+3\\s+\\s+\[^\r\n\]+" \
+ "\\s+4\\s+\\s+" \
+ "\\s+5\\s+\\s+" \
+ "\\s+6\\s+\\s+\[^\r\n\]+" \
+ "\\s+7\\s+\\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+1\\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"