From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lndn.lancelotsix.com (lndn.lancelotsix.com [51.195.220.111]) by sourceware.org (Postfix) with ESMTPS id 0BD483858CDB for ; Wed, 5 Oct 2022 21:15:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0BD483858CDB Received: from ubuntu.lan (unknown [IPv6:2a02:390:9086::635]) by lndn.lancelotsix.com (Postfix) with ESMTPSA id AF32280F1F; Wed, 5 Oct 2022 21:15:10 +0000 (UTC) Date: Wed, 5 Oct 2022 21:15:05 +0000 From: Lancelot SIX To: Andrew Burgess Cc: gdb-patches@sourceware.org Subject: Re: [PATCHv2 7/7] gdb: some process_stratum_target should not be shared Message-ID: <20221005211505.u2pj6qzkumpf4kle@ubuntu.lan> References: <20220921131200.3983844-1-aburgess@redhat.com> <3ea56551906f0e7815950c3dc98747ce86b6e64d.1664729722.git.aburgess@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <3ea56551906f0e7815950c3dc98747ce86b6e64d.1664729722.git.aburgess@redhat.com> X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.5.11 (lndn.lancelotsix.com [0.0.0.0]); Wed, 05 Oct 2022 21:15:10 +0000 (UTC) X-Spam-Status: No, score=-11.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 05 Oct 2022 21:15:15 -0000 Hi, Thanks for doing this! I have a couple of comments below. On Sun, Oct 02, 2022 at 06:04:48PM +0100, Andrew Burgess via Gdb-patches wrote: > When multi-target support was added to GDB, an assumption was made > that all process_stratum_target sub-classes could be shared by > multiple inferiors. > > For things like the Linux and FreeBSD native targets, as well as the > remote target, this is absolutely true (or was made true). But some > targets were never updated to be shareable, for example, the > core_target, which is used when reading core-files, stores some of its > state in the program_space, but also, the core-file and the executable > being debugged are closely related. > > As each add-inferior call creates an inferior with a new > program_space, and doesn't automatically copy the executable, or the > current core-file, I don't think it really makes sense to "share" > core_target objects between inferiors. > > Consider this session: > > $ gdb -q > (gdb) file test1 > Reading symbols from test1... > (gdb) core-file 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; > (gdb) add-inferior > [New inferior 2] > Added inferior 2 on connection 1 (core) > (gdb) info inferiors > Num Description Connection Executable > * 1 process 433190 1 (core) /tmp/multi-core/test1 > 2 1 (core) > (gdb) info connections > Num What Description > * 1 core Local core dump file > (gdb) inferior 2 > [Switching to inferior 2 [] ()] > (gdb) file test2 > Reading symbols from test2... > (gdb) core-file core.test2.433203 > [New LWP 433203] > Core was generated by `./test2'. > Program terminated with signal SIGSEGV, Segmentation fault. > #0 0x0000000000401111 in main () at test2.c:6 > 6 return *global_ptr; > (gdb) info inferiors > Num Description Connection Executable > 1 process 433190 1 (core) /tmp/multi-core/test1 > * 2 process 433203 2 (core) /tmp/multi-core/test2 > (gdb) info connections > Num What Description > 1 core Local core dump file > * 2 core Local core dump file > (gdb) > > After the 'add-inferior' the core_target connection is shared between > the inferiors. However, as soon as the user sets up the core-file and > executable in the new inferior a new core connection has been created. > > I think this behaviour might be confusing, so I'd like to have GDB not > initially share the core connection. Instead, when the user tries to > add the new inferior a warning is given, and the new inferior is > created without a connection, like this: > > $ gdb -q > (gdb) file test1 > Reading symbols from test1... > (gdb) core-file 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; > (gdb) add-inferior > [New inferior 2] > warning: can't share connection 1 (core) between inferiors > Added inferior 2 > (gdb) info inferiors > Num Description Connection Executable > * 1 process 433190 1 (core) /tmp/multi-core/test1 > 2 > (gdb) > > If the user explicitly asks for the new inferior to be created without > a connection, then no warning will be given. > > At this point the user is free to setup inferior 2 with a different > executable and core file (or to do anything they like with the > inferior). > > In an earlier version of this patch I had GDB error instead of giving > a warning. However, the error message ended up being something like: > > can't share connection ..... between inferiors, use -no-connection > option to create an inferior without sharing a connection. > > but it seemed better to just create the inferior. > > I've updated the docs, and added a NEWS entry for the new warning. In > the docs for clone-inferior I've added reference to -no-connection, > which was previously missing. > --- > gdb/NEWS | 7 + > gdb/corelow.c | 5 + > gdb/doc/gdb.texinfo | 37 ++++- > gdb/inferior.c | 16 ++ > gdb/inferior.h | 6 +- > gdb/target.c | 14 ++ > gdb/target.h | 8 + > gdb/testsuite/gdb.multi/multi-core-files-1.c | 37 +++++ > gdb/testsuite/gdb.multi/multi-core-files-2.c | 31 ++++ > gdb/testsuite/gdb.multi/multi-core-files.exp | 156 +++++++++++++++++++ > 10 files changed, 313 insertions(+), 4 deletions(-) > create mode 100644 gdb/testsuite/gdb.multi/multi-core-files-1.c > create mode 100644 gdb/testsuite/gdb.multi/multi-core-files-2.c > create mode 100644 gdb/testsuite/gdb.multi/multi-core-files.exp > > 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..a558fc4de38 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 a498b9d493c..0868a55593a 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 344974c4811..639364e5de3 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..9cf188b0caa > --- /dev/null > +++ b/gdb/testsuite/gdb.multi/multi-core-files.exp > @@ -0,0 +1,156 @@ > +# 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 first executable" $binfile2 $srcfile2 \ s/first/second/ maybe? > + debug] == -1} { > + untested "failed to compile second executable" > + return -1 > +} > + > +set corefile1 [core_find $binfile1] > +set corefile2 [core_find $binfile2] I think you should check corefile*. On my system (where ulimit -c gives 0), I have: WARNING: can't generate a core file - core tests suppressed - check ulimit -c WARNING: can't generate a core file - core tests suppressed - check ulimit -c FAIL: gdb.multi/multi-core-files.exp: load core file FAIL: gdb.multi/multi-core-files.exp: check backtrace in inferior 1 FAIL: gdb.multi/multi-core-files.exp: add-inferior FAIL: gdb.multi/multi-core-files.exp: clone-inferior FAIL: gdb.multi/multi-core-files.exp: interpreter-exec mi "-add-inferior" FAIL: gdb.multi/multi-core-files.exp: first info inferiors call FAIL: gdb.multi/multi-core-files.exp: second info inferiors call FAIL: gdb.multi/multi-core-files.exp: info connections FAIL: gdb.multi/multi-core-files.exp: Loaded second core file FAIL: gdb.multi/multi-core-files.exp: check backtrace in inferior 2 FAIL: gdb.multi/multi-core-files.exp: Loaded first core file into inferior 3 FAIL: gdb.multi/multi-core-files.exp: check backtrace in inferior 3 FAIL: gdb.multi/multi-core-files.exp: detach from inferior 3 core file (the program is no longer running) FAIL: gdb.multi/multi-core-files.exp: detach from inferior 2 core file (the program is no longer running) FAIL: gdb.multi/multi-core-files.exp: check backtrace in inferior 1 again FAIL: gdb.multi/multi-core-files.exp: detach from inferior 1 core file (the program is no longer running) I think something like this could do: if { $corefile1 eq "" || $corefile2 eq "" } { 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 ^ Should be 2 spaces after the "."? > +# 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 non of the new inferiors have a connection. s/non/none/ > +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 non of the new inferiors have a connection. s/non/none/ Best, Lancelot. > +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" > -- > 2.25.4 >