objdump.c revision cbb422eb102660d97209ec632e3b6572f0b0c7a6
1/* Print information from ELF file in human-readable form.
2   Copyright (C) 2005, 2006, 2007, 2009 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);
52ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
53
54/* Bug report address.  */
55ARGP_PROGRAM_BUG_ADDRESS_DEF = 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"), "20089");
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,
238		     program_invocation_short_name);
239	  exit (EXIT_FAILURE);
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	    {
504	      char sign = '+';
505	      if (rel->r_addend < 0)
506		{
507		  sign = '-';
508		  rel->r_addend = -rel->r_addend;
509		}
510	      printf ("%c%#" PRIx64, sign, rel->r_addend);
511	    }
512	  putchar ('\n');
513	}
514    }
515}
516
517
518static bool
519section_match (Elf *elf, uint32_t scnndx, GElf_Shdr *shdr, size_t shstrndx)
520{
521  if (section_list == NULL)
522    return true;
523
524  struct section_list *runp = section_list;
525
526  do
527    {
528      if (runp->is_name)
529	{
530	  if (strcmp (runp->name,
531		      elf_strptr (elf, shstrndx, shdr->sh_name)) == 0)
532	    return true;
533	}
534      else
535	{
536	  if (runp->scnndx == scnndx)
537	    return true;
538	}
539
540      runp = runp->next;
541    }
542  while (runp != NULL);
543
544  return false;
545}
546
547
548static int
549show_relocs (Ebl *ebl, const char *fname, uint32_t shstrndx)
550{
551  int elfclass = gelf_getclass (ebl->elf);
552
553  Elf_Scn *scn = NULL;
554  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
555    {
556      GElf_Shdr shdr_mem;
557      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
558
559      if (shdr == NULL)
560	INTERNAL_ERROR (fname);
561
562      if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
563	{
564 	  if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
565	    continue;
566
567	  GElf_Shdr destshdr_mem;
568	  GElf_Shdr *destshdr = gelf_getshdr (elf_getscn (ebl->elf,
569							  shdr->sh_info),
570					      &destshdr_mem);
571
572	  printf (gettext ("\n\nRELOCATION RECORDS FOR [%s]:\n"
573			   "%-*s TYPE                 VALUE\n"),
574		  elf_strptr (ebl->elf, shstrndx, destshdr->sh_name),
575		  elfclass == ELFCLASS32 ? 8 : 16, gettext ("OFFSET"));
576
577	  /* Get the data of the section.  */
578	  Elf_Data *data = elf_getdata (scn, NULL);
579	  if (data == NULL)
580	    continue;
581
582	  /* Get the symbol table information.  */
583	  Elf_Scn *symscn = elf_getscn (ebl->elf, shdr->sh_link);
584	  GElf_Shdr symshdr_mem;
585	  GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
586	  Elf_Data *symdata = elf_getdata (symscn, NULL);
587
588	  /* Search for the optional extended section index table.  */
589	  Elf_Data *xndxdata = NULL;
590	  Elf_Scn *xndxscn = NULL;
591	  while ((xndxscn = elf_nextscn (ebl->elf, xndxscn)) != NULL)
592	    {
593	      GElf_Shdr xndxshdr_mem;
594	      GElf_Shdr *xndxshdr;
595
596	      xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
597	      if (xndxshdr != NULL && xndxshdr->sh_type == SHT_SYMTAB_SHNDX
598		  && xndxshdr->sh_link == elf_ndxscn (symscn))
599		{
600		  /* Found it.  */
601		  xndxdata = elf_getdata (xndxscn, NULL);
602		  break;
603		}
604	    }
605
606	  if (shdr->sh_type == SHT_REL)
607	    show_relocs_rel (ebl, shdr, data, symdata, xndxdata,
608			     symshdr->sh_link, shstrndx);
609	  else
610	    show_relocs_rela (ebl, shdr, data, symdata, xndxdata,
611			      symshdr->sh_link, shstrndx);
612	}
613    }
614
615  fputs_unlocked ("\n\n", stdout);
616
617  return 0;
618}
619
620
621static int
622show_full_content (Ebl *ebl, const char *fname, uint32_t shstrndx)
623{
624  Elf_Scn *scn = NULL;
625  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
626    {
627      GElf_Shdr shdr_mem;
628      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
629
630      if (shdr == NULL)
631	INTERNAL_ERROR (fname);
632
633      if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0)
634	{
635 	  if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
636	    continue;
637
638	  printf (gettext ("Contents of section %s:\n"),
639		  elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
640
641	  /* Get the data of the section.  */
642	  Elf_Data *data = elf_getdata (scn, NULL);
643	  if (data == NULL)
644	    continue;
645
646	  unsigned char *cp = data->d_buf;
647	  size_t cnt;
648	  for (cnt = 0; cnt + 16 < data->d_size; cp += 16, cnt += 16)
649	    {
650	      printf (" %04zx ", cnt);
651
652	      for (size_t inner = 0; inner < 16; inner += 4)
653		printf ("%02hhx%02hhx%02hhx%02hhx ",
654			cp[inner], cp[inner + 1], cp[inner + 2],
655			cp[inner + 3]);
656	      fputc_unlocked (' ', stdout);
657
658	      for (size_t inner = 0; inner < 16; ++inner)
659		fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
660				? cp[inner] : '.', stdout);
661	      fputc_unlocked ('\n', stdout);
662	    }
663
664	  printf (" %04zx ", cnt);
665
666	  size_t remaining = data->d_size - cnt;
667	  size_t inner;
668	  for (inner = 0; inner + 4 <= remaining; inner += 4)
669	    printf ("%02hhx%02hhx%02hhx%02hhx ",
670		    cp[inner], cp[inner + 1], cp[inner + 2], cp[inner + 3]);
671
672	  for (; inner < remaining; ++inner)
673	    printf ("%02hhx", cp[inner]);
674
675	  for (inner = 2 * (16 - inner) + (16 - inner + 3) / 4 + 1; inner > 0;
676	       --inner)
677	    fputc_unlocked (' ', stdout);
678
679	  for (inner = 0; inner < remaining; ++inner)
680	    fputc_unlocked (isascii (cp[inner]) && isprint (cp[inner])
681			    ? cp[inner] : '.', stdout);
682	  fputc_unlocked ('\n', stdout);
683
684	  fputc_unlocked ('\n', stdout);
685	}
686    }
687
688  return 0;
689}
690
691
692struct disasm_info
693{
694  GElf_Addr addr;
695  const uint8_t *cur;
696  const uint8_t *last_end;
697};
698
699
700// XXX This is not the preferred output for all architectures.  Needs
701// XXX customization, too.
702static int
703disasm_output (char *buf, size_t buflen, void *arg)
704{
705  struct disasm_info *info = (struct disasm_info *) arg;
706
707  printf ("%8" PRIx64 ":   ", (uint64_t) info->addr);
708  size_t cnt;
709  for (cnt = 0; cnt < (size_t) MIN (info->cur - info->last_end, 8); ++cnt)
710    printf (" %02" PRIx8, info->last_end[cnt]);
711  printf ("%*s %.*s\n",
712	  (int) (8 - cnt) * 3 + 1, "", (int) buflen, buf);
713
714  info->addr += cnt;
715
716  /* We limit the number of bytes printed before the mnemonic to 8.
717     Print the rest on a separate, following line.  */
718  if (info->cur - info->last_end > 8)
719    {
720      printf ("%8" PRIx64 ":   ", (uint64_t) info->addr);
721      for (; cnt < (size_t) (info->cur - info->last_end); ++cnt)
722	printf (" %02" PRIx8, info->last_end[cnt]);
723      putchar_unlocked ('\n');
724      info->addr += info->cur - info->last_end - 8;
725    }
726
727  info->last_end = info->cur;
728
729  return 0;
730}
731
732
733static int
734show_disasm (Ebl *ebl, const char *fname, uint32_t shstrndx)
735{
736  DisasmCtx_t *ctx = disasm_begin (ebl, ebl->elf, NULL /* XXX TODO */);
737  if (ctx == NULL)
738    error (EXIT_FAILURE, 0, gettext ("cannot disassemble"));
739
740  Elf_Scn *scn = NULL;
741  while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
742    {
743      GElf_Shdr shdr_mem;
744      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
745
746      if (shdr == NULL)
747	INTERNAL_ERROR (fname);
748
749      if (shdr->sh_type == SHT_PROGBITS && shdr->sh_size > 0
750	  && (shdr->sh_flags & SHF_EXECINSTR) != 0)
751	{
752 	  if  (! section_match (ebl->elf, elf_ndxscn (scn), shdr, shstrndx))
753	    continue;
754
755	  Elf_Data *data = elf_getdata (scn, NULL);
756	  if (data == NULL)
757	    continue;
758
759	  printf ("Disassembly of section %s:\n\n",
760		  elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
761
762	  struct disasm_info info;
763	  info.addr = shdr->sh_addr;
764	  info.last_end = info.cur = data->d_buf;
765
766	  disasm_cb (ctx, &info.cur, info.cur + data->d_size, info.addr,
767		     "%7m %.1o,%.2o,%.3o%34a %l", disasm_output, &info,
768		     NULL /* XXX */);
769	}
770    }
771
772  (void) disasm_end (ctx);
773
774  return 0;
775}
776
777
778static int
779handle_elf (Elf *elf, const char *prefix, const char *fname,
780	    const char *suffix)
781{
782
783  /* Get the backend for this object file type.  */
784  Ebl *ebl = ebl_openbackend (elf);
785
786  printf ("%s: elf%d-%s\n\n",
787	  fname, gelf_getclass (elf) == ELFCLASS32 ? 32 : 64,
788	  ebl_backend_name (ebl));
789
790  /* Create the full name of the file.  */
791  size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
792  size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
793  size_t fname_len = strlen (fname) + 1;
794  char fullname[prefix_len + 1 + fname_len + suffix_len];
795  char *cp = fullname;
796  if (prefix != NULL)
797    cp = mempcpy (cp, prefix, prefix_len);
798  cp = mempcpy (cp, fname, fname_len);
799  if (suffix != NULL)
800    memcpy (cp - 1, suffix, suffix_len + 1);
801
802  /* Get the section header string table index.  */
803  size_t shstrndx;
804  if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
805    error (EXIT_FAILURE, 0,
806	   gettext ("cannot get section header string table index"));
807
808  int result = 0;
809  if (print_disasm)
810    result = show_disasm (ebl, fullname, shstrndx);
811  if (print_relocs && !print_disasm)
812    result = show_relocs (ebl, fullname, shstrndx);
813  if (print_full_content)
814    result = show_full_content (ebl, fullname, shstrndx);
815
816  /* Close the ELF backend library descriptor.  */
817  ebl_closebackend (ebl);
818
819  return result;
820}
821
822
823#include "debugpred.h"
824