]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Add beginning of objdump program.
authorUlrich Drepper <drepper@redhat.com>
Wed, 3 Aug 2005 02:24:12 +0000 (02:24 +0000)
committerUlrich Drepper <drepper@redhat.com>
Wed, 3 Aug 2005 02:24:12 +0000 (02:24 +0000)
NEWS
src/ChangeLog
src/Makefile.am
src/objdump.c [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 28d6815945c81d909fd84bcec763568f4520247d..5e206a1ce502dc74e51cf29673f241352fdd3cf7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,8 @@ libasm: asm_begin interface changes.
 libebl: Add three new interfaces to directly access machine, class, and
 data encoding information.
 
+objdump: New program.  Just the beginning.
+
 Version 0.111:
 
 libdw: now contains all of libdwfl.  The latter is not installed anymore.
index b3a9787e809a9b8f05482c58703d0ecc5fbcd2fd..9ded08982c95f62ba45737d6f2346c4093b66fe3 100644 (file)
@@ -1,5 +1,9 @@
 2005-08-02  Ulrich Drepper  <drepper@redhat.com>
 
+       * objdump.c: New file.
+       * Makefile.am (bin_PROGRAMS): Add objdump.
+       (objdump_LDADD): Define.
+
        * elflint.c (check_reloc_shdr): New function split out from check_rela
        and check_rel.
        (check_one_reloc): New function.  Likewise.
index ccb6f96cf01064a5c9f899a3c725e0045e47f9c1..5229dce3270a28f9862581e72f440783d434e546 100644 (file)
@@ -39,7 +39,7 @@ native_ld = @native_ld@
 base_cpu = @base_cpu@
 
 bin_PROGRAMS = readelf nm size strip ld elflint findtextrel addr2line \
-              elfcmp
+              elfcmp objdump
 
 
 ld_dsos = libld_elf_i386_pic.a
@@ -91,6 +91,7 @@ elflint_LDADD  = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
 findtextrel_LDADD = $(libdw) $(libelf) $(libmudflap)
 addr2line_LDADD = $(libdw) $(libelf) $(libmudflap)
 elfcmp_LDADD = $(libebl) $(libelf) $(libmudflap) -ldl
+objdump_LDADD  = $(libebl) $(libelf) $(libeu) $(libmudflap) -ldl
 
 ldlex.o: ldscript.c
 ldlex_no_Werror = yes
diff --git a/src/objdump.c b/src/objdump.c
new file mode 100644 (file)
index 0000000..e571171
--- /dev/null
@@ -0,0 +1,725 @@
+/* Print information from ELF file in human-readable form.
+   Copyright (C) 2005 Red Hat, Inc.
+   Written by Ulrich Drepper <drepper@redhat.com>, 2005.
+
+   This program is Open Source software; you can redistribute it and/or
+   modify it under the terms of the Open Software License version 1.0 as
+   published by the Open Source Initiative.
+
+   You should have received a copy of the Open Software License along
+   with this program; if not, you may obtain a copy of the Open Software
+   License version 1.0 from http://www.opensource.org/licenses/osl.php or
+   by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
+   3001 King Ranch Road, Ukiah, CA 95482.   */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <argp.h>
+#include <error.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <locale.h>
+#include <mcheck.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdio_ext.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include <system.h>
+#include "../libebl/libeblP.h"
+
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Bug report address.  */
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+
+
+/* Definitions of arguments for argp functions.  */
+static const struct argp_option options[] =
+{
+  { NULL, 0, NULL, 0, N_("Mode selection:"), 0 },
+  { "reloc", 'r', NULL, 0, N_("Display relocation information."), 0 },
+  { "full-contents", 's', NULL, 0,
+    N_("Display the full contents of all sections requested"), 0 },
+  { "disassemble", 'd', NULL, 0,
+    N_("Display assembler code of executable sections"), 0 },
+
+  { NULL, 0, NULL, 0, N_("Output option selection:"), 0 },
+  { "section", 'j', "NAME", 0,
+    N_("Only display information for section NAME."), 0 },
+
+  { NULL, 0, NULL, 0, NULL, 0 }
+};
+
+/* Short description of program.  */
+static const char doc[] = N_("\
+Show information from FILEs (a.out by default).");
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = N_("[FILE...]");
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, NULL, NULL
+};
+
+
+/* Print symbols in file named FNAME.  */
+static int process_file (const char *fname, bool more_than_one);
+
+/* Handle content of archive.  */
+static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
+                     const char *suffix);
+
+/* Handle ELF file.  */
+static int handle_elf (Elf *elf, const char *prefix, const char *fname,
+                      const char *suffix);
+
+
+#define INTERNAL_ERROR(fname) \
+  error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"),      \
+        fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1))
+
+
+/* List of sections which should be used.  */
+static struct section_list
+{
+  bool is_name;
+  union
+  {
+    const char *name;
+    uint32_t scnndx;
+  };
+  struct section_list *next;
+} *section_list;
+
+
+/* If true print archive index.  */
+static bool print_relocs;
+
+/* If true print full contents of requested sections.  */
+static bool print_full_content;
+
+/* If true print disassembled output..  */
+static bool print_disasm;
+
+int
+main (int argc, char *argv[])
+{
+  /* Make memory leak detection possible.  */
+  mtrace ();
+
+  /* We use no threads here which can interfere with handling a stream.  */
+  (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
+  (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
+  (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
+
+  /* Set locale.  */
+  (void) setlocale (LC_ALL, "");
+
+  /* Make sure the message catalog can be found.  */
+  (void) bindtextdomain (PACKAGE, LOCALEDIR);
+
+  /* Initialize the message catalog.  */
+  (void) textdomain (PACKAGE);
+
+  /* Parse and process arguments.  */
+  int remaining;
+  (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  /* Tell the library which version we are expecting.  */
+  (void) elf_version (EV_CURRENT);
+
+  int result = 0;
+  if (remaining == argc)
+    /* The user didn't specify a name so we use a.out.  */
+    result = process_file ("a.out", false);
+  else
+    {
+      /* Process all the remaining files.  */
+      const bool more_than_one = remaining + 1 < argc;
+
+      do
+       result |= process_file (argv[remaining], more_than_one);
+      while (++remaining < argc);
+    }
+
+  return result;
+}
+
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
+{
+  fprintf (stream, "objdump (%s) %s\n", PACKAGE_NAME, VERSION);
+  fprintf (stream, gettext ("\
+Copyright (C) %s Red Hat, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2005");
+  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg,
+          struct argp_state *state __attribute__ ((unused)))
+{
+  /* True if any of the control options is set.  */
+  static bool any_control_option;
+
+  switch (key)
+    {
+    case 'j':
+      {
+       struct section_list *newp = xmalloc (sizeof (*newp));
+       char *endp;
+       newp->scnndx = strtoul (arg, &endp, 0);
+       if (*endp == 0)
+         newp->is_name = false;
+       else
+         {
+           newp->name = arg;
+           newp->is_name = true;
+         }
+       newp->next = section_list;
+       section_list = newp;
+      }
+      any_control_option = true;
+      break;
+
+    case 'd':
+      print_disasm = true;
+      any_control_option = true;
+      break;
+
+    case 'r':
+      print_relocs = true;
+      any_control_option = true;
+      break;
+
+    case 's':
+      print_full_content = true;
+      any_control_option = true;
+      break;
+
+    case ARGP_KEY_FINI:
+      if (! any_control_option)
+       {
+         fputs (gettext ("No operation specified.\n"), stderr);
+         argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
+                    program_invocation_short_name);
+         exit (1);
+       }
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+
+/* Open the file and determine the type.  */
+static int
+process_file (const char *fname, bool more_than_one)
+{
+  /* Open the file.  */
+  int fd = open (fname, O_RDONLY);
+  if (fd == -1)
+    {
+      error (0, errno, gettext ("cannot open %s"), fname);
+      return 1;
+    }
+
+  /* Now get the ELF descriptor.  */
+  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+  if (elf != NULL)
+    {
+      if (elf_kind (elf) == ELF_K_ELF)
+       {
+         int result = handle_elf (elf, more_than_one ? "" : NULL,
+                                  fname, NULL);
+
+         if (elf_end (elf) != 0)
+           INTERNAL_ERROR (fname);
+
+         if (close (fd) != 0)
+           error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
+
+         return result;
+       }
+      else if (elf_kind (elf) == ELF_K_AR)
+       {
+         int result = handle_ar (fd, elf, NULL, fname, NULL);
+
+         if (elf_end (elf) != 0)
+           INTERNAL_ERROR (fname);
+
+         if (close (fd) != 0)
+           error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
+
+         return result;
+       }
+
+      /* We cannot handle this type.  Close the descriptor anyway.  */
+      if (elf_end (elf) != 0)
+       INTERNAL_ERROR (fname);
+    }
+
+  error (0, 0, gettext ("%s: File format not recognized"), fname);
+
+  return 1;
+}
+
+
+static int
+handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
+          const char *suffix)
+{
+  size_t fname_len = strlen (fname) + 1;
+  size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
+  char new_prefix[prefix_len + fname_len + 2];
+  size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
+  char new_suffix[suffix_len + 2];
+  Elf *subelf;
+  Elf_Cmd cmd = ELF_C_READ_MMAP;
+  int result = 0;
+
+  char *cp = new_prefix;
+  if (prefix != NULL)
+    cp = stpcpy (cp, prefix);
+  cp = stpcpy (cp, fname);
+  stpcpy (cp, "[");
+
+  cp = new_suffix;
+  if (suffix != NULL)
+    cp = stpcpy (cp, suffix);
+  stpcpy (cp, "]");
+
+  /* Process all the files contained in the archive.  */
+  while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
+    {
+      /* The the header for this element.  */
+      Elf_Arhdr *arhdr = elf_getarhdr (subelf);
+
+      /* Skip over the index entries.  */
+      if (strcmp (arhdr->ar_name, "/") != 0
+         && strcmp (arhdr->ar_name, "//") != 0)
+       {
+         if (elf_kind (subelf) == ELF_K_ELF)
+           result |= handle_elf (subelf, new_prefix, arhdr->ar_name,
+                                 new_suffix);
+         else if (elf_kind (subelf) == ELF_K_AR)
+           result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
+                                new_suffix);
+         else
+           {
+             error (0, 0, gettext ("%s%s%s: file format not recognized"),
+                    new_prefix, arhdr->ar_name, new_suffix);
+             result = 1;
+           }
+       }
+
+      /* Get next archive element.  */
+      cmd = elf_next (subelf);
+      if (elf_end (subelf) != 0)
+       INTERNAL_ERROR (fname);
+    }
+
+  return result;
+}
+
+
+static void
+show_relocs_rel (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
+                Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
+                size_t shstrndx)
+{
+  int elfclass = gelf_getclass (ebl->elf);
+  int nentries = shdr->sh_size / shdr->sh_entsize;
+
+  for (int cnt = 0; cnt < nentries; ++cnt)
+    {
+      GElf_Rel relmem;
+      GElf_Rel *rel;
+
+      rel = gelf_getrel (data, cnt, &relmem);
+      if (rel != NULL)
+       {
+         char buf[128];
+         GElf_Sym symmem;
+         GElf_Sym *sym;
+         Elf32_Word xndx;
+
+         sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info),
+                                 &symmem, &xndx);
+         if (sym == NULL)
+           printf ("%0*" PRIx64 " %-20s <%s %ld>\n",
+                   elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                   ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                          buf, sizeof (buf))
+                   : gettext ("<INVALID RELOC>"),
+                   gettext ("INVALID SYMBOL"),
+                   (long int) GELF_R_SYM (rel->r_info));
+         else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
+           printf ("%0*" PRIx64 " %-20s %s\n",
+                   elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                   ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                          buf, sizeof (buf))
+                   : gettext ("<INVALID RELOC>"),
+                   elf_strptr (ebl->elf, symstrndx, sym->st_name));
+         else
+           {
+             GElf_Shdr destshdr_mem;
+             GElf_Shdr *destshdr;
+             destshdr = gelf_getshdr (elf_getscn (ebl->elf,
+                                                  sym->st_shndx == SHN_XINDEX
+                                                  ? xndx : sym->st_shndx),
+                                      &destshdr_mem);
+
+             if (shdr == NULL)
+               printf ("%0*" PRIx64 " %-20s <%s %ld>\n",
+                       elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf))
+                       : gettext ("<INVALID RELOC>"),
+                       gettext ("INVALID SECTION"),
+                       (long int) (sym->st_shndx == SHN_XINDEX
+                                   ? xndx : sym->st_shndx));
+             else
+               printf ("%0*" PRIx64 " %-20s %s\n",
+                       elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf))
+                       : gettext ("<INVALID RELOC>"),
+                       elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+           }
+       }
+    }
+}
+
+
+static void
+show_relocs_rela (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
+                 Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
+                 size_t shstrndx)
+{
+  int elfclass = gelf_getclass (ebl->elf);
+  int nentries = shdr->sh_size / shdr->sh_entsize;
+
+  for (int cnt = 0; cnt < nentries; ++cnt)
+    {
+      GElf_Rela relmem;
+      GElf_Rela *rel;
+
+      rel = gelf_getrela (data, cnt, &relmem);
+      if (rel != NULL)
+       {
+         char buf[128];
+         GElf_Sym symmem;
+         GElf_Sym *sym;
+         Elf32_Word xndx;
+
+         sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info),
+                                 &symmem, &xndx);
+         if (sym == NULL)
+           printf ("%0*" PRIx64 " %-20s <%s %ld>",
+                   elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                   ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                          buf, sizeof (buf))
+                   : gettext ("<INVALID RELOC>"),
+                   gettext ("INVALID SYMBOL"),
+                   (long int) GELF_R_SYM (rel->r_info));
+         else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
+           printf ("%0*" PRIx64 " %-20s %s",
+                   elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                   ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                   ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                          buf, sizeof (buf))
+                   : gettext ("<INVALID RELOC>"),
+                   elf_strptr (ebl->elf, symstrndx, sym->st_name));
+         else
+           {
+             GElf_Shdr destshdr_mem;
+             GElf_Shdr *destshdr;
+             destshdr = gelf_getshdr (elf_getscn (ebl->elf,
+                                                  sym->st_shndx == SHN_XINDEX
+                                                  ? xndx : sym->st_shndx),
+                                      &destshdr_mem);
+
+             if (shdr == NULL)
+               printf ("%0*" PRIx64 " %-20s <%s %ld>",
+                       elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf))
+                       : gettext ("<INVALID RELOC>"),
+                       gettext ("INVALID SECTION"),
+                       (long int) (sym->st_shndx == SHN_XINDEX
+                                   ? xndx : sym->st_shndx));
+             else
+               printf ("%0*" PRIx64 " %-20s %s",
+                       elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
+                       ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+                       ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+                                              buf, sizeof (buf))
+                       : gettext ("<INVALID RELOC>"),
+                       elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+           }
+
+         if (rel->r_addend != 0)
+           printf ("+%#" PRIx64, rel->r_addend);
+         putchar ('\n');
+       }
+    }
+}
+
+
+static bool
+section_match (Elf *elf, uint32_t scnndx, GElf_Shdr *shdr, size_t shstrndx)
+{
+  if (section_list == NULL)
+    return true;
+
+  struct section_list *runp = section_list;
+
+  do
+    {
+      if (runp->is_name)
+       {
+         if (strcmp (runp->name,
+                     elf_strptr (elf, shstrndx, shdr->sh_name)) == 0)
+           return true;
+       }
+      else
+       {
+         if (runp->scnndx == scnndx)
+           return true;
+       }
+
+      runp = runp->next;
+    }
+  while (runp != NULL);
+
+  return false;
+}
+
+
+static int
+show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx)
+{
+  int elfclass = gelf_getclass (ebl->elf);
+
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+      if (shdr == NULL)
+       INTERNAL_ERROR (fname);
+
+      if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+       {
+         if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
+           continue;
+
+         GElf_Shdr destshdr_mem;
+         GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf,
+                                                         shdr->sh_info),
+                                             &destshdr_mem);
+
+         printf (gettext ("RELOCATION RECORDS FOR [%s]:\n"
+                          "%-*s TYPE                 VALUE\n"),
+                 elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
+                 elfclass == ELFCLASS32 ? 8 : 16, gettext ("OFFSET"));
+
+         /* Get the data of the section.  */
+         Elf_Data *data = elf_getdata (scn, NULL);
+         if (data == NULL)
+           continue;
+
+         /* Get the symbol table information.  */
+         Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
+         GElf_Shdr symshdr_mem;
+         GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
+         Elf_Data *symdata = elf_getdata (symscn, NULL);
+
+         /* Search for the optional extended section index table.  */
+         Elf_Data *xndxdata = NULL;
+         Elf_Scn *xndxscn = NULL;
+         while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
+           {
+             GElf_Shdr xndxshdr_mem;
+             GElf_Shdr *xndxshdr;
+
+             xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
+             if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
+                 && xndxshdr->sh_link == elf_ndxscn (symscn))
+               {
+                 /* Found it.  */
+                 xndxdata = elf_getdata (xndxscn, NULL);
+                 break;
+               }
+           }
+
+         if (shdr->sh_type == SHT_REL)
+           show_relocs_rel (ebl, shdr, data, symdata, xndxdata,
+                            symshdr->sh_link, shstrndx);
+         else
+           show_relocs_rela (ebl, shdr, data, symdata, xndxdata,
+                             symshdr->sh_link, shstrndx);
+       }
+    }
+
+  fputs_unlocked ("\n\n", stdout);
+
+  return 0;
+}
+
+
+static int
+show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
+{
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+
+      if (shdr == NULL)
+       INTERNAL_ERROR (fname);
+
+      if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0)
+       {
+         if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
+           continue;
+
+         printf (gettext ("Contents of section %s:\n"),
+                 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
+
+         /* Get the data of the section.  */
+         Elf_Data *data = elf_getdata (scn, NULL);
+         if (data == NULL)
+           continue;
+
+         unsigned char *cp = data->d_buf;
+         size_t cnt;
+         for (cnt = 0; cnt + 16 < data->d_size; cp += 16, cnt += 16)
+           {
+             printf (" %04zx ", cnt);
+
+             for (size_t inner = 0; inner < 16; inner += 4)
+               printf ("%02hhx%02hhx%02hhx%02hhx ",
+                       cp[inner], cp[inner + 1], cp[inner + 2],
+                       cp[inner + 3]);
+             fputc_unlocked (' ', stdout);
+
+             for (size_t inner = 0; inner < 16; ++inner)
+               fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
+                               ? cp[inner] : '.', stdout);
+             fputc_unlocked ('\n', stdout);
+           }
+
+         printf (" %04zx ", cnt);
+
+         size_t remaining = data->d_size - cnt;
+         size_t inner;
+         for (inner = 0; inner + 4 <= remaining; inner += 4)
+           printf ("%02hhx%02hhx%02hhx%02hhx ",
+                   cp[inner], cp[inner + 1], cp[inner + 2], cp[inner + 3]);
+
+         for (; inner < remaining; ++inner)
+           printf ("%02hhx", cp[inner]);
+
+         for (inner = 2 * (16 - inner) + (16 - inner + 3) / 4 + 1; inner > 0;
+              --inner)
+           fputc_unlocked (' ', stdout);
+
+         for (inner = 0; inner < remaining; ++inner)
+           fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
+                           ? cp[inner] : '.', stdout);
+         fputc_unlocked ('\n', stdout);
+
+         fputc_unlocked ('\n', stdout);
+       }
+    }
+
+  return 0;
+}
+
+
+static int
+show_disasm (Ebl *ebl __attribute__ ((unused)),
+            const char *fname __attribute__ ((unused)),
+            uint32_t shstrndx __attribute__ ((unused)))
+{
+  /// XXX For now nothing.
+
+  return 0;
+}
+
+
+static int
+handle_elf (Elf *elf, const char *prefix, const char *fname,
+           const char *suffix)
+{
+
+  /* Get the backend for this object file type.  */
+  Ebl *ebl = ebl_openbackend (elf);
+
+  printf (gettext ("%s: elf%d-%s\n\n"),
+         fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64,
+         ebl_backend_name (ebl));
+
+  /* Create the full name of the file.  */
+  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
+  size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
+  size_t fname_len = strlen (fname) + 1;
+  char fullname[prefix_len + 1 + fname_len + suffix_len];
+  char *cp = fullname;
+  if (prefix != NULL)
+    cp = mempcpy (cp, prefix, prefix_len);
+  cp = mempcpy (cp, fname, fname_len);
+  if (suffix != NULL)
+    memcpy (cp - 1, suffix, suffix_len + 1);
+
+  /* Get the section header string table index.  */
+  size_t shstrndx;
+  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
+    error (EXIT_FAILURE, 0,
+          gettext ("cannot get section header string table index"));
+
+  int result = 0;
+  if (print_disasm)
+    result = show_disasm (ebl, fullname, shstrndx);
+  if (print_relocs && !print_disasm)
+    result = show_relocs (ebl, fullname, shstrndx);
+  if (print_full_content)
+    result = show_full_content (ebl, fullname, shstrndx);
+
+  /* Close the ELF backend library descriptor.  */
+  ebl_closebackend (ebl);
+
+  return result;
+}