diff --git a/gdb/symfile.c b/gdb/symfile.c index 30147b7c3df..584a62cd1d6 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -2475,20 +2475,32 @@ reread_symbols (int from_tty) if (objfile->separate_debug_objfile_backlink) continue; - /* If this object is from an archive (what you usually create with - `ar', often called a `static library' on most systems, though - a `shared library' on AIX is also an archive), then you should - stat on the archive name, not member name. */ - const char *filename; - if (objfile->obfd->my_archive) - filename = bfd_get_filename (objfile->obfd->my_archive); - else - filename = objfile_name (objfile); + /* When a in-memory BFD is initially created, it's mtime (as + returned by bfd_get_mtime) is the creation time of the BFD. + However, we call bfd_stat here as we want to see if the + underlying file has changed, and in this case an in-memory BFD + will return an st_mtime of zero, so it appears that the in-memory + file has changed, which isn't what we want here -- this code is + about reloading BFDs that changed on disk. + + Just skip any in-memory BFD. */ + if (objfile->obfd.get ()->flags & BFD_IN_MEMORY) + continue; struct stat new_statbuf; - int res = stat (filename, &new_statbuf); + int res = bfd_stat (objfile->obfd.get (), &new_statbuf); if (res != 0) { + /* If this object is from an archive (what you usually create + with `ar', often called a `static library' on most systems, + though a `shared library' on AIX is also an archive), then you + should stat on the archive name, not member name. */ + const char *filename; + if (objfile->obfd->my_archive) + filename = bfd_get_filename (objfile->obfd->my_archive); + else + filename = objfile_name (objfile); + warning (_("`%ps' has disappeared; keeping its symbols."), styled_string (file_name_style.style (), filename)); continue; diff --git a/gdb/testsuite/gdb.server/target-exec-file.c b/gdb/testsuite/gdb.server/target-exec-file.c new file mode 100644 index 00000000000..3a264f239ed --- /dev/null +++ b/gdb/testsuite/gdb.server/target-exec-file.c @@ -0,0 +1,22 @@ +/* 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 . */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.server/target-exec-file.exp b/gdb/testsuite/gdb.server/target-exec-file.exp new file mode 100644 index 00000000000..9260df8b88d --- /dev/null +++ b/gdb/testsuite/gdb.server/target-exec-file.exp @@ -0,0 +1,174 @@ +# 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 . + +# Test GDB's handling of using a file with a 'target:' prefix as the +# executable file. This test includes checking what happens when the +# file on the target system changes and GDB needs to reload it. + +load_lib gdbserver-support.exp + +require allow_gdbserver_tests !use_gdb_stub + +standard_testfile + +if { [build_executable "failed to prepare" $testfile $srcfile debug] } { + return -1 +} + +clean_restart + +# Some boards specifically set the sysroot to the empty string to +# avoid copying files from the target. But for this test we do want +# to copy files from the target, so set the sysroot back to 'target:'. +# +# This is fine so long as we're not using a board file that sets the +# sysroot to something else -- but none of the standard boards do +# this, and plenty of other tests mess with the sysroot, so I guess we +# don't worry about that too much. +gdb_test "set sysroot target:" ".*" + +# Make sure we're disconnected, in case we're testing with an +# extended-remote board, therefore already connected. +gdb_test "disconnect" ".*" + +# Ensure the executable is on the target. +set target_exec [gdb_remote_download target $binfile] + +# We're going to be restarting the inferior. Lets ask GDB not to +# prompt us if this is the right thing to do. +gdb_test_no_output "set confirm off" + +# Start gdbserver, but always in extended-remote mode, and then +# connect to it from GDB. +set res [gdbserver_start "--multi" $target_exec] +set gdbserver_protocol "extended-remote" +set gdbserver_gdbport [lindex $res 1] +gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport + +# Issue a 'file' command and parse the output. We look for a couple +# of specific things to ensure that we are correctly reading the exec +# from the remote target. +set saw_read_of_remote_exec false +set saw_read_of_syms_from_exec false +gdb_test_multiple "file target:$target_exec" "run file command" { + -re "^file target:\[^\r\n\]+\r\n" { + exp_continue + } + + -re "^Reading (\[^\r\n\]+) from remote target\\.\\.\\.\r\n" { + set filename $expect_out(1,string) + if { $filename eq $target_exec } { + set saw_read_of_remote_exec true + } + exp_continue + } + + -re "^warning: File transfers from remote targets can be slow\[^\r\n\]+\r\n" { + exp_continue + } + + -re "^Reading symbols from target:(\[^\r\n\]+)\\.\\.\\.\r\n" { + set filename $expect_out(1,string) + if { $filename eq $target_exec } { + set saw_read_of_syms_from_exec true + } + exp_continue + } + + -re "^Expanding full symbols from \[^\r\n\]+\r\n" { + exp_continue + } + + -re "^$gdb_prompt $" { + pass $gdb_test_name + } +} + +gdb_assert { $saw_read_of_remote_exec } \ + "exec was read from the remote target" + +gdb_assert { $saw_read_of_syms_from_exec } \ + "symbols were read from remote exec file" + +# Start the inferior (with the 'start' command), use TESTNAME for any +# pass/fail calls. EXPECT_REREAD should be true or false and +# indicates if we expect to too a line like: +# +# `FILE' has changed; re-reading symbols. +proc start_inferior { testname expect_reread } { + with_test_prefix $testname { + if { [gdb_start_cmd] < 0 } { + fail "start command" + return -1 + } + + set saw_reread false + gdb_test_multiple "" "stopped at main" { + -re "^start\\s*\r\n" { + exp_continue + } + -re "^`\[^\r\n\]+' has changed; re-reading symbols\\.\r\n" { + set saw_reread true + exp_continue + } + -re "^Reading \[^\r\n\]+ from remote target\\.\\.\\.\r\n" { + exp_continue + } + -re "^Expanding full symbols from \[^\r\n\]+\\.\\.\\.\r\n" { + exp_continue + } + -re "^Temporary breakpoint $::decimal at $::hex: \[^\r\n\]+\r\n" { + exp_continue + } + -re "^Starting program: \[^\r\n\]+\r\n" { + exp_continue + } + -re "^\\s*\r\n" { + exp_continue + } + -re "^Temporary breakpoint $::decimal, main \\(\\) at .*$::gdb_prompt $" { + pass $testname + } + } + + gdb_assert { $expect_reread == $saw_reread } \ + "check symbol re-read behaviour" + } +} + +# Start the inferior for the first time. The symbols were already +# read from the file when the 'file' command was used, we should not +# see the symbols re-read now. +start_inferior "start inferior the first time" false + +# Re-start the inferior. The executable is unchanged so we should not +# see the symbol file being re-read. +start_inferior "start inferior a second time" false + +# Delay for a short while so, when we touch the exec, we know the +# timestamp will change. +sleep 1 +set res [remote_exec target "touch $target_exec"] +set status [lindex $res 0] +if { $status != 0 } { + fail "touching executable on target" + return -1 +} + +# Start the inferior again, we expect to see the symbols being re-read +# from the remote file. +start_inferior "start inferior a third time" true