This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[patch] Attach to running but deleted executable
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Sun, 28 Mar 2010 20:35:30 +0200
- Subject: [patch] Attach to running but deleted executable
Hi,
it is just an easy-fix small pain lasting some years, not a big problem:
prelink -u /bin/sleep; sleep 1h& p=$!; sleep 1; ls -l /proc/$p/exe; ls -Lli /proc/$p/exe; prelink -R /bin/sleep; ls -l /proc/$p/exe; ls -Lli /proc/$p/exe; ./gdb -q -nx -p $p -ex bt
produces:
[1] 4895
lrwxrwxrwx 1 root root 0 2010-03-28 19:34 /proc/4895/exe -> /bin/sleep*
41619 -rwxr-xr-x 1 root root 24952 2010-01-12 15:35 /proc/4895/exe*
lrwxrwxrwx 1 root root 0 2010-03-28 19:34 /proc/4895/exe -> /bin/sleep\ (deleted)
41619 -rwxr-xr-x 0 root root 24952 2010-01-12 15:35 /proc/4895/exe*
With patched GDB && with /usr/lib/debug/.build-id/:
Attaching to process 4895
Reading symbols from /proc/4895/exe...Reading symbols from /usr/lib/debug/bin/sleep.debug...done.
done.
Reading symbols from /lib64/librt.so.1...Reading symbols from /usr/lib/debug/lib64/librt-2.11.1.so.debug...done.
done.
Loaded symbols for /lib64/librt.so.1
...
0x000000324e4a4d00 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
82 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
#0 0x000000324e4a4d00 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x0000000000403d9b in rpl_nanosleep (requested_delay=0x7fffc10934a0, remaining_delay=0x0)
at nanosleep.c:69
#2 0x000000000040343b in xnanosleep (seconds=<value optimized out>) at xnanosleep.c:112
#3 0x00000000004016fc in main (argc=2, argv=<value optimized out>) at sleep.c:147
With patched GDB && without /usr/lib/debug/.build-id/:
Attaching to process 4949
Reading symbols from /proc/4949/exe...(no debugging symbols found)...done.
Reading symbols from /lib64/librt.so.1...Reading symbols from /usr/lib/debug/lib64/librt-2.11.1.so.debug...done.
done.
Loaded symbols for /lib64/librt.so.1
...
0x000000324e4a4d00 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
82 T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
#0 0x000000324e4a4d00 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:82
#1 0x0000000000403d9b in ?? ()
#2 0x000000000040343b in ?? ()
#3 0x00000000004016fc in ?? ()
#4 0x000000324e41eb1d in __libc_start_main (main=<value optimized out>, argc=<value optimized out>,
ubp_av=<value optimized out>, init=<value optimized out>, fini=<value optimized out>,
rtld_fini=<value optimized out>, stack_end=<value optimized out>) at libc-start.c:226
#5 0x0000000000401289 in ?? ()
...
With unpatched GDB:
Attaching to process 6818
/bin/sleep (deleted): No such file or directory.
#0 0x4e4a4d00 in ?? ()
(I wrote this patch just without thinking out the text below first.)
It is questionable whether GDB should try to load the separate debug info file
even when no build-id is present. It could either:
(a) Currently chosen - load "/proc/PID/exe" as both exec_bfd and
symfile_objfile. Solution does not see a difference between the binary
changed by prelink or by an upgrade. If it has split debug info then:
* If build-id is present, load even the separate debug info file.
Backtrace works.
[ It works for the prelink change but currently on Fedora not for the
upgrade case. The older debuginfo file would no longer be installed
and/as there is no way to install debuginfo for multiple versions of
the same package. But that is a Fedora release engineering problem
outside of the scope of GDB and GDB supports such case. ]
* If build-id is not present GDB fails to load the separate debug info.
(b) Just remove " (deleted)" and load the different binary "/bin/sleep".
* If the file was changed by prelink: It would work.
* If the file was changed by upgrade: Backtrace will not work due to the
different both the binary and both the separate debug info file, neither
with nor without build-id present.
(c) Deal with two names - "/proc/PID/exe" for loading and "/bin/sleep" for
searching separate debug info. target_pid_to_exec_file would need to be
changed.
* If the file was changed by prelink: It would work.
* If the file was changed by upgrade:
* If build-id is present: It is exactly the (a) case with no difference.
* If build-id is not present: Backtrace will not work. While the binary
will be right the separate debug info file from "/bin/sleep" will be
the upgraded one and there is no way how to find the old separate
debug info.
| build-id is present | build-id is not present |
| prelink | upgrade | prelink | upgrade |
(a) | pass | pass | fail | fail |
(b) | pass | fail | pass | fail |
(c) | pass | pass | pass | fail |
(a) = simple, preferring build-id systems
(b) = simple, preferring non build-id systems
(c) = complicated with pros of (a) & (b) and no cons of (a) & (b)
Understandably I have implemented (a). :-)
Another problem is with libraries upgraded / prelinked underneath but there is
AFAIK no way how to open their already unlinked file (as required for (a)+(c)).
No regressions on {x86_64,x86_64-m32,i686}-fedora12-linux-gnu.
OK to check-in? There are some unrelated cleanups (I will split it if it is
not a clear approval). I have seen in none of man pages, POSIX, Linux kernel
source VFS that readlink would guarantee '\0'-terminated result for the
MAXPATHLEN length.
Thanks,
Jan
gdb/
2010-03-28 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix attaching to running and deleted executables on GNU/Linux.
* linux-nat.c (linux_child_pid_to_exec_file): New variables deleted,
deleted_len and len. Reduce allocation of name1. Remove memset of
name2. Call readlink with one byte smaller size. Call gdb_assert on
returned length. Terminate returned string by explicit single zero.
Return unresolved link for " (deleted)" resolved filenames.
* target.h (target_pid_to_exec_file): Extend comment wrt a cleanup.
gdb/testsuite/
2010-03-28 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix attaching to running and deleted executables on GNU/Linux.
* gdb.base/attach-deleted.exp, gdb.base/attach-deleted.c: New.
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -4002,16 +4002,28 @@ static char *
linux_child_pid_to_exec_file (int pid)
{
char *name1, *name2;
+ const char deleted[] = " (deleted)";
+ size_t deleted_len = strlen (deleted);
+ ssize_t len;
- name1 = xmalloc (MAXPATHLEN);
+ name1 = xmalloc (32);
name2 = xmalloc (MAXPATHLEN);
make_cleanup (xfree, name1);
make_cleanup (xfree, name2);
- memset (name2, 0, MAXPATHLEN);
sprintf (name1, "/proc/%d/exe", pid);
- if (readlink (name1, name2, MAXPATHLEN) > 0)
- return name2;
+ len = readlink (name1, name2, MAXPATHLEN - 1);
+ if (len > 0)
+ {
+ gdb_assert (len < MAXPATHLEN);
+ name2[len] = 0;
+ if (len > deleted_len && strcmp (deleted, &name2[len - deleted_len]) == 0)
+ {
+ /* Unlinked executables are still readable by their /proc/PID/exe. */
+ return name1;
+ }
+ return name2;
+ }
else
return name1;
}
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -1204,7 +1204,7 @@ extern char *normal_pid_to_str (ptid_t ptid);
Else, a pointer to a character string containing the pathname
is returned. This string should be copied into a buffer by
the client if the string will not be immediately used, or if
- it must persist. */
+ it must persist as it may be registered for xfree on the cleanup stack. */
#define target_pid_to_exec_file(pid) \
(current_target.to_pid_to_exec_file) (pid)
--- /dev/null
+++ b/gdb/testsuite/gdb.base/attach-deleted.c
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2010 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/>. */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main (int argc, char **argv)
+{
+ puts ("sleeping");
+ fflush (stdout);
+
+ return sleep (60);
+}
--- /dev/null
+++ b/gdb/testsuite/gdb.base/attach-deleted.exp
@@ -0,0 +1,69 @@
+# Copyright 2010 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/>.
+
+if [is_remote host] {
+ continue
+}
+
+set test "attach-deleted"
+set srcfile ${test}.c
+set executable ${test}
+set binfile ${objdir}/${subdir}/${executable}
+
+if {[build_executable ${test}.exp $executable $srcfile] == -1} {
+ return -1
+}
+
+set test "start inferior"
+gdb_exit
+
+set res [remote_spawn host $binfile];
+if { $res < 0 || $res == "" } {
+ perror "Spawning $binfile failed."
+ fail $test
+ return
+}
+set pid [exp_pid -i $res]
+gdb_expect {
+ -re "sleeping\r\n" {
+ pass $test
+ }
+ eof {
+ fail "$test (eof)"
+ remote_exec host "kill -9 $pid"
+ return
+ }
+ timeout {
+ fail "$test (timeout)"
+ remote_exec host "kill -9 $pid"
+ return
+ }
+}
+
+file delete $binfile
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+gdb_test "attach $pid" "Attaching to process $pid\r\nReading symbols from .*" "attach"
+
+if [istarget *-linux*] {
+ gdb_test "info files" "Symbols from \"/proc/\[0-9\]+/exe\"\\.\r\n.*"
+}
+
+gdb_test "detach" "Detaching from program: .*"
+
+remote_exec host "kill -9 $pid"