[From nobody Fri Aug 29 20:39:05 2014 From: Jan Kratochvil <jan.kratochvil@redhat.com> Date: Sun, 17 Aug 2014 18:49:36 +0200 Subject: [PATCH] Fix resolving ELF symbols for live PIDs with deleted files For deleted shared library files the offsets to the symbol table were calculated wrongly from the phdrs because the main_bias wasn't taken into account. Formerly shared libraries did not get resolved properly: #2 0x00007fc4d86c56d6 #3 0x0000000000400938 main Fixed elfutils produce: #2 0x00007f61094876d6 libfunc #3 0x0000000000400938 main Signed-off-by: Jan Kratochvil <jan.kratochvil@redhat.com> --- libdwfl/ChangeLog | 6 +++++ libdwfl/dwfl_module_getdwarf.c | 11 +++++----- tests/ChangeLog | 9 ++++++++ tests/Makefile.am | 10 ++++++--- tests/deleted-lib.c | 27 +++++++++++++++++++++++ tests/deleted.c | 50 ++++++++++++++++++++++++++++++++++++++++++ tests/run-deleted.sh | 33 ++++++++++++++++++++++++++++ 7 files changed, 138 insertions(+), 8 deletions(-) create mode 100644 tests/deleted-lib.c create mode 100644 tests/deleted.c create mode 100755 tests/run-deleted.sh diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index c644ffe..3de772e 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,9 @@ +2014-08-28 Jan Kratochvil <jan.kratochvil@redhat.com> + + * dwfl_module_getdwarf.c (find_offsets): Add parameter main_bias, use + it. + (find_dynsym): Pass the new parameter main_bias. + 2014-08-14 Mark Wielaard <mjw@redhat.com> * linux-kernel-modules.c (check-suffix): Also TRY .ko.xz. diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 7259984..e705f57 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -621,7 +621,7 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, /* Translate addresses into file offsets. OFFS[*] start out zero and remain zero if unresolved. */ static void -find_offsets (Elf *elf, size_t phnum, size_t n, +find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, GElf_Addr addrs[n], GElf_Off offs[n]) { size_t unsolved = n; @@ -632,10 +632,10 @@ find_offsets (Elf *elf, size_t phnum, size_t n, if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0) for (size_t j = 0; j < n; ++j) if (offs[j] == 0 - && addrs[j] >= phdr->p_vaddr - && addrs[j] - phdr->p_vaddr < phdr->p_filesz) + && addrs[j] >= phdr->p_vaddr + main_bias + && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz) { - offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset; + offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset; if (--unsolved == 0) break; } @@ -720,7 +720,8 @@ find_dynsym (Dwfl_Module *mod) /* Translate pointers into file offsets. */ GElf_Off offs[i_max] = { 0, }; - find_offsets (mod->main.elf, phnum, i_max, addrs, offs); + find_offsets (mod->main.elf, mod->main_bias, phnum, i_max, addrs, + offs); /* Figure out the size of the symbol table. */ if (offs[i_hash] != 0) diff --git a/tests/ChangeLog b/tests/ChangeLog index dce6ebe..3f12728 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,12 @@ +2014-08-28 Jan Kratochvil <jan.kratochvil@redhat.com> + + * 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. + 2014-06-15 Mark Wielaard <mjw@redhat.com> * backtrace.c (frame_callback): Error on seeing more than 16 frames. diff --git a/tests/Makefile.am b/tests/Makefile.am index 4cc81c9..be3494d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -50,7 +50,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ test-elf_cntl_gelf_getshdr dwflsyms dwfllines \ dwfl-report-elf-align varlocs backtrace backtrace-child \ backtrace-data backtrace-dwarf debuglink debugaltlink \ - buildid + buildid deleted deleted-lib.so asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 @@ -109,7 +109,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-backtrace-core-s390x.sh run-backtrace-core-s390.sh \ run-backtrace-core-aarch64.sh \ run-backtrace-demangle.sh run-stack-d-test.sh run-stack-i-test.sh \ - run-readelf-dwz-multi.sh run-allfcts-multi.sh + run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -271,7 +271,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ testfile-backtrace-demangle.core.bz2 \ run-stack-d-test.sh run-stack-i-test.sh \ testfiledwarfinlines.bz2 testfiledwarfinlines.core.bz2 \ - run-readelf-zdebug.sh testfile-debug.bz2 testfile-zdebug.bz2 + run-readelf-zdebug.sh testfile-debug.bz2 testfile-zdebug.bz2 \ + run-deleted.sh if USE_VALGRIND valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no' @@ -406,6 +407,9 @@ backtrace_dwarf_LDADD = $(libdw) $(libelf) debuglink_LDADD = $(libdw) $(libelf) debugaltlink_LDADD = $(libdw) $(libelf) buildid_LDADD = $(libdw) $(libelf) +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 0000000..1ff411b --- /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 (60000); + /* 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 0000000..32a310b --- /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 0000000..b3f17ff --- /dev/null +++ b/tests/run-deleted.sh @@ -0,0 +1,33 @@ +#! /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 + +tempfiles deleted deleted-lib.so +cp -p ${abs_builddir}/deleted ${abs_builddir}/deleted-lib.so . +pid=$(testrun ${abs_builddir}/deleted) +sleep 1 +rm -f deleted deleted-lib.so +tempfiles bt +# It may have non-zero exit code with: +# .../elfutils/src/stack: dwfl_thread_getframes tid 26376 at 0x4006c8 in .../elfutils/tests/deleted: no matching address range +testrun ${abs_top_builddir}/src/stack -p $pid >bt || true +cat bt +kill -9 $pid +wait +grep -qw libfunc bt +grep -qw main bt -- 1.9.3 ]