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