diff options
author | Mark Wielaard <mark@klomp.org> | 2018-10-21 23:41:32 +0200 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2018-11-09 18:11:48 +0100 |
commit | ecbe3120cddb1b9597a19a68c4265e4f2c530444 (patch) | |
tree | 40f6549cda3aa5bff3df983f15ac88d0da597b72 | |
parent | 4b0342b85b5b1a3d3636e06e3b5320954828dfb1 (diff) |
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 <mark@klomp.org>
-rw-r--r-- | libdw/ChangeLog | 4 | ||||
-rw-r--r-- | libdw/libdw.map | 5 | ||||
-rw-r--r-- | libdwelf/ChangeLog | 8 | ||||
-rw-r--r-- | libdwelf/Makefile.am | 2 | ||||
-rw-r--r-- | libdwelf/dwelf_elf_begin.c | 62 | ||||
-rw-r--r-- | libdwelf/libdwelf.h | 10 | ||||
-rw-r--r-- | libdwfl/ChangeLog | 8 | ||||
-rw-r--r-- | libdwfl/libdwflP.h | 4 | ||||
-rw-r--r-- | libdwfl/open.c | 30 | ||||
-rw-r--r-- | src/ChangeLog | 7 | ||||
-rw-r--r-- | src/readelf.c | 8 | ||||
-rw-r--r-- | tests/ChangeLog | 6 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rwxr-xr-x | tests/run-readelf-compressed.sh | 34 |
14 files changed, 174 insertions, 16 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 627fddeb..7caa2234 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,7 @@ +2018-10-20 Mark Wielaard <mark@klomp.org> + + * libdw.map (ELFUTILS_0.175): New section. Add dwelf_elf_begin. + 2018-10-29 Milian Wolff <milian.wolff@kdab.com> * dwarf_getcfi_elf.c (getcfi_shdr): Check sh_type != SHT_NOBITS. diff --git a/libdw/libdw.map b/libdw/libdw.map index 3fef2ede..55482d58 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 ba921347..88be3421 100644 --- a/libdwelf/ChangeLog +++ b/libdwelf/ChangeLog @@ -1,9 +1,15 @@ +2018-10-21 Mark Wielaard <mark@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. + 2018-10-18 Mark Wielaard <mark@klomp.org> * dwelf_elf_gnu_build_id.c (find_elf_build_id): Check p_align to set ELF type. -2015-10-11 Akihiko Odaki <akihiko.odaki.4i@stu.hosei.ac.jp> +2016-10-11 Akihiko Odaki <akihiko.odaki.4i@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 7ca767a9..a7933fda 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 00000000..79825338 --- /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 <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; + 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 72089dbf..6d491847 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 9e7bb316..45cc1b4e 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,11 @@ +2018-10-20 Mark Wielaard <mark@klomp.org> + + * 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 <mark@klomp.org> * dwfl_segment_report_module.c (consider_note): Take align as new diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 31e6e190..941a8b66 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 4e0461bd..74367359 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 79e6872a..f1a35798 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2018-10-20 Mark Wielaard <mark@klomp.org> + + * readelf.c (process_elf_file): Use dwelf_elf_begin to open pure_elf. + 2018-10-26 Mark Wielaard <mark@klomp.org> * strip.c (OPT_RELOC_DEBUG_ONLY): New define. @@ -93,11 +97,10 @@ * findtextrel.c (process_file): Check that sh_entsize is not zero. -2018-09-13 Mark Wielaard <mark@klomp.org> +2018-10-13 Mark Wielaard <mark@klomp.org> * readelf.c (print_debug_macro_section): Use elf_getdata. Print decoded flag string. -2018-09-13 Mark Wielaard <mark@klomp.org> 2018-10-19 Mark Wielaard <mark@klomp.org> diff --git a/src/readelf.c b/src/readelf.c index ccd07eb7..c6c3fb32 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 7ce39808..b0da4c79 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,9 @@ +2018-10-20 Mark Wielaard <mark@klomp.org> + + * run-readelf-compressed.sh: New test. + * Makefile.am (TESTS): Add run-readelf-compressed.sh. + (EXTRA_DIST): Likewise. + 2018-11-09 Mark Wielaard <mark@klomp.org> * testfile-debug-rel-ppc64-g.o.bz2: New test file. diff --git a/tests/Makefile.am b/tests/Makefile.am index d3ac345d..ac467d93 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 00000000..a2a04a2a --- /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 |