objdump.c revision fd47989094090138b0c857d067ac7ff05e7b6d91
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@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.  */
51static void print_version (FILE *stream, struct argp_state *state);
52void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
53
54/* Bug report address.  */
55const char *argp_program_bug_address = PACKAGE_BUGREPORT;
56
57
58/* Definitions of arguments for argp functions.  */
59static 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.  */
76static const char doc[] = N_("\
77Show information from FILEs (a.out by default).");
78
79/* Strings for arguments in help texts.  */
80static const char args_doc[] = N_("[FILE...]");
81
82/* Prototype for option handler.  */
83static error_t parse_opt (int key, char *arg, struct argp_state *state);
84
85/* Data structure to communicate with argp functions.  */
86static struct argp argp =
87{
88  options, parse_opt, args_doc, doc, NULL, NULL, NULL
89};
90
91
92/* Print symbols in file named FNAME.  */
93static int process_file (const char *fname, bool more_than_one);
94
95/* Handle content of archive.  */
96static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
97		      const char *suffix);
98
99/* Handle ELF file.  */
100static 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.  */
110static 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.  */
123static bool print_relocs;
124
125/* If true print full contents of requested sections.  */
126static bool print_full_content;
127
128/* If true print disassembled output..  */
129static bool print_disasm;
130
131int
132main (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.  */
177static void
178print_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 ("\
182Copyright (C) %s Red Hat, Inc.\n\
183This is free software; see the source for copying conditions.  There is NO\n\
184warranty; 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.  */
191static error_t
192parse_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.  */
250static int
251process_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
302static int
303handle_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
360static void
361show_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
433static void
434show_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
510static bool
511section_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
540static int
541show_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
613static int
614show_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
684struct 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.
694static int
695disasm_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
725static int
726show_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
770static int
771handle_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