Home | History | Annotate | Download | only in src
      1 /* Print information from ELF file in human-readable form.
      2    Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4    Written by Ulrich Drepper <drepper (at) redhat.com>, 2005.
      5 
      6    Red Hat elfutils is free software; you can redistribute it and/or modify
      7    it under the terms of the GNU General Public License as published by the
      8    Free Software Foundation; version 2 of the License.
      9 
     10    Red Hat elfutils is distributed in the hope that it will be useful, but
     11    WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13    General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License along
     16    with Red Hat elfutils; if not, write to the Free Software Foundation,
     17    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     18 
     19    Red Hat elfutils is an included package of the Open Invention Network.
     20    An included package of the Open Invention Network is a package for which
     21    Open Invention Network licensees cross-license their patents.  No patent
     22    license is granted, either expressly or impliedly, by designation as an
     23    included package.  Should you wish to participate in the Open Invention
     24    Network licensing program, please visit www.openinventionnetwork.com
     25    <http://www.openinventionnetwork.com>.  */
     26 
     27 #ifdef HAVE_CONFIG_H
     28 # include <config.h>
     29 #endif
     30 
     31 #include <argp.h>
     32 #include <error.h>
     33 #include <fcntl.h>
     34 #include <inttypes.h>
     35 #include <libintl.h>
     36 #include <locale.h>
     37 #include <mcheck.h>
     38 #include <stdbool.h>
     39 #include <stdio.h>
     40 #include <stdio_ext.h>
     41 #include <stdlib.h>
     42 #include <string.h>
     43 #include <unistd.h>
     44 #include <sys/param.h>
     45 
     46 #include <system.h>
     47 #include "../libebl/libeblP.h"
     48 
     49 
     50 /* Name and version of program.  */
     51 static void print_version (FILE *stream, struct argp_state *state);
     52 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
     53 
     54 /* Bug report address.  */
     55 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
     56 
     57 
     58 /* Definitions of arguments for argp functions.  */
     59 static const struct argp_option options[] =
     60 {
     61   { NULL, 0, NULL, 0, N_("Mode selection:"), 0 },
     62   { "reloc", 'r', NULL, 0, N_("Display relocation information."), 0 },
     63   { "full-contents", 's', NULL, 0,
     64     N_("Display the full contents of all sections requested"), 0 },
     65   { "disassemble", 'd', NULL, 0,
     66     N_("Display assembler code of executable sections"), 0 },
     67 
     68   { NULL, 0, NULL, 0, N_("Output option selection:"), 0 },
     69   { "section", 'j', "NAME", 0,
     70     N_("Only display information for section NAME."), 0 },
     71 
     72   { NULL, 0, NULL, 0, NULL, 0 }
     73 };
     74 
     75 /* Short description of program.  */
     76 static const char doc[] = N_("\
     77 Show information from FILEs (a.out by default).");
     78 
     79 /* Strings for arguments in help texts.  */
     80 static const char args_doc[] = N_("[FILE...]");
     81 
     82 /* Prototype for option handler.  */
     83 static error_t parse_opt (int key, char *arg, struct argp_state *state);
     84 
     85 /* Data structure to communicate with argp functions.  */
     86 static struct argp argp =
     87 {
     88   options, parse_opt, args_doc, doc, NULL, NULL, NULL
     89 };
     90 
     91 
     92 /* Print symbols in file named FNAME.  */
     93 static int process_file (const char *fname, bool more_than_one);
     94 
     95 /* Handle content of archive.  */
     96 static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
     97 		      const char *suffix);
     98 
     99 /* Handle ELF file.  */
    100 static int handle_elf (Elf *elf, const char *prefix, const char *fname,
    101 		       const char *suffix);
    102 
    103 
    104 #define INTERNAL_ERROR(fname) \
    105   error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"),      \
    106 	 fname, __LINE__, PACKAGE_VERSION, __DATE__, elf_errmsg (-1))
    107 
    108 
    109 /* List of sections which should be used.  */
    110 static struct section_list
    111 {
    112   bool is_name;
    113   union
    114   {
    115     const char *name;
    116     uint32_t scnndx;
    117   };
    118   struct section_list *next;
    119 } *section_list;
    120 
    121 
    122 /* If true print archive index.  */
    123 static bool print_relocs;
    124 
    125 /* If true print full contents of requested sections.  */
    126 static bool print_full_content;
    127 
    128 /* If true print disassembled output..  */
    129 static bool print_disasm;
    130 
    131 int
    132 main (int argc, char *argv[])
    133 {
    134   /* Make memory leak detection possible.  */
    135   mtrace ();
    136 
    137   /* We use no threads here which can interfere with handling a stream.  */
    138   (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
    139   (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
    140   (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
    141 
    142   /* Set locale.  */
    143   (void) setlocale (LC_ALL, "");
    144 
    145   /* Make sure the message catalog can be found.  */
    146   (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
    147 
    148   /* Initialize the message catalog.  */
    149   (void) textdomain (PACKAGE_TARNAME);
    150 
    151   /* Parse and process arguments.  */
    152   int remaining;
    153   (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
    154 
    155   /* Tell the library which version we are expecting.  */
    156   (void) elf_version (EV_CURRENT);
    157 
    158   int result = 0;
    159   if (remaining == argc)
    160     /* The user didn't specify a name so we use a.out.  */
    161     result = process_file ("a.out", false);
    162   else
    163     {
    164       /* Process all the remaining files.  */
    165       const bool more_than_one = remaining + 1 < argc;
    166 
    167       do
    168 	result |= process_file (argv[remaining], more_than_one);
    169       while (++remaining < argc);
    170     }
    171 
    172   return result;
    173 }
    174 
    175 
    176 /* Print the version information.  */
    177 static void
    178 print_version (FILE *stream, struct argp_state *state __attribute__ ((unused)))
    179 {
    180   fprintf (stream, "objdump (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
    181   fprintf (stream, gettext ("\
    182 Copyright (C) %s Red Hat, Inc.\n\
    183 This is free software; see the source for copying conditions.  There is NO\n\
    184 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
    185 "), "2008");
    186   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
    187 }
    188 
    189 
    190 /* Handle program arguments.  */
    191 static error_t
    192 parse_opt (int key, char *arg,
    193 	   struct argp_state *state __attribute__ ((unused)))
    194 {
    195   /* True if any of the control options is set.  */
    196   static bool any_control_option;
    197 
    198   switch (key)
    199     {
    200     case 'j':
    201       {
    202 	struct section_list *newp = xmalloc (sizeof (*newp));
    203 	char *endp;
    204 	newp->scnndx = strtoul (arg, &endp, 0);
    205 	if (*endp == 0)
    206 	  newp->is_name = false;
    207 	else
    208 	  {
    209 	    newp->name = arg;
    210 	    newp->is_name = true;
    211 	  }
    212 	newp->next = section_list;
    213 	section_list = newp;
    214       }
    215       any_control_option = true;
    216       break;
    217 
    218     case 'd':
    219       print_disasm = true;
    220       any_control_option = true;
    221       break;
    222 
    223     case 'r':
    224       print_relocs = true;
    225       any_control_option = true;
    226       break;
    227 
    228     case 's':
    229       print_full_content = true;
    230       any_control_option = true;
    231       break;
    232 
    233     case ARGP_KEY_FINI:
    234       if (! any_control_option)
    235 	{
    236 	  fputs (gettext ("No operation specified.\n"), stderr);
    237 	  argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
    238 		     program_invocation_short_name);
    239 	  exit (1);
    240 	}
    241 
    242     default:
    243       return ARGP_ERR_UNKNOWN;
    244     }
    245   return 0;
    246 }
    247 
    248 
    249 /* Open the file and determine the type.  */
    250 static int
    251 process_file (const char *fname, bool more_than_one)
    252 {
    253   /* Open the file.  */
    254   int fd = open (fname, O_RDONLY);
    255   if (fd == -1)
    256     {
    257       error (0, errno, gettext ("cannot open %s"), fname);
    258       return 1;
    259     }
    260 
    261   /* Now get the ELF descriptor.  */
    262   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
    263   if (elf != NULL)
    264     {
    265       if (elf_kind (elf) == ELF_K_ELF)
    266 	{
    267 	  int result = handle_elf (elf, more_than_one ? "" : NULL,
    268 				   fname, NULL);
    269 
    270 	  if (elf_end (elf) != 0)
    271 	    INTERNAL_ERROR (fname);
    272 
    273 	  if (close (fd) != 0)
    274 	    error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
    275 
    276 	  return result;
    277 	}
    278       else if (elf_kind (elf) == ELF_K_AR)
    279 	{
    280 	  int result = handle_ar (fd, elf, NULL, fname, NULL);
    281 
    282 	  if (elf_end (elf) != 0)
    283 	    INTERNAL_ERROR (fname);
    284 
    285 	  if (close (fd) != 0)
    286 	    error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
    287 
    288 	  return result;
    289 	}
    290 
    291       /* We cannot handle this type.  Close the descriptor anyway.  */
    292       if (elf_end (elf) != 0)
    293 	INTERNAL_ERROR (fname);
    294     }
    295 
    296   error (0, 0, gettext ("%s: File format not recognized"), fname);
    297 
    298   return 1;
    299 }
    300 
    301 
    302 static int
    303 handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
    304 	   const char *suffix)
    305 {
    306   size_t fname_len = strlen (fname) + 1;
    307   size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
    308   char new_prefix[prefix_len + fname_len + 2];
    309   size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
    310   char new_suffix[suffix_len + 2];
    311   Elf *subelf;
    312   Elf_Cmd cmd = ELF_C_READ_MMAP;
    313   int result = 0;
    314 
    315   char *cp = new_prefix;
    316   if (prefix != NULL)
    317     cp = stpcpy (cp, prefix);
    318   cp = stpcpy (cp, fname);
    319   stpcpy (cp, "[");
    320 
    321   cp = new_suffix;
    322   if (suffix != NULL)
    323     cp = stpcpy (cp, suffix);
    324   stpcpy (cp, "]");
    325 
    326   /* Process all the files contained in the archive.  */
    327   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
    328     {
    329       /* The the header for this element.  */
    330       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
    331 
    332       /* Skip over the index entries.  */
    333       if (strcmp (arhdr->ar_name, "/") != 0
    334 	  && strcmp (arhdr->ar_name, "//") != 0)
    335 	{
    336 	  if (elf_kind (subelf) == ELF_K_ELF)
    337 	    result |= handle_elf (subelf, new_prefix, arhdr->ar_name,
    338 				  new_suffix);
    339 	  else if (elf_kind (subelf) == ELF_K_AR)
    340 	    result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
    341 				 new_suffix);
    342 	  else
    343 	    {
    344 	      error (0, 0, gettext ("%s%s%s: file format not recognized"),
    345 		     new_prefix, arhdr->ar_name, new_suffix);
    346 	      result = 1;
    347 	    }
    348 	}
    349 
    350       /* Get next archive element.  */
    351       cmd = elf_next (subelf);
    352       if (elf_end (subelf) != 0)
    353 	INTERNAL_ERROR (fname);
    354     }
    355 
    356   return result;
    357 }
    358 
    359 
    360 static void
    361 show_relocs_rel (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
    362 		 Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
    363 		 size_t shstrndx)
    364 {
    365   int elfclass = gelf_getclass (ebl->elf);
    366   int nentries = shdr->sh_size / shdr->sh_entsize;
    367 
    368   for (int cnt = 0; cnt < nentries; ++cnt)
    369     {
    370       GElf_Rel relmem;
    371       GElf_Rel *rel;
    372 
    373       rel = gelf_getrel (data, cnt, &relmem);
    374       if (rel != NULL)
    375 	{
    376 	  char buf[128];
    377 	  GElf_Sym symmem;
    378 	  GElf_Sym *sym;
    379 	  Elf32_Word xndx;
    380 
    381 	  sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info),
    382 				  &symmem, &xndx);
    383 	  if (sym == NULL)
    384 	    printf ("%0*" PRIx64 " %-20s <%s %ld>\n",
    385 		    elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    386 		    ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    387 		    ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    388 					   buf, sizeof (buf))
    389 		    : gettext ("<INVALID RELOC>"),
    390 		    gettext ("INVALID SYMBOL"),
    391 		    (long int) GELF_R_SYM (rel->r_info));
    392 	  else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
    393 	    printf ("%0*" PRIx64 " %-20s %s\n",
    394 		    elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    395 		    ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    396 		    ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    397 					   buf, sizeof (buf))
    398 		    : gettext ("<INVALID RELOC>"),
    399 		    elf_strptr (ebl->elf, symstrndx, sym->st_name));
    400 	  else
    401 	    {
    402 	      GElf_Shdr destshdr_mem;
    403 	      GElf_Shdr *destshdr;
    404 	      destshdr = gelf_getshdr (elf_getscn (ebl->elf,
    405 						   sym->st_shndx == SHN_XINDEX
    406 						   ? xndx : sym->st_shndx),
    407 				       &destshdr_mem);
    408 
    409 	      if (shdr == NULL)
    410 		printf ("%0*" PRIx64 " %-20s <%s %ld>\n",
    411 			elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    412 			ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    413 			? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    414 					       buf, sizeof (buf))
    415 			: gettext ("<INVALID RELOC>"),
    416 			gettext ("INVALID SECTION"),
    417 			(long int) (sym->st_shndx == SHN_XINDEX
    418 				    ? xndx : sym->st_shndx));
    419 	      else
    420 		printf ("%0*" PRIx64 " %-20s %s\n",
    421 			elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    422 			ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    423 			? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    424 					       buf, sizeof (buf))
    425 			: gettext ("<INVALID RELOC>"),
    426 			elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
    427 	    }
    428 	}
    429     }
    430 }
    431 
    432 
    433 static void
    434 show_relocs_rela (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data,
    435 		  Elf_Data *symdata, Elf_Data *xndxdata, size_t symstrndx,
    436 		  size_t shstrndx)
    437 {
    438   int elfclass = gelf_getclass (ebl->elf);
    439   int nentries = shdr->sh_size / shdr->sh_entsize;
    440 
    441   for (int cnt = 0; cnt < nentries; ++cnt)
    442     {
    443       GElf_Rela relmem;
    444       GElf_Rela *rel;
    445 
    446       rel = gelf_getrela (data, cnt, &relmem);
    447       if (rel != NULL)
    448 	{
    449 	  char buf[128];
    450 	  GElf_Sym symmem;
    451 	  GElf_Sym *sym;
    452 	  Elf32_Word xndx;
    453 
    454 	  sym = gelf_getsymshndx (symdata, xndxdata, GELF_R_SYM (rel->r_info),
    455 				  &symmem, &xndx);
    456 	  if (sym == NULL)
    457 	    printf ("%0*" PRIx64 " %-20s <%s %ld>",
    458 		    elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    459 		    ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    460 		    ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    461 					   buf, sizeof (buf))
    462 		    : gettext ("<INVALID RELOC>"),
    463 		    gettext ("INVALID SYMBOL"),
    464 		    (long int) GELF_R_SYM (rel->r_info));
    465 	  else if (GELF_ST_TYPE (sym->st_info) != STT_SECTION)
    466 	    printf ("%0*" PRIx64 " %-20s %s",
    467 		    elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    468 		    ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    469 		    ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    470 					   buf, sizeof (buf))
    471 		    : gettext ("<INVALID RELOC>"),
    472 		    elf_strptr (ebl->elf, symstrndx, sym->st_name));
    473 	  else
    474 	    {
    475 	      GElf_Shdr destshdr_mem;
    476 	      GElf_Shdr *destshdr;
    477 	      destshdr = gelf_getshdr (elf_getscn (ebl->elf,
    478 						   sym->st_shndx == SHN_XINDEX
    479 						   ? xndx : sym->st_shndx),
    480 				       &destshdr_mem);
    481 
    482 	      if (shdr == NULL)
    483 		printf ("%0*" PRIx64 " %-20s <%s %ld>",
    484 			elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    485 			ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    486 			? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    487 					       buf, sizeof (buf))
    488 			: gettext ("<INVALID RELOC>"),
    489 			gettext ("INVALID SECTION"),
    490 			(long int) (sym->st_shndx == SHN_XINDEX
    491 				    ? xndx : sym->st_shndx));
    492 	      else
    493 		printf ("%0*" PRIx64 " %-20s %s",
    494 			elfclass == ELFCLASS32 ? 8 : 16, rel->r_offset,
    495 			ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
    496 			? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
    497 					       buf, sizeof (buf))
    498 			: gettext ("<INVALID RELOC>"),
    499 			elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
    500 	    }
    501 
    502 	  if (rel->r_addend != 0)
    503 	    printf ("+%#" PRIx64, rel->r_addend);
    504 	  putchar ('\n');
    505 	}
    506     }
    507 }
    508 
    509 
    510 static bool
    511 section_match (Elf *elf, uint32_t scnndx, GElf_Shdr *shdr, size_t shstrndx)
    512 {
    513   if (section_list == NULL)
    514     return true;
    515 
    516   struct section_list *runp = section_list;
    517 
    518   do
    519     {
    520       if (runp->is_name)
    521 	{
    522 	  if (strcmp (runp->name,
    523 		      elf_strptr (elf, shstrndx, shdr->sh_name)) == 0)
    524 	    return true;
    525 	}
    526       else
    527 	{
    528 	  if (runp->scnndx == scnndx)
    529 	    return true;
    530 	}
    531 
    532       runp = runp->next;
    533     }
    534   while (runp != NULL);
    535 
    536   return false;
    537 }
    538 
    539 
    540 static int
    541 show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx)
    542 {
    543   int elfclass = gelf_getclass (ebl->elf);
    544 
    545   Elf_Scn *scn = NULL;
    546   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    547     {
    548       GElf_Shdr shdr_mem;
    549       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    550 
    551       if (shdr == NULL)
    552 	INTERNAL_ERROR (fname);
    553 
    554       if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
    555 	{
    556  	  if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
    557 	    continue;
    558 
    559 	  GElf_Shdr destshdr_mem;
    560 	  GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf,
    561 							  shdr->sh_info),
    562 					      &destshdr_mem);
    563 
    564 	  printf (gettext ("RELOCATION RECORDS FOR [%s]:\n"
    565 			   "%-*s TYPE                 VALUE\n"),
    566 		  elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
    567 		  elfclass == ELFCLASS32 ? 8 : 16, gettext ("OFFSET"));
    568 
    569 	  /* Get the data of the section.  */
    570 	  Elf_Data *data = elf_getdata (scn, NULL);
    571 	  if (data == NULL)
    572 	    continue;
    573 
    574 	  /* Get the symbol table information.  */
    575 	  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
    576 	  GElf_Shdr symshdr_mem;
    577 	  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
    578 	  Elf_Data *symdata = elf_getdata (symscn, NULL);
    579 
    580 	  /* Search for the optional extended section index table.  */
    581 	  Elf_Data *xndxdata = NULL;
    582 	  Elf_Scn *xndxscn = NULL;
    583 	  while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
    584 	    {
    585 	      GElf_Shdr xndxshdr_mem;
    586 	      GElf_Shdr *xndxshdr;
    587 
    588 	      xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
    589 	      if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
    590 		  && xndxshdr->sh_link == elf_ndxscn (symscn))
    591 		{
    592 		  /* Found it.  */
    593 		  xndxdata = elf_getdata (xndxscn, NULL);
    594 		  break;
    595 		}
    596 	    }
    597 
    598 	  if (shdr->sh_type == SHT_REL)
    599 	    show_relocs_rel (ebl, shdr, data, symdata, xndxdata,
    600 			     symshdr->sh_link, shstrndx);
    601 	  else
    602 	    show_relocs_rela (ebl, shdr, data, symdata, xndxdata,
    603 			      symshdr->sh_link, shstrndx);
    604 	}
    605     }
    606 
    607   fputs_unlocked ("\n\n", stdout);
    608 
    609   return 0;
    610 }
    611 
    612 
    613 static int
    614 show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
    615 {
    616   Elf_Scn *scn = NULL;
    617   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    618     {
    619       GElf_Shdr shdr_mem;
    620       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    621 
    622       if (shdr == NULL)
    623 	INTERNAL_ERROR (fname);
    624 
    625       if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0)
    626 	{
    627  	  if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
    628 	    continue;
    629 
    630 	  printf (gettext ("Contents of section %s:\n"),
    631 		  elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
    632 
    633 	  /* Get the data of the section.  */
    634 	  Elf_Data *data = elf_getdata (scn, NULL);
    635 	  if (data == NULL)
    636 	    continue;
    637 
    638 	  unsigned char *cp = data->d_buf;
    639 	  size_t cnt;
    640 	  for (cnt = 0; cnt + 16 < data->d_size; cp += 16, cnt += 16)
    641 	    {
    642 	      printf (" %04zx ", cnt);
    643 
    644 	      for (size_t inner = 0; inner < 16; inner += 4)
    645 		printf ("%02hhx%02hhx%02hhx%02hhx ",
    646 			cp[inner], cp[inner + 1], cp[inner + 2],
    647 			cp[inner + 3]);
    648 	      fputc_unlocked (' ', stdout);
    649 
    650 	      for (size_t inner = 0; inner < 16; ++inner)
    651 		fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
    652 				? cp[inner] : '.', stdout);
    653 	      fputc_unlocked ('\n', stdout);
    654 	    }
    655 
    656 	  printf (" %04zx ", cnt);
    657 
    658 	  size_t remaining = data->d_size - cnt;
    659 	  size_t inner;
    660 	  for (inner = 0; inner + 4 <= remaining; inner += 4)
    661 	    printf ("%02hhx%02hhx%02hhx%02hhx ",
    662 		    cp[inner], cp[inner + 1], cp[inner + 2], cp[inner + 3]);
    663 
    664 	  for (; inner < remaining; ++inner)
    665 	    printf ("%02hhx", cp[inner]);
    666 
    667 	  for (inner = 2 * (16 - inner) + (16 - inner + 3) / 4 + 1; inner > 0;
    668 	       --inner)
    669 	    fputc_unlocked (' ', stdout);
    670 
    671 	  for (inner = 0; inner < remaining; ++inner)
    672 	    fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
    673 			    ? cp[inner] : '.', stdout);
    674 	  fputc_unlocked ('\n', stdout);
    675 
    676 	  fputc_unlocked ('\n', stdout);
    677 	}
    678     }
    679 
    680   return 0;
    681 }
    682 
    683 
    684 struct disasm_info
    685 {
    686   GElf_Addr addr;
    687   const uint8_t *cur;
    688   const uint8_t *last_end;
    689 };
    690 
    691 
    692 // XXX This is not the preferred output for all architectures.  Needs
    693 // XXX customization, too.
    694 static int
    695 disasm_output (char *buf, size_t buflen, void *arg)
    696 {
    697   struct disasm_info *info = (struct disasm_info *) arg;
    698 
    699   printf ("%8" PRIx64 ":   ", (uint64_t) info->addr);
    700   size_t cnt;
    701   for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt)
    702     printf (" %02" PRIx8, info->last_end[cnt]);
    703   printf ("%*s %.*s\n",
    704 	  (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf);
    705 
    706   info->addr += cnt;
    707 
    708   /* We limit the number of bytes printed before the mnemonic to 8.
    709      Print the rest on a separate, following line.  */
    710   if (info->cur - info->last_end > 8)
    711     {
    712       printf ("%8" PRIx64 ":   ", (uint64_t) info->addr);
    713       for (; cnt < (size_t) (info->cur - info->last_end); ++cnt)
    714 	printf (" %02" PRIx8, info->last_end[cnt]);
    715       putchar_unlocked ('\n');
    716       info->addr += info->cur - info->last_end - 8;
    717     }
    718 
    719   info->last_end = info->cur;
    720 
    721   return 0;
    722 }
    723 
    724 
    725 static int
    726 show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx)
    727 {
    728   DisasmCtx_t *ctx = disasm_begin (ebl, ebl->elf, NULL /* XXX TODO */);
    729   if (ctx == NULL)
    730     error (EXIT_FAILURE, 0, gettext ("cannot disassemble"));
    731 
    732   Elf_Scn *scn = NULL;
    733   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
    734     {
    735       GElf_Shdr shdr_mem;
    736       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
    737 
    738       if (shdr == NULL)
    739 	INTERNAL_ERROR (fname);
    740 
    741       if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0
    742 	  && (shdr->sh_flags & SHF_EXECINSTR) != 0)
    743 	{
    744  	  if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
    745 	    continue;
    746 
    747 	  Elf_Data *data = elf_getdata (scn, NULL);
    748 	  if (data == NULL)
    749 	    continue;
    750 
    751 	  printf ("Disassembly of section %s:\n\n",
    752 		  elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
    753 
    754 	  struct disasm_info info;
    755 	  info.addr = shdr->sh_addr;
    756 	  info.last_end = info.cur = data->d_buf;
    757 
    758 	  disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr,
    759 		     "%7m %.1o,%.2o,%.3o%34a %l", disasm_output, &info,
    760 		     NULL /* XXX */);
    761 	}
    762     }
    763 
    764   (void) disasm_end (ctx);
    765 
    766   return 0;
    767 }
    768 
    769 
    770 static int
    771 handle_elf (Elf *elf, const char *prefix, const char *fname,
    772 	    const char *suffix)
    773 {
    774 
    775   /* Get the backend for this object file type.  */
    776   Ebl *ebl = ebl_openbackend (elf);
    777 
    778   printf ("%s: elf%d-%s\n\n",
    779 	  fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64,
    780 	  ebl_backend_name (ebl));
    781 
    782   /* Create the full name of the file.  */
    783   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
    784   size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
    785   size_t fname_len = strlen (fname) + 1;
    786   char fullname[prefix_len + 1 + fname_len + suffix_len];
    787   char *cp = fullname;
    788   if (prefix != NULL)
    789     cp = mempcpy (cp, prefix, prefix_len);
    790   cp = mempcpy (cp, fname, fname_len);
    791   if (suffix != NULL)
    792     memcpy (cp - 1, suffix, suffix_len + 1);
    793 
    794   /* Get the section header string table index.  */
    795   size_t shstrndx;
    796   if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
    797     error (EXIT_FAILURE, 0,
    798 	   gettext ("cannot get section header string table index"));
    799 
    800   int result = 0;
    801   if (print_disasm)
    802     result = show_disasm (ebl, fullname, shstrndx);
    803   if (print_relocs && !print_disasm)
    804     result = show_relocs (ebl, fullname, shstrndx);
    805   if (print_full_content)
    806     result = show_full_content (ebl, fullname, shstrndx);
    807 
    808   /* Close the ELF backend library descriptor.  */
    809   ebl_closebackend (ebl);
    810 
    811   return result;
    812 }
    813 
    814 
    815 #include "debugpred.h"
    816