This introduces a new function dwelf_elf_begin which creates a (read-only) ELF handle from a possibly compressed file handle or a file that start with a linux kernel header. This can be used in eu-readelf to (re)open a (pure) ELF.
eu-readelf uses libdwfl to relocate addresses in the original file in case it is ET_REL. But to show the "raw" data it might need to (re)open the file. Which could fail if the file was compressed. And produced an obscure error message: "cannot create EBL handle". It currently wraps __libdw_open_file which makes error handling slight tricky and needs duplicating the file handle. Signed-off-by: Mark Wielaard <m...@klomp.org> --- libdw/ChangeLog | 4 +++ libdw/libdw.map | 5 ++++ libdwelf/ChangeLog | 8 +++++- libdwelf/Makefile.am | 2 +- libdwelf/dwelf_elf_begin.c | 61 +++++++++++++++++++++++++++++++++++++++++ libdwelf/libdwelf.h | 10 ++++++- src/ChangeLog | 7 +++-- src/readelf.c | 8 ++++-- tests/ChangeLog | 6 ++++ tests/Makefile.am | 2 ++ tests/run-readelf-compressed.sh | 34 +++++++++++++++++++++++ 11 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 libdwelf/dwelf_elf_begin.c create mode 100755 tests/run-readelf-compressed.sh diff --git a/libdw/ChangeLog b/libdw/ChangeLog index ebe002c..e5d01c1 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,7 @@ +2018-10-20 Mark Wielaard <m...@klomp.org> + + * libdw.map (ELFUTILS_0.175): New section. Add dwelf_elf_begin. + 2018-09-13 Mark Wielaard <m...@klomp.org> * dwarf_begin_elf.c (check_section): Drop ehdr argument, add and diff --git a/libdw/libdw.map b/libdw/libdw.map index 3fef2ed..55482d5 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -356,3 +356,8 @@ ELFUTILS_0.173 { global: dwarf_next_lines; } ELFUTILS_0.171; + +ELFUTILS_0.175 { + global: + dwelf_elf_begin; +} ELFUTILS_0.173; \ No newline at end of file diff --git a/libdwelf/ChangeLog b/libdwelf/ChangeLog index a332655..d26fe32 100644 --- a/libdwelf/ChangeLog +++ b/libdwelf/ChangeLog @@ -1,4 +1,10 @@ -2015-10-11 Akihiko Odaki <akihiko.odaki...@stu.hosei.ac.jp> +2018-10-21 Mark Wielaard <m...@klomp.org> + + * libdwelf.h (dwelf_elf_begin): Add function declaration. + * dwelf_elf_begin.c: New file. + * Makefile.am (libdwelf_a_SOURCES): Add dwelf_elf_begin.c. + +2016-10-11 Akihiko Odaki <akihiko.odaki...@stu.hosei.ac.jp> * dwelf_strtab.c: Remove sys/param.h include. (MIN): Remove definition. diff --git a/libdwelf/Makefile.am b/libdwelf/Makefile.am index 7ca767a..a7933fd 100644 --- a/libdwelf/Makefile.am +++ b/libdwelf/Makefile.am @@ -41,7 +41,7 @@ noinst_HEADERS = libdwelfP.h libdwelf_a_SOURCES = dwelf_elf_gnu_debuglink.c dwelf_dwarf_gnu_debugaltlink.c \ dwelf_elf_gnu_build_id.c dwelf_scn_gnu_compressed_size.c \ - dwelf_strtab.c + dwelf_strtab.c dwelf_elf_begin.c libdwelf = $(libdw) diff --git a/libdwelf/dwelf_elf_begin.c b/libdwelf/dwelf_elf_begin.c new file mode 100644 index 0000000..43c3bc1 --- /dev/null +++ b/libdwelf/dwelf_elf_begin.c @@ -0,0 +1,61 @@ +/* Creates an ELF handle from a possibly compressed file descriptor. + Copyright (C) 2018 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 either + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at + your option) any later version + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at + your option) any later version + + or both in parallel, as here. + + 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 copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdwelfP.h" +#include "libdwflP.h" +#include "libelfP.h" + +#include <unistd.h> + +Elf * +dwelf_elf_begin (int fd) +{ + Elf *elf = NULL; + int elf_fd = dup (fd); /* __libdw_open_file will consume and close it. */ + Dwfl_Error e = __libdw_open_file (&elf_fd, &elf, true, true); + if (elf != NULL && elf_kind (elf) != ELF_K_NONE) + return elf; + + if (elf != NULL) + elf_end (elf); + + if (e != DWFL_E_LIBELF) + { + /* Force a bad ELF error. */ + char badelf[EI_NIDENT] = { }; + Elf *belf = elf_memory (badelf, EI_NIDENT); + elf32_getehdr (belf); + elf_end (belf); + } + + return NULL; +} diff --git a/libdwelf/libdwelf.h b/libdwelf/libdwelf.h index 72089db..6d49184 100644 --- a/libdwelf/libdwelf.h +++ b/libdwelf/libdwelf.h @@ -1,5 +1,5 @@ /* Interfaces for libdwelf. DWARF ELF Low-level Functions. - Copyright (C) 2014, 2015, 2016 Red Hat, Inc. + Copyright (C) 2014, 2015, 2016, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -125,6 +125,14 @@ extern const char *dwelf_strent_str (Dwelf_Strent *se) extern void dwelf_strtab_free (Dwelf_Strtab *st) __nonnull_attribute__ (1); +/* Creates a read-only Elf handle from the given file handle. The + file may be compressed and/or contain a linux kernel image header, + in which case it is eagerly decompressed in full and the Elf handle + is created as if created with elf_memory (). On error NULL is + returned. The Elf handle should be closed with elf_end (). The + file handle will not be closed. Does not return ELF_K_NONE handles. */ +extern Elf *dwelf_elf_begin (int fd); + #ifdef __cplusplus } #endif diff --git a/src/ChangeLog b/src/ChangeLog index 602312e..17d5ba6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2018-10-20 Mark Wielaard <m...@klomp.org> + + * readelf.c (process_elf_file): Use dwelf_elf_begin to open pure_elf. + 2018-10-16 Mark Wielaard <m...@klomp.org> * readelf.c (print_debug_frame_section): Make sure readp is never @@ -26,11 +30,10 @@ * findtextrel.c (process_file): Check that sh_entsize is not zero. -2018-09-13 Mark Wielaard <m...@klomp.org> +2018-10-13 Mark Wielaard <m...@klomp.org> * readelf.c (print_debug_macro_section): Use elf_getdata. Print decoded flag string. -2018-09-13 Mark Wielaard <m...@klomp.org> 2018-10-19 Mark Wielaard <m...@klomp.org> diff --git a/src/readelf.c b/src/readelf.c index dfbb3d0..c4d8aa0 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -905,7 +905,6 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) if (ehdr == NULL) { - elf_error: error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1)); return; } @@ -948,7 +947,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) { /* Read the file afresh. */ off_t aroff = elf_getaroff (elf); - pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL); + pure_elf = dwelf_elf_begin (fd); if (aroff > 0) { /* Archive member. */ @@ -958,7 +957,10 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) pure_elf = armem; } if (pure_elf == NULL) - goto elf_error; + { + error (0, 0, gettext ("cannot read ELF: %s"), elf_errmsg (-1)); + return; + } pure_ebl = ebl_openbackend (pure_elf); if (pure_ebl == NULL) goto ebl_error; diff --git a/tests/ChangeLog b/tests/ChangeLog index 751a081..e64a8b5 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2018-10-20 Mark Wielaard <m...@klomp.org> + + * run-readelf-compressed.sh: New test. + * Makefile.am (TESTS): Add run-readelf-compressed.sh. + (EXTRA_DIST): Likewise. + 2018-10-12 Mark Wielaard <m...@klomp.org> * run-readelf-zdebug.sh: Adjust flags output. diff --git a/tests/Makefile.am b/tests/Makefile.am index 15b429b..165a414 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -100,6 +100,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-find-prologues.sh run-allregs.sh run-addrcfi.sh \ run-dwarfcfi.sh \ run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \ + run-readelf-compressed.sh \ run-readelf-const-values.sh \ run-varlocs-self.sh run-exprlocs-self.sh \ run-readelf-test1.sh run-readelf-test2.sh run-readelf-test3.sh \ @@ -215,6 +216,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ run-ranlib-test3.sh run-ranlib-test4.sh \ run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \ run-nm-self.sh run-readelf-self.sh run-readelf-info-plus.sh \ + run-readelf-compressed.sh \ run-readelf-const-values.sh testfile-const-values.debug.bz2 \ run-addrcfi.sh run-dwarfcfi.sh \ testfile11-debugframe.bz2 testfile12-debugframe.bz2 \ diff --git a/tests/run-readelf-compressed.sh b/tests/run-readelf-compressed.sh new file mode 100755 index 0000000..a2a04a2 --- /dev/null +++ b/tests/run-readelf-compressed.sh @@ -0,0 +1,34 @@ +#! /bin/sh +# Copyright (C) 2018 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 + +# See run-strip-reloc.sh +testfiles hello_i386.ko + +tempfiles hello_i386.ko.bz2 readelf.out.1 readelf.out.2 + +testrun ${abs_top_builddir}/src/readelf -a hello_i386.ko > readelf.out.1 +bzip2 hello_i386.ko +testrun ${abs_top_builddir}/src/readelf -a hello_i386.ko.bz2 > readelf.out.2 + +diff -u readelf.out.1 readelf.out.2 +if [ $? != 0 ]; then + exit 1; +fi + +exit 0 -- 1.8.3.1