From 940515f0ba9641b9ac38d721aaac87fd898bb1fd Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Sun, 21 Oct 2018 23:41:32 +0200 Subject: [PATCH] libdwelf: New function dwelf_elf_begin. 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". This rewrites __libdw_open_file a little so that the given file handle will never be closed (whether on success or failure) and introduces a new internal function __libdw_open_elf that dwelf_elf_begin wraps. Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 4 +++ libdw/libdw.map | 5 ++++ libdwelf/ChangeLog | 8 +++++- libdwelf/Makefile.am | 2 +- libdwelf/dwelf_elf_begin.c | 62 +++++++++++++++++++++++++++++++++++++++++ libdwelf/libdwelf.h | 10 ++++++- libdwfl/ChangeLog | 8 ++++++ libdwfl/libdwflP.h | 4 +++ libdwfl/open.c | 30 ++++++++++++++------ src/ChangeLog | 7 +++-- src/readelf.c | 8 ++++-- tests/ChangeLog | 6 ++++ tests/Makefile.am | 2 ++ tests/run-readelf-compressed.sh | 34 ++++++++++++++++++++++ 14 files changed, 174 insertions(+), 16 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 + + * libdw.map (ELFUTILS_0.175): New section. Add dwelf_elf_begin. + 2018-09-13 Mark Wielaard * 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 ba92134..88be342 100644 --- a/libdwelf/ChangeLog +++ b/libdwelf/ChangeLog @@ -1,9 +1,15 @@ +2018-10-21 Mark Wielaard + + * libdwelf.h (dwelf_elf_begin): Add function declaration. + * dwelf_elf_begin.c: New file. + * Makefile.am (libdwelf_a_SOURCES): Add dwelf_elf_begin.c. + 2018-10-18 Mark Wielaard * dwelf_elf_gnu_build_id.c (find_elf_build_id): Check p_align to set ELF type. -2015-10-11 Akihiko Odaki +2016-10-11 Akihiko Odaki * 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..7982533 --- /dev/null +++ b/libdwelf/dwelf_elf_begin.c @@ -0,0 +1,62 @@ +/* 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 . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwelfP.h" +#include "libdwflP.h" +#include "libelfP.h" + +#include + +Elf * +dwelf_elf_begin (int fd) +{ + Elf *elf = NULL; + Dwfl_Error e = __libdw_open_elf (fd, &elf); + if (elf != NULL && elf_kind (elf) != ELF_K_NONE) + return elf; + + /* Elf wasn't usable. Make sure there is a proper elf error message. */ + + 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/libdwfl/ChangeLog b/libdwfl/ChangeLog index 9e7bb31..45cc1b4 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,11 @@ +2018-10-20 Mark Wielaard + + * libdwflP.h (__libdw_open_elf): New internal function declaration. + * open.c (what_kind): Rename close_fd to may_close_fd. + (__libdw_open_file): Replaced (and renamed) by a call to ... + (libdw_open_elf): this. And add never_close_fd argument. + (__libdw_open_elf): New function that calls libdw_open_elf. + 2018-10-18 Mark Wielaard * dwfl_segment_report_module.c (consider_note): Take align as new diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 31e6e19..941a8b6 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -626,6 +626,10 @@ extern Dwfl_Error __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) internal_function; +/* Same as __libdw_open_file, but never closes the given file + descriptor and ELF_K_AR is always an acceptable type. */ +extern Dwfl_Error __libdw_open_elf (int fd, Elf **elfp) internal_function; + /* Fetch PT_DYNAMIC P_VADDR from ELF and store it to *VADDRP. Return success. *VADDRP is not modified if the function fails. */ extern bool __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp) diff --git a/libdwfl/open.c b/libdwfl/open.c index 4e0461b..7436735 100644 --- a/libdwfl/open.c +++ b/libdwfl/open.c @@ -95,7 +95,7 @@ decompress (int fd __attribute__ ((unused)), Elf **elf) } static Dwfl_Error -what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd) +what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *may_close_fd) { Dwfl_Error error = DWFL_E_NOERROR; *kind = elf_kind (*elfp); @@ -108,7 +108,7 @@ what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd) error = decompress (fd, elfp); if (error == DWFL_E_NOERROR) { - *close_fd = true; + *may_close_fd = true; *kind = elf_kind (*elfp); } } @@ -116,15 +116,16 @@ what_kind (int fd, Elf **elfp, Elf_Kind *kind, bool *close_fd) return error; } -Dwfl_Error internal_function -__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) +static Dwfl_Error +libdw_open_elf (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok, + bool never_close_fd) { - bool close_fd = false; + bool may_close_fd = false; Elf *elf = elf_begin (*fdp, ELF_C_READ_MMAP_PRIVATE, NULL); Elf_Kind kind; - Dwfl_Error error = what_kind (*fdp, &elf, &kind, &close_fd); + Dwfl_Error error = what_kind (*fdp, &elf, &kind, &may_close_fd); if (error == DWFL_E_BADELF) { /* It's not an ELF file or a compressed file. @@ -153,7 +154,7 @@ __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) elf->flags &= ~(ELF_F_MMAPPED | ELF_F_MALLOCED); elf_end (elf); elf = subelf; - error = what_kind (*fdp, &elf, &kind, &close_fd); + error = what_kind (*fdp, &elf, &kind, &may_close_fd); } } } @@ -169,7 +170,8 @@ __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) elf = NULL; } - if (error == DWFL_E_NOERROR ? close_fd : close_on_fail) + if (! never_close_fd + && error == DWFL_E_NOERROR ? may_close_fd : close_on_fail) { close (*fdp); *fdp = -1; @@ -178,3 +180,15 @@ __libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) *elfp = elf; return error; } + +Dwfl_Error internal_function +__libdw_open_file (int *fdp, Elf **elfp, bool close_on_fail, bool archive_ok) +{ + return libdw_open_elf (fdp, elfp, close_on_fail, archive_ok, false); +} + +Dwfl_Error internal_function +__libdw_open_elf (int fd, Elf **elfp) +{ + return libdw_open_elf (&fd, elfp, false, true, true); +} diff --git a/src/ChangeLog b/src/ChangeLog index ca1533d..0d8b457 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2018-10-20 Mark Wielaard + + * readelf.c (process_elf_file): Use dwelf_elf_begin to open pure_elf. + 2018-11-02 Mark Wielaard * unstrip.c (copy_elf): Add ELF_CHECK to make sure gelf_getehdr () @@ -64,11 +68,10 @@ * findtextrel.c (process_file): Check that sh_entsize is not zero. -2018-09-13 Mark Wielaard +2018-10-13 Mark Wielaard * readelf.c (print_debug_macro_section): Use elf_getdata. Print decoded flag string. -2018-09-13 Mark Wielaard 2018-10-19 Mark Wielaard diff --git a/src/readelf.c b/src/readelf.c index ccd07eb..c6c3fb3 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 d5a0656..ae8587d 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2018-10-20 Mark Wielaard + + * run-readelf-compressed.sh: New test. + * Makefile.am (TESTS): Add run-readelf-compressed.sh. + (EXTRA_DIST): Likewise. + 2018-10-18 Mark Wielaard * run-readelf-n.sh: New test. diff --git a/tests/Makefile.am b/tests/Makefile.am index a2a381a..5627cf9 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 \ @@ -216,6 +217,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 . + +. $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