diff --git a/gdb/remote.c b/gdb/remote.c index 6d674c8139f..96e2750cd32 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -5636,6 +5636,15 @@ remote_unpush_target (remote_target *target) pop_all_targets_at_and_above (process_stratum); generic_mourn_inferior (); } + + /* Don't rely on target_close doing this when the target is popped + from the last remote inferior above, because something may be + holding a reference to the target higher up on the stack, meaning + target_close won't be called yet. We lost the connection to the + target, so clear these now, otherwise we may later throw + TARGET_CLOSE_ERROR while trying to tell the remote target to + close the file. */ + fileio_handles_invalidate_target (target); } static void diff --git a/gdb/target.c b/gdb/target.c index 767685fbca3..78752898191 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -3121,13 +3121,9 @@ static std::vector fileio_fhandles; list each time a new file is opened. */ static int lowest_closed_fd; -/* Invalidate the target associated with open handles that were open - on target TARG, since we're about to close (and maybe destroy) the - target. The handles remain open from the client's perspective, but - trying to do anything with them other than closing them will fail - with EIO. */ +/* See target.h. */ -static void +void fileio_handles_invalidate_target (target_ops *targ) { for (fileio_fh_t &fh : fileio_fhandles) diff --git a/gdb/target.h b/gdb/target.h index e22f9038197..ddd4f3803cb 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -2230,6 +2230,12 @@ extern LONGEST target_fileio_read_alloc (struct inferior *inf, extern gdb::unique_xmalloc_ptr target_fileio_read_stralloc (struct inferior *inf, const char *filename); +/* Invalidate the target associated with open handles that were open + on target TARG, since we're about to close (and maybe destroy) the + target. The handles remain open from the client's perspective, but + trying to do anything with them other than closing them will fail + with EIO. */ +extern void fileio_handles_invalidate_target (target_ops *targ); /* Tracepoint-related operations. */ diff --git a/gdb/testsuite/gdb.base/detach-sysroot-target.c b/gdb/testsuite/gdb.base/detach-sysroot-target.c new file mode 100644 index 00000000000..9811b15f06d --- /dev/null +++ b/gdb/testsuite/gdb.base/detach-sysroot-target.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2021 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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.base/detach-sysroot-target.exp b/gdb/testsuite/gdb.base/detach-sysroot-target.exp new file mode 100644 index 00000000000..9ae1eb6277a --- /dev/null +++ b/gdb/testsuite/gdb.base/detach-sysroot-target.exp @@ -0,0 +1,59 @@ +# Copyright 2021 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 . */ + +# Test running a program from the GDB prompt and then detaching it, +# with "set sysroot target:". Regression test for PR gdb/28080. +# +# It is assumed that it is only safe to tweak the sysroot on the +# current board if it is currently either empty or already "target:". +# If set to anything else, we skip the test. + +standard_testfile + +if {[prepare_for_testing "failed to prepare" ${binfile} ${srcfile}]} { + return +} + +gdb_test_multiple "show sysroot" "" { + -wrap -re "The current system root is \"\"\\." { + pass $gdb_test_name + + # Explicitly set target: sysroot. + gdb_test_no_output "set sysroot target:" + } + -wrap -re "The current system root is \"target:\"\\." { + pass $gdb_test_name + + # Nothing else to do. + } + -re "$gdb_prompt $" { + pass $gdb_test_name + + # If testing with any other sysroot, we probably should not + # mess with it. + unsupported "sysroot is set" + return + } +} + +if ![runto_main] { + fail "couldn't run to main" + return +} + +# With PR gdb/28080, this would crash GDB when testing with "target +# remote". +set escapedbinfile [string_to_regexp ${binfile}] +gdb_test "detach" "Detaching from program: .*$escapedbinfile, .*"