This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]