]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Access deleted files by /dev/PID/mem. jankratochvil/devmem
authorJan Kratochvil <jan.kratochvil@redhat.com>
Sat, 22 Feb 2014 20:06:49 +0000 (21:06 +0100)
committerJan Kratochvil <jan.kratochvil@redhat.com>
Sat, 22 Feb 2014 21:05:04 +0000 (22:05 +0100)
libdwfl/
2014-02-22  Jan Kratochvil  <jan.kratochvil@redhat.com>

Access deleted files by /dev/PID/mem.
* dwfl_module.c (dwfl_report_module_pid): New function.
* dwfl_module_getdwarf.c (open_elf): Call __libdw_open_file_at_offset.
* libdwfl.h (dwfl_report_module_pid): New declaration.
* libdwflP.h (struct Dwfl_Module): New field pid.
(INTDECL (dwfl_report_module_pid)): New.
* linux-proc-maps.c (proc_maps_report): New variable first_high.
(proc_maps_report) (report): Possibly call dwfl_report_module_pid.

tests/
2014-02-22  Jan Kratochvil  <jan.kratochvil@redhat.com>

Access deleted files by /dev/PID/mem.
* Makefile.am (check_PROGRAMS): Add deleted and deleted-lib.so.
(TESTS, EXTRA_DIST): Add run-deleted.sh.
(deleted_LDADD, deleted_lib_so_LDFLAGS, deleted_lib_so_CFLAGS): New.
* deleted-lib.c: New file.
* deleted.c: New file.
* run-deleted.sh: New file.

Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com>
libdwfl/dwfl_module.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/libdwfl.h
libdwfl/libdwflP.h
libdwfl/linux-proc-maps.c
tests/Makefile.am
tests/deleted-lib.c [new file with mode: 0644]
tests/deleted.c [new file with mode: 0644]
tests/run-deleted.sh [new file with mode: 0755]

index bb167ab265d91d74f4cb73e8e9ebf4bf28b702a8..6787edf04d930029475ece3d045766508f6a8cd1 100644 (file)
@@ -175,6 +175,17 @@ dwfl_report_module (Dwfl *dwfl, const char *name,
 }
 INTDEF (dwfl_report_module)
 
+Dwfl_Module *
+dwfl_report_module_pid (Dwfl *dwfl, const char *name, Dwarf_Addr start,
+                       Dwarf_Addr end, pid_t pid)
+{
+  assert (pid > 0);
+  Dwfl_Module *mod = dwfl_report_module (dwfl, name, start, end);
+  if (mod != NULL)
+    mod->pid = pid;
+  return mod;
+}
+INTDEF (dwfl_report_module_pid)
 
 /* Finish reporting the current set of modules to the library.
    If REMOVED is not null, it's called for each module that
index c4bd7395a952e43db540fa2853bbbadfa4366b5e..d667513f2322326135a2f707ad980fe68d518a23 100644 (file)
@@ -45,6 +45,16 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
         set it with an open failure below.  */
       errno = 0;
 
+      off_t start_offset = 0;
+      size_t maximum_size = ~((size_t) 0);
+      if (mod->pid != 0 && file == &mod->main)
+       {
+         if (asprintf (&file->name, "/proc/%d/mem", mod->pid) < 0)
+           return CBFAIL;
+         start_offset = mod->low_addr;
+         maximum_size = mod->high_addr - mod->low_addr;
+       }
+
       /* If there was a pre-primed file name left that the callback left
         behind, try to open that file name.  */
       if (file->fd < 0 && file->name != NULL)
@@ -53,7 +63,10 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
       if (file->fd < 0)
        return CBFAIL;
 
-      Dwfl_Error error = __libdw_open_file (&file->fd, &file->elf, true, false);
+      Dwfl_Error error = __libdw_open_file_at_offset (&file->fd, &file->elf,
+                                                     start_offset,
+                                                     maximum_size,
+                                                     true, false);
       if (error != DWFL_E_NOERROR)
        return error;
     }
index 2bb4f455af17dc05c125718123eb7655cbfe10b4..cedadaef5ab6d7ac6aa3c5fb6733f736d1e8d1e3 100644 (file)
@@ -145,6 +145,12 @@ extern int dwfl_report_segment (Dwfl *dwfl, int ndx,
 extern Dwfl_Module *dwfl_report_module (Dwfl *dwfl, const char *name,
                                        Dwarf_Addr start, Dwarf_Addr end);
 
+/* Call dwfl_report_module with support of possibly deleted files of running
+   live process with pid PID.  */
+extern Dwfl_Module *dwfl_report_module_pid (Dwfl *dwfl, const char *name,
+                                           Dwarf_Addr start, Dwarf_Addr end,
+                                           pid_t pid);
+
 /* Report a module to address BASE with start and end addresses computed
    from the ELF program headers in the given file - see the table below.
    FD may be -1 to open FILE_NAME.  On success, FD is consumed by the
index 9d7157d6483a56a9068c12638a327afc52dbced0..f9915547dd81626053cd91e0236c4919eeff8bf3 100644 (file)
@@ -158,6 +158,7 @@ struct Dwfl_Module
 
   char *name;                  /* Iterator name for this module.  */
   GElf_Addr low_addr, high_addr;
+  pid_t pid;                   /* Used for /proc/PID/mem reading.  */
 
   struct dwfl_file main, debug, aux_sym;
   GElf_Addr main_bias;
@@ -709,6 +710,7 @@ INTDECL (dwfl_getthread_frames)
 INTDECL (dwfl_getthreads)
 INTDECL (dwfl_thread_getframes)
 INTDECL (dwfl_frame_pc)
+INTDECL (dwfl_report_module_pid)
 
 /* Leading arguments standard to callbacks passed a Dwfl_Module.  */
 #define MODCB_ARGS(mod)        (mod), &(mod)->userdata, (mod)->name, (mod)->low_addr
index cdb6959db38210fdec7a62498a810f66d03f001c..803cbdc083e25734b7dad2356356e251d429f840 100644 (file)
@@ -177,14 +177,25 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
   unsigned int last_dmajor = -1, last_dminor = -1;
   uint64_t last_ino = -1;
   char *last_file = NULL;
-  Dwarf_Addr low = 0, high = 0;
+  Dwarf_Addr low = 0, high = 0, first_high = 0;
 
   inline bool report (void)
     {
       if (last_file != NULL)
        {
-         Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, last_file,
-                                                        low, high);
+         size_t last_file_len = strlen (last_file);
+         const char deleted[] = " (deleted)";
+         const size_t deleted_len = strlen (deleted);
+         Dwfl_Module *mod;
+         if (last_file_len > deleted_len
+             && strcmp (last_file + last_file_len - deleted_len, deleted) == 0)
+           {
+             last_file[last_file_len - deleted_len] = 0;
+             mod = INTUSE(dwfl_report_module_pid) (dwfl, last_file,
+                                                   low, first_high, pid);
+           }
+         else
+           mod = INTUSE(dwfl_report_module) (dwfl, last_file, low, high);
          free (last_file);
          last_file = NULL;
          if (unlikely (mod == NULL))
@@ -226,7 +237,7 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
            }
 
          low = start;
-         high = end;
+         high = first_high = end;
          if (asprintf (&last_file, "[vdso: %d]", (int) pid) < 0
              || report ())
            goto bad_report;
@@ -250,7 +261,7 @@ proc_maps_report (Dwfl *dwfl, FILE *f, GElf_Addr sysinfo_ehdr, pid_t pid)
          if (report ())
            goto bad_report;
          low = start;
-         high = end;
+         high = first_high = end;
          last_file = strdup (file);
          last_ino = ino;
          last_dmajor = dmajor;
index c75e7969fb11666c30713c0eed384db9713b8aa9..4e16fadece9eef113cbef9db860b729d9b8454a5 100644 (file)
@@ -53,7 +53,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  alldts md5-sha1-test typeiter typeiter2 low_high_pc \
                  test-elf_cntl_gelf_getshdr dwflsyms dwfllines \
                  dwfl-report-elf-align varlocs backtrace backtrace-child \
-                 backtrace-data backtrace-dwarf
+                 backtrace-data backtrace-dwarf deleted deleted-lib.so
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
            asm-tst6 asm-tst7 asm-tst8 asm-tst9
 
@@ -108,7 +108,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-backtrace-native-core-biarch.sh run-backtrace-core-x86_64.sh \
        run-backtrace-core-i386.sh run-backtrace-core-ppc.sh \
        run-backtrace-core-s390x.sh run-backtrace-core-s390.sh \
-       run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh
+       run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \
+       run-deleted.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -266,7 +267,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile-backtrace-demangle.cc \
             testfile-backtrace-demangle.core.bz2 \
             run-stack-d-test.sh run-stack-i-test.sh \
-            testfiledwarfinlines.bz2 testfiledwarfinlines.core.bz2
+            testfiledwarfinlines.bz2 testfiledwarfinlines.core.bz2 \
+            run-deleted.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
@@ -402,6 +404,9 @@ backtrace_child_biarch_SOURCES = backtrace-child.c
 backtrace_data_LDADD = $(libdw) $(libelf) $(libmudflap)
 backtrace_dwarf_CFLAGS = -Wno-unused-parameter
 backtrace_dwarf_LDADD = $(libdw) $(libelf) $(libmudflap)
+deleted_LDADD = ./deleted-lib.so
+deleted_lib_so_LDFLAGS = -shared -rdynamic
+deleted_lib_so_CFLAGS = -fPIC
 
 if GCOV
 check: check-am coverage
diff --git a/tests/deleted-lib.c b/tests/deleted-lib.c
new file mode 100644 (file)
index 0000000..ce3b1da
--- /dev/null
@@ -0,0 +1,27 @@
+/* Test program for opening already deleted running binaries.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file 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.
+
+   elfutils 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 <config.h>
+#include <unistd.h>
+
+void
+libfunc (void)
+{
+  sleep (60);
+  /* Avoid tail call optimization for the sleep call.  */
+  asm volatile ("");
+}
diff --git a/tests/deleted.c b/tests/deleted.c
new file mode 100644 (file)
index 0000000..32a310b
--- /dev/null
@@ -0,0 +1,50 @@
+/* Test program for opening already deleted running binaries.
+   Copyright (C) 2014 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file 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.
+
+   elfutils 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 <config.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdio.h>
+#include <error.h>
+#include <errno.h>
+
+extern void libfunc (void);
+
+int
+main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
+{
+  /* Set locale.  */
+  (void) setlocale (LC_ALL, "");
+
+  pid_t pid = fork ();
+  assert (pid != -1);
+  if (pid == 0)
+    {
+      int err = close (0);
+      assert (!err);
+      err = close (1);
+      assert (!err);
+      err = close (2);
+      assert (!err);
+      libfunc ();
+      abort ();
+    }
+  printf ("%d\n", pid);
+  return EXIT_SUCCESS;
+}
diff --git a/tests/run-deleted.sh b/tests/run-deleted.sh
new file mode 100755 (executable)
index 0000000..6deeb9b
--- /dev/null
@@ -0,0 +1,38 @@
+#! /bin/bash
+# Copyright (C) 2014 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file 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.
+#
+# elfutils 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/>.
+
+. $srcdir/test-subr.sh
+
+# Older Linux (such as 2.6.32) required PTRACE_ATTACH to read /proc/PID/mem.
+sleep 60 & p=$!; sleep 0.1
+addr=0x$(cat /proc/$p/maps|sed -n 's#^\([0-9a-f]*\)-[0-9a-f]* r[^ ]* 00* .*/sleep$#\1#p'|head -n1)
+supported=$[$(dd if=/proc/$p/mem bs=1 skip=$[$addr] count=1|wc -c)]
+kill -9 $p
+if [ $supported -eq 0 ]; then
+  exit 77
+fi
+
+tempfiles deleted deleted-lib.so
+cp -p ${abs_builddir}/deleted ${abs_builddir}/deleted-lib.so .
+pid=$(testrun ${abs_builddir}/deleted)
+sleep 1
+tempfiles bt
+testrun ${abs_top_builddir}/src/stack -p $pid >bt
+kill -9 $pid
+wait
+grep -w libfunc bt
+grep -w main bt