forked from Imagelibrary/binutils-gdb
This commit works around a problem introduced by commit:
commit e58beedf2c
Date: Tue Jan 23 16:00:59 2024 +0000
gdb: attach to a process when the executable has been deleted
The above commit extended GDB for Linux, so that, of the executable
for a process had been deleted, GDB would instead try to use
/proc/PID/exe as the executable.
This worked by updating linux_proc_pid_to_exec_file to introduce the
/proc/PID/exe fallback. However, the result of
linux_proc_pid_to_exec_file is then passed to exec_file_find to
actually find the executable, and exec_file_find, will take into
account the sysroot. In addition, if GDB is attaching to a process in
a different MNT and/or PID namespace then the executable lookup is
done within that namespace.
This all means two things:
1. Just because linux_proc_pid_to_exec_file cannot see the
executable doesn't mean that GDB is actually going to fail to
find the executable, and
2. returning /proc/PID/exe isn't useful if we know GDB is then going
to look for this within a sysroot, or within some other
namespace (where PIDs might be different).
There was an initial attempt to fix this issue here:
https://inbox.sourceware.org/gdb-patches/20250511141517.2455092-4-kilger@sec.in.tum.de/
This proposal addresses the issue in PR gdb/32955, which is all about
the namespace side of the problem. The fix in this original proposal
is to check the MNT namespace inside linux_proc_pid_to_exec_file, and
for the namespace problem this is fine. But we should also consider
the sysroot problem.
And for the sysroot problem, the fix cannot fully live inside
linux_proc_pid_to_exec_file, as linux_proc_pid_to_exec_file is shared
between GDB and gdbserver, and gdbserver has no sysroot.
And so, I propose a slightly bigger change.
Now, linux_proc_pid_to_exec_file takes a flag which indicates if
GDB (or gdbserver) will look for the inferior executable in the
local file system, where local means the same file system as GDB (or
gdbserver) is running in.
This local file system check is true if:
1. The MNT namespace of the inferior is the same as for GDB, and
2. for GDB only, the sysroot must either be empty, or 'target:'.
If the local file system check is false then GDB (or gdbserver) is
going to look elsewhere for the inferior executable, and so, falling
back to /proc/PID/exe should not be done, as GDB will end up looking
for this file in the sysroot, or within the alternative MNT
namespace (which in also likely to be a different PID namespace).
Now this is all a bit of a shame really. It would be nice if
linux_proc_pid_to_exec_file could return /proc/PID/exe in such a way
that exec_file_find would know that the file should NOT be looked for
in the sysroot, or in the alternative namespace. But fixing that
problem would be a much bigger change, so for now lets just disable
the /proc/PID/exe fallback for cases where it might not work.
For testing, the sysroot case is now tested.
I don't believe we have any alternative namespace testing. It would
certainly be interesting to add some, but I'm not proposing any with
this patch, so the code for checking the MNT namespace has been tested
manually by me, but isn't covered by a new test I'm adding here.
Author of the original fix is listed as co-author here. Credit for
identifying the original problem, and proposing a solution belongs to
them.
Co-Authored-By: Fabian Kilger <kilger@sec.in.tum.de>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32955
116 lines
4.1 KiB
Plaintext
116 lines
4.1 KiB
Plaintext
# Copyright (C) 2024-2025 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/>.
|
|
|
|
# Attach to a process, the executable for which has been deleted. On
|
|
# GNU/Linux GDB will spot the missing executable and fallback to use
|
|
# /proc/PID/exe instead.
|
|
|
|
require can_spawn_for_attach
|
|
require {istarget *-linux*}
|
|
|
|
standard_testfile
|
|
|
|
if { [build_executable "failed to prepare" $testfile $srcfile] } {
|
|
return -1
|
|
}
|
|
|
|
set test_spawn_id [spawn_wait_for_attach $binfile]
|
|
set testpid [spawn_id_get_pid $test_spawn_id]
|
|
|
|
# Move the executable rather than deleting it. This just to aid with
|
|
# debugging if someone needs to reproduce this test.
|
|
set binfile_moved ${binfile}_moved
|
|
|
|
# Don't move BINFILE as the kernel will just assign a new name to the
|
|
# same inode; and the /proc/PID/exe link will continue to point to the
|
|
# renamed inode.
|
|
remote_exec host "cp $binfile $binfile_moved"
|
|
remote_exec host "rm $binfile"
|
|
|
|
# Don't pass the executable when GDB starts. Instead rely on GDB
|
|
# finding the executable from the PID we attach too.
|
|
clean_restart
|
|
|
|
# Attach. GDB should spot that the executable is gone and fallback to
|
|
# use /proc/PID/exe.
|
|
set test "attach to process with deleted executable"
|
|
set re \
|
|
[multi_line \
|
|
"Attaching to process $decimal" \
|
|
"Reading symbols from (\[^\r\n\]+)[string_to_regexp ...]" \
|
|
".*"]
|
|
set filename ""
|
|
gdb_test_multiple "attach $testpid" $test {
|
|
-re -wrap $re {
|
|
set filename $expect_out(1,string)
|
|
pass $gdb_test_name
|
|
}
|
|
}
|
|
|
|
set test "filename /proc/PID/exe"
|
|
set re_nfs \[^\r\n\]+[string_to_regexp /.nfs]\[^\r\n\]+
|
|
if { [regexp $re_nfs $filename] } {
|
|
unsupported $test
|
|
} else {
|
|
gdb_assert { [string equal $filename /proc/${testpid}/exe] } $test
|
|
}
|
|
|
|
# Restart GDB.
|
|
clean_restart
|
|
|
|
# Setup an empty sysroot. GDB will fail to find the executable within
|
|
# the sysroot. Additionally, the presence of a sysroot should prevent
|
|
# GDB from trying to load the executable from /proc/PID/exe.
|
|
set sysroot [standard_output_file "sysroot"]
|
|
gdb_test_no_output "set sysroot $sysroot" \
|
|
"setup sysroot"
|
|
|
|
# Attach to the inferior. GDB should complain about failing to find
|
|
# the executable. It is the name of the executable that GDB doesn't
|
|
# find that we're interesting in here. For native targets GDB should
|
|
# be looking for BINFILE, not /proc/PID/exe.
|
|
#
|
|
# For extended-remote targets things are unfortunately harder. Native
|
|
# GDB looks for BINFILE because it understands that GDB will be
|
|
# looking in the sysroot. But remote GDB doesn't know if GDB is using
|
|
# a sysroot or not. As such, gdbserver will return /proc/PID/exe if
|
|
# it knows that the file has been deleted locally. This isn't great
|
|
# if GDB then plans to look in a sysroot, but equally, if the remote
|
|
# file has been deleted, then the name GDB will return, will have had
|
|
# " (deleted" appended, so we're unlikely to get a hit in the sysroot
|
|
# either way.
|
|
if { [target_info gdb_protocol] == "extended-remote" } {
|
|
set filename_re "/proc/$testpid/exe"
|
|
} else {
|
|
set filename_re "\[^\r\n\]+/${testfile} \\(deleted\\)"
|
|
}
|
|
|
|
verbose -log "APB: warning: No executable has been specified, and target executable $filename_re could not be found\\. Try using the \"file\" command\\."
|
|
|
|
gdb_test "attach $testpid" \
|
|
[multi_line \
|
|
"Attaching to process $decimal" \
|
|
"warning: No executable has been specified, and target executable $filename_re could not be found\\. Try using the \"file\" command\\." \
|
|
".*"] \
|
|
"attach to inferior"
|
|
|
|
# Check GDB hasn't managed to load an executable.
|
|
gdb_test "info inferior" \
|
|
"\\*\[^)\]+\\)\\s*" \
|
|
"confirm no executable is loaded."
|
|
|
|
# Cleanup.
|
|
kill_wait_spawned_process $test_spawn_id
|