diff options
author | Jan Kratochvil <jan.kratochvil@redhat.com> | 2014-02-22 21:06:49 +0100 |
---|---|---|
committer | Jan Kratochvil <jan.kratochvil@redhat.com> | 2014-02-22 22:05:04 +0100 |
commit | 25a2c8477e8bc165a7c78719e7f0f30514abfc57 (patch) | |
tree | 620ec2a62487b104792212527395ed552f29d2e9 | |
parent | 112bcc0bebc8c3499acc67d04f292b3908e4fbcc (diff) | |
download | elfutils-25a2c8477e8bc165a7c78719e7f0f30514abfc57.tar.gz |
Access deleted files by /dev/PID/mem.jankratochvil/devmem
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>
-rw-r--r-- | libdwfl/dwfl_module.c | 11 | ||||
-rw-r--r-- | libdwfl/dwfl_module_getdwarf.c | 15 | ||||
-rw-r--r-- | libdwfl/libdwfl.h | 6 | ||||
-rw-r--r-- | libdwfl/libdwflP.h | 2 | ||||
-rw-r--r-- | libdwfl/linux-proc-maps.c | 21 | ||||
-rw-r--r-- | tests/Makefile.am | 11 | ||||
-rw-r--r-- | tests/deleted-lib.c | 27 | ||||
-rw-r--r-- | tests/deleted.c | 50 | ||||
-rwxr-xr-x | tests/run-deleted.sh | 38 |
9 files changed, 172 insertions, 9 deletions
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c index bb167ab2..6787edf0 100644 --- a/libdwfl/dwfl_module.c +++ b/libdwfl/dwfl_module.c @@ -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 diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index c4bd7395..d667513f 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -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; } diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h index 2bb4f455..cedadaef 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -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 diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 9d7157d6..f9915547 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -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 diff --git a/libdwfl/linux-proc-maps.c b/libdwfl/linux-proc-maps.c index cdb6959d..803cbdc0 100644 --- a/libdwfl/linux-proc-maps.c +++ b/libdwfl/linux-proc-maps.c @@ -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; diff --git a/tests/Makefile.am b/tests/Makefile.am index c75e7969..4e16fade 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 00000000..ce3b1daf --- /dev/null +++ b/tests/deleted-lib.c @@ -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 index 00000000..32a310b6 --- /dev/null +++ b/tests/deleted.c @@ -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 index 00000000..6deeb9bd --- /dev/null +++ b/tests/run-deleted.sh @@ -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 |