]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdwelf: New function dwelf_elf_begin.
authorMark Wielaard <mark@klomp.org>
Sun, 21 Oct 2018 21:41:32 +0000 (23:41 +0200)
committerMark Wielaard <mark@klomp.org>
Fri, 9 Nov 2018 17:11:48 +0000 (18:11 +0100)
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>
14 files changed:
libdw/ChangeLog
libdw/libdw.map
libdwelf/ChangeLog
libdwelf/Makefile.am
libdwelf/dwelf_elf_begin.c [new file with mode: 0644]
libdwelf/libdwelf.h
libdwfl/ChangeLog
libdwfl/libdwflP.h
libdwfl/open.c
src/ChangeLog
src/readelf.c
tests/ChangeLog
tests/Makefile.am
tests/run-readelf-compressed.sh [new file with mode: 0755]

index 627fddebe2196c37adeba2ef2636d2eb4f50b38c..7caa2234e0ffce8852a9e843313d540dd90627d8 100644 (file)
@@ -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.
index 3fef2ededef8271ee08ffdd86703c4d0246a9586..55482d58792eba8bceb34ef48284e51a01081ee8 100644 (file)
@@ -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
index ba921347b46384cbaeccfbbd89ba688ff78e8517..88be3421e13f4aaaeff3886e1ad97f7dc07b695d 100644 (file)
@@ -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.
index 7ca767a9e45dac2617574a5fc6fb630c12ebdaeb..a7933fda0d950e44799558068e7a86bc1992033a 100644 (file)
@@ -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 (file)
index 0000000..7982533
--- /dev/null
@@ -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;
+}
index 72089dbfd558f66639d1b9d0e1a263b196d8f88d..6d491847114fa8fe037c0fff07eb456222e2b70b 100644 (file)
@@ -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
index 9e7bb316f34cb7c16e73f80bebbed0e823d3baa4..45cc1b4efdc255adb26e67b55d5e20e5e13a7d66 100644 (file)
@@ -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
index 31e6e19051ccfde69865abbe926b946d10a256df..941a8b669f149d872aa231cc711eca22ff74da55 100644 (file)
@@ -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)
index 4e0461bd2a9e89fae926d44195f49dca95f83789..74367359418ee33f72a3ba6f755f6d08d7fe31d9 100644 (file)
@@ -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);
+}
index 79e6872a00d0f52382326cfea0094afc6ae6a5cc..f1a35798027765e351e4ff47cd1f2ff101195f73 100644 (file)
@@ -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.
 
        * 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>
 
index ccd07eb7b7c2cff8a2195b36742b3c6c0e8c6b4d..c6c3fb323c0bc8064d54c9d47d8420f871650ef8 100644 (file)
@@ -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;
index 7ce39808d81c8877518d4dd5bb3d00cf6ab3bf80..b0da4c79c52e20ee3db57b9da1f6a281f0eb27ee 100644 (file)
@@ -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.
index d3ac345df60b8d257d971bb7ef7ab43fb831ab5c..ac467d93adc2e732a290d4babf73260b435e264b 100644 (file)
@@ -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 (executable)
index 0000000..a2a04a2
--- /dev/null
@@ -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