| /* od-pe.c -- dump information about a PE object file. | 
 |    Copyright (C) 2011-2024 Free Software Foundation, Inc. | 
 |    Written by Tristan Gingold, Adacore and Nick Clifton, Red Hat. | 
 |  | 
 |    This file is part of GNU Binutils. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3, or (at your option) | 
 |    any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include <stddef.h> | 
 | #include <time.h> | 
 | #include "safe-ctype.h" | 
 | #include "bfd.h" | 
 | #include "objdump.h" | 
 | #include "bucomm.h" | 
 | #include "bfdlink.h" | 
 | #include "coff/internal.h" | 
 | #define L_LNNO_SIZE 4 /* FIXME: which value should we use ?  */ | 
 | #include "coff/external.h" | 
 | #include "coff/pe.h" | 
 | #include "libcoff.h" | 
 | #include "libpei.h" | 
 | #include "libiberty.h" | 
 |  | 
 | /* Index of the options in the options[] array.  */ | 
 | #define OPT_FILE_HEADER 0 | 
 | #define OPT_AOUT 1 | 
 | #define OPT_SECTIONS 2 | 
 | #define OPT_SYMS 3 | 
 | #define OPT_RELOCS 4 | 
 | #define OPT_LINENO 5 | 
 | #define OPT_LOADER 6 | 
 | #define OPT_EXCEPT 7 | 
 | #define OPT_TYPCHK 8 | 
 | #define OPT_TRACEBACK 9 | 
 | #define OPT_TOC 10 | 
 | #define OPT_LDINFO 11 | 
 |  | 
 | /* List of actions.  */ | 
 | static struct objdump_private_option options[] = | 
 | { | 
 |   { "header", 0 }, | 
 |   { "aout", 0 }, | 
 |   { "sections", 0 }, | 
 |   { "syms", 0 }, | 
 |   { "relocs", 0 }, | 
 |   { "lineno", 0 }, | 
 |   { "loader", 0 }, | 
 |   { "except", 0 }, | 
 |   { "typchk", 0 }, | 
 |   { "traceback", 0 }, | 
 |   { "toc", 0 }, | 
 |   { "ldinfo", 0 }, | 
 |   { NULL, 0 } | 
 | }; | 
 |  | 
 | /* Simplified section header.  */ | 
 | struct pe_section | 
 | { | 
 |   /* NUL terminated name.  */ | 
 |   char name[9]; | 
 |  | 
 |   /* Section flags.  */ | 
 |   unsigned int flags; | 
 |  | 
 |   /* Offsets in file.  */ | 
 |   ufile_ptr scnptr; | 
 |   ufile_ptr relptr; | 
 |   ufile_ptr lnnoptr; | 
 |  | 
 |   /* Number of relocs and line numbers.  */ | 
 |   unsigned int nreloc; | 
 |   unsigned int nlnno; | 
 | }; | 
 |  | 
 | /* Translation entry type.  The last entry must be {0, NULL}.  */ | 
 |  | 
 | struct xlat_table | 
 | { | 
 |   unsigned int  val; | 
 |   const char *  name; | 
 | }; | 
 |  | 
 | /* PE file flags.  */ | 
 | static const struct xlat_table file_flag_xlat[] = | 
 | { | 
 |   { IMAGE_FILE_RELOCS_STRIPPED,     "RELOCS STRIPPED"}, | 
 |   { IMAGE_FILE_EXECUTABLE_IMAGE,    "EXECUTABLE"}, | 
 |   { IMAGE_FILE_LINE_NUMS_STRIPPED,  "LINE NUMS STRIPPED"}, | 
 |   { IMAGE_FILE_LOCAL_SYMS_STRIPPED, "LOCAL SYMS STRIPPED"}, | 
 |   { IMAGE_FILE_AGGRESSIVE_WS_TRIM,  "AGGRESSIVE WS TRIM"}, | 
 |   { IMAGE_FILE_LARGE_ADDRESS_AWARE, "LARGE ADDRESS AWARE"}, | 
 |   { IMAGE_FILE_16BIT_MACHINE,       "16BIT MACHINE"}, | 
 |   { IMAGE_FILE_BYTES_REVERSED_LO,   "BYTES REVERSED LO"}, | 
 |   { IMAGE_FILE_32BIT_MACHINE,       "32BIT MACHINE"}, | 
 |   { IMAGE_FILE_DEBUG_STRIPPED,      "DEBUG STRIPPED"}, | 
 |   { IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, "REMOVABLE RUN FROM SWAP"}, | 
 |   { IMAGE_FILE_NET_RUN_FROM_SWAP,   "NET RUN FROM SWAP"}, | 
 |   { IMAGE_FILE_SYSTEM,              "SYSTEM"}, | 
 |   { IMAGE_FILE_DLL,                 "DLL"}, | 
 |   { IMAGE_FILE_UP_SYSTEM_ONLY,      "UP SYSTEM ONLY"}, | 
 |   { IMAGE_FILE_BYTES_REVERSED_HI,   "BYTES REVERSED HI"}, | 
 |   { 0, NULL } | 
 | }; | 
 |  | 
 | /* PE section flags.  */ | 
 | static const struct xlat_table section_flag_xlat[] = | 
 | { | 
 |   { IMAGE_SCN_MEM_DISCARDABLE, "DISCARDABLE" }, | 
 |   { IMAGE_SCN_MEM_EXECUTE,     "EXECUTE" }, | 
 |   { IMAGE_SCN_MEM_READ,        "READ" }, | 
 |   { IMAGE_SCN_MEM_WRITE,       "WRITE" }, | 
 |   { IMAGE_SCN_TYPE_NO_PAD,     "NO PAD" }, | 
 |   { IMAGE_SCN_CNT_CODE,        "CODE" }, | 
 |   { IMAGE_SCN_CNT_INITIALIZED_DATA,   "INITIALIZED DATA" }, | 
 |   { IMAGE_SCN_CNT_UNINITIALIZED_DATA, "UNINITIALIZED DATA" }, | 
 |   { IMAGE_SCN_LNK_OTHER,       "OTHER" }, | 
 |   { IMAGE_SCN_LNK_INFO,        "INFO" }, | 
 |   { IMAGE_SCN_LNK_REMOVE,      "REMOVE" }, | 
 |   { IMAGE_SCN_LNK_COMDAT,      "COMDAT" }, | 
 |   { IMAGE_SCN_MEM_FARDATA,     "FARDATA" }, | 
 |   { IMAGE_SCN_MEM_PURGEABLE,   "PURGEABLE" }, | 
 |   { IMAGE_SCN_MEM_LOCKED,      "LOCKED" }, | 
 |   { IMAGE_SCN_MEM_PRELOAD,     "PRELOAD" }, | 
 |   { IMAGE_SCN_LNK_NRELOC_OVFL, "NRELOC OVFL" }, | 
 |   { IMAGE_SCN_MEM_NOT_CACHED,  "NOT CACHED" }, | 
 |   { IMAGE_SCN_MEM_NOT_PAGED,   "NOT PAGED" }, | 
 |   { IMAGE_SCN_MEM_SHARED,      "SHARED" },     | 
 |   { 0, NULL } | 
 | }; | 
 |  | 
 | typedef struct target_specific_info | 
 | { | 
 |   unsigned int  machine_number; | 
 |   const char *  name; | 
 |   unsigned int  aout_hdr_size; | 
 | } target_specific_info; | 
 |  | 
 | const struct target_specific_info targ_info[] = | 
 | { | 
 |   { IMAGE_FILE_MACHINE_ALPHA, "ALPHA", 80 }, | 
 |   { IMAGE_FILE_MACHINE_ALPHA64, "ALPHA64", 80 }, | 
 |   { IMAGE_FILE_MACHINE_AM33, "AM33", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_AMD64, "AMD64", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_ARM, "ARM", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_ARM64, "ARM64", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_ARMNT, "ARM NT", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_CEE, "CEE", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_CEF, "CEF", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_EBC, "EBC", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_I386, "I386", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_IA64, "IA64", 108 }, | 
 |   { IMAGE_FILE_MACHINE_LOONGARCH64, "LOONGARCH64", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_M32R, "M32R", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_M68K, "M68K", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_MIPS16, "MIPS16", 56 }, | 
 |   { IMAGE_FILE_MACHINE_MIPSFPU, "MIPSFPU", 56 }, | 
 |   { IMAGE_FILE_MACHINE_MIPSFPU16, "MIPSFPU16", 56 }, | 
 |   { IMAGE_FILE_MACHINE_POWERPC, "POWERPC", 72 }, | 
 |   { IMAGE_FILE_MACHINE_POWERPCFP, "POWERPCFP", 72 }, | 
 |   { IMAGE_FILE_MACHINE_R10000, "R10000", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_R3000, "R3000", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_R4000, "R4000", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_SH3, "SH3", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_SH3DSP, "SH3DSP", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_SH3E, "SH3E", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_SH4, "SH4", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_SH5, "SH5", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_THUMB, "THUMB", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_TRICORE, "TRICORE", AOUTHDRSZ }, | 
 |   { IMAGE_FILE_MACHINE_WCEMIPSV2, "WCEMIPSV2", AOUTHDRSZ }, | 
 |  | 
 |   { 0x0093, "TI C4X", 28 }, | 
 |   { 0x00C1, "TI C4X", 28 }, | 
 |   { 0x00C2, "TI C4X", 28 }, | 
 |   { 0x0500, "SH (big endian)", AOUTHDRSZ }, | 
 |   { 0x0550, "SH (little endian)", AOUTHDRSZ }, | 
 |   { 0x0a00, "ARM", AOUTHDRSZ }, | 
 |   { 0x0b00, "MCore", AOUTHDRSZ } | 
 | }; | 
 |  | 
 | static const struct target_specific_info unknown_info = | 
 |   { 0, "unknown", AOUTHDRSZ }; | 
 |  | 
 | static const struct target_specific_info * | 
 | get_target_specific_info (unsigned int machine) | 
 | { | 
 |   unsigned int i; | 
 |  | 
 |   for (i = ARRAY_SIZE (targ_info); i--;) | 
 |     if (targ_info[i].machine_number == machine) | 
 |       return targ_info + i; | 
 |  | 
 |   return &unknown_info; | 
 | } | 
 |  | 
 | /* Display help.  */ | 
 |  | 
 | static void | 
 | pe_help (FILE *stream) | 
 | { | 
 |   fprintf (stream, _("\ | 
 | For PE files:\n\ | 
 |   header      Display the file header\n\ | 
 |   sections    Display the section headers\n\ | 
 | ")); | 
 | } | 
 |  | 
 | /* Return true if ABFD is handled.  */ | 
 |  | 
 | static int | 
 | pe_filter (bfd *abfd) | 
 | { | 
 |   return bfd_get_flavour (abfd) == bfd_target_coff_flavour; | 
 | } | 
 |  | 
 | /* Display the list of name (from TABLE) for FLAGS, using comma to | 
 |    separate them.  A name is displayed if FLAGS & VAL is not 0.  */ | 
 |  | 
 | static void | 
 | dump_flags (const struct xlat_table * table, unsigned int flags) | 
 | { | 
 |   unsigned int r = flags; | 
 |   bool first = true; | 
 |   const struct xlat_table *t; | 
 |  | 
 |   for (t = table; t->name; t++) | 
 |     if ((flags & t->val) != 0) | 
 |       { | 
 |         r &= ~t->val; | 
 |  | 
 |         if (first) | 
 |           first = false; | 
 |         else | 
 |           putchar (','); | 
 |         fputs (t->name, stdout); | 
 |       } | 
 |  | 
 |   /* Undecoded flags.  */ | 
 |   if (r != 0) | 
 |     { | 
 |       if (!first) | 
 |         putchar (','); | 
 |       printf (_("unknown: 0x%x"), r); | 
 |     } | 
 | } | 
 |  | 
 | /* Dump the file header.  */ | 
 |  | 
 | static void | 
 | dump_pe_file_header (bfd *                            abfd, | 
 | 		     struct external_PEI_filehdr *    fhdr, | 
 | 		     struct external_PEI_IMAGE_hdr *  ihdr) | 
 | { | 
 |   unsigned int data; | 
 |   unsigned long ldata; | 
 |   unsigned long ihdr_off = 0; | 
 |  | 
 |   if (fhdr == NULL) | 
 |     printf (_("\n  File header not present\n")); | 
 |   else | 
 |     { | 
 |       printf (_("\n  File Header (at offset 0):\n")); | 
 |  | 
 |       // The values of the following fields are normally fixed. | 
 |       // But we display them anyway, in case there are discrepancies. | 
 |  | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_cblp); | 
 |       printf (_("Bytes on Last Page:\t\t%d\n"), data); | 
 |  | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_cp); | 
 |       printf (_("Pages In File:\t\t\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_crlc); | 
 |       printf (_("Relocations:\t\t\t%d\n"), data); | 
 |  | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_cparhdr); | 
 |       printf (_("Size of header in paragraphs:\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_minalloc); | 
 |       printf (_("Min extra paragraphs needed:\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_maxalloc); | 
 |       printf (_("Max extra paragraphs needed:\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_ss); | 
 |       printf (_("Initial (relative) SS value:\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_sp); | 
 |       printf (_("Initial SP value:\t\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_csum); | 
 |       printf (_("Checksum:\t\t\t%#x\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_ip); | 
 |       printf (_("Initial IP value:\t\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_cs); | 
 |       printf (_("Initial (relative) CS value:\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_lfarlc); | 
 |       printf (_("File address of reloc table:\t%d\n"), data); | 
 |        | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_ovno); | 
 |       printf (_("Overlay number:\t\t\t%d\n"), data); | 
 |  | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_oemid); | 
 |       printf (_("OEM identifier:\t\t\t%d\n"), data); | 
 |    | 
 |       data = bfd_h_get_16 (abfd, fhdr->e_oeminfo); | 
 |       printf (_("OEM information:\t\t%#x\n"), data); | 
 |    | 
 |       ldata = bfd_h_get_32 (abfd, fhdr->e_lfanew); | 
 |       printf (_("File address of new exe header:\t%#lx\n"), ldata); | 
 |          | 
 |       /* Display the first string found in the stub. | 
 | 	 FIXME: Look for more than one string ? | 
 | 	 FIXME: Strictly speaking we may not have read the full stub, since | 
 | 	 it can be longer than the dos_message array in the PEI_fileheader | 
 | 	 structure.  */ | 
 |       const unsigned char * message = (const unsigned char *) fhdr->dos_message; | 
 |       unsigned int len = sizeof (fhdr->dos_message); | 
 |       unsigned int i; | 
 |       unsigned int seen_count = 0; | 
 |       unsigned int string_start = 0; | 
 |    | 
 |       for (i = 0; i < len; i++) | 
 | 	{ | 
 | 	  if (ISPRINT (message[i])) | 
 | 	    { | 
 | 	      if (string_start == 0) | 
 | 		string_start = i; | 
 | 	      ++ seen_count; | 
 | 	      if (seen_count > 4) | 
 | 		break; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      seen_count = string_start = 0; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (seen_count > 4) | 
 | 	{ | 
 | 	  printf (_("Stub message:\t\t\t")); | 
 | 	  while (string_start < len) | 
 | 	    { | 
 | 	      char c = message[string_start ++]; | 
 | 	      if (! ISPRINT (c)) | 
 | 		break; | 
 | 	      putchar (c); | 
 | 	    } | 
 | 	  putchar ('\n'); | 
 | 	} | 
 |  | 
 |       ihdr_off = (long) bfd_h_get_32 (abfd, fhdr->e_lfanew); | 
 |     } | 
 |  | 
 |   printf (_("\n  Image Header (at offset %#lx):\n"), ihdr_off); | 
 |  | 
 |   /* Note - we try to make this output use the same format as the output from -p. | 
 |      But since there are multiple headers to display and the order of the fields | 
 |      in the headers do not match the order of information displayed by -p, there | 
 |      are some discrepancies.  */ | 
 |  | 
 |   unsigned int machine = (int) bfd_h_get_16 (abfd, ihdr->f_magic); | 
 |   printf (_("Machine Number:\t\t\t%#x\t\t- %s\n"), machine, | 
 | 	  get_target_specific_info (machine)->name); | 
 |  | 
 |   printf (_("Number of sections:\t\t\%d\n"), (int) bfd_h_get_16 (abfd, ihdr->f_nscns)); | 
 |  | 
 |   long timedat = bfd_h_get_32 (abfd, ihdr->f_timdat); | 
 |   printf (_("Time/Date:\t\t\t%#08lx\t- "), timedat); | 
 |   if (timedat == 0) | 
 |     printf (_("not set\n")); | 
 |   else | 
 |     { | 
 |       /* Not correct on all platforms, but works on unix.  */ | 
 |       time_t t = timedat; | 
 |       fputs (ctime (&t), stdout); | 
 |     } | 
 |    | 
 |   printf (_("Symbol table offset:\t\t%#08lx\n"), | 
 | 	  (long) bfd_h_get_32 (abfd, ihdr->f_symptr)); | 
 |   printf (_("Number of symbols:\t\t\%ld\n"), | 
 | 	  (long) bfd_h_get_32 (abfd, ihdr->f_nsyms)); | 
 |  | 
 |   unsigned int opt_header_size = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr); | 
 |   printf (_("Optional header size:\t\t%#x\n"), opt_header_size); | 
 |  | 
 |   unsigned int flags = (int) bfd_h_get_16 (abfd, ihdr->f_flags); | 
 |   printf (_("Flags:\t\t\t\t0x%04x\t\t- "), flags); | 
 |   dump_flags (file_flag_xlat, flags); | 
 |   putchar ('\n'); | 
 |  | 
 |   if (opt_header_size == PEPAOUTSZ) | 
 |     { | 
 |       PEPAOUTHDR xhdr; | 
 |  | 
 |       printf (_("\n  Optional 64-bit AOUT Header (at offset %#lx):\n"), | 
 | 	      ihdr_off + sizeof (* ihdr)); | 
 |  | 
 |       // Fortunately, it appears that the size and layout of the | 
 |       // PEPAOUTHDR header is consistent across all architectures. | 
 |       if (bfd_seek (abfd, ihdr_off + sizeof (* ihdr), SEEK_SET) != 0 | 
 | 	  || bfd_read (&xhdr, sizeof (xhdr), abfd) != sizeof (xhdr)) | 
 | 	printf (_("error: unable to read AOUT and PE+ headers\n")); | 
 |       else | 
 | 	{ | 
 | 	  data = (int) bfd_h_get_16 (abfd, xhdr.standard.magic); | 
 | 	  printf (_("Magic:\t\t\t\t%x\t\t- %s\n"), data, | 
 | 		    data == 0x020b ? "PE32+" : _("Unknown")); | 
 | 	   | 
 | 	  printf (_("Version:\t\t\t%x\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.standard.vstamp)); | 
 |  | 
 | 	  printf (_("Text Size:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.tsize)); | 
 | 	  printf (_("Data Size:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.dsize)); | 
 | 	  printf (_("BSS Size:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.bsize)); | 
 | 	  printf (_("Entry Point:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.entry)); | 
 | 	  printf (_("Text Start:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.text_start)); | 
 | 	  /* There is no data_start field in the PE+ standard header.  */ | 
 |  | 
 | 	  printf (_("\n  Optional PE+ Header (at offset %#lx):\n"), | 
 | 		  ihdr_off + sizeof (* ihdr) + sizeof (xhdr.standard)); | 
 |  | 
 | 	  printf (_("Image Base:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.ImageBase)); | 
 | 	  printf (_("Section Alignment:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SectionAlignment)); | 
 | 	  printf (_("File Alignment:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.FileAlignment)); | 
 | 	  printf (_("Major OS Version:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MajorOperatingSystemVersion)); | 
 | 	  printf (_("Minor OS ersion:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MinorOperatingSystemVersion)); | 
 | 	  printf (_("Major Image Version:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MajorImageVersion)); | 
 | 	  printf (_("Minor Image Version:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MinorImageVersion)); | 
 | 	  printf (_("Major Subsystem Version:\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MajorSubsystemVersion)); | 
 | 	  printf (_("Minor Subsystem Version:\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MinorSubsystemVersion)); | 
 | 	  printf (_("Size Of Image:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfImage)); | 
 | 	  printf (_("Size Of Headers:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeaders)); | 
 | 	  printf (_("CheckSum:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.CheckSum)); | 
 | 	  printf (_("Subsystem:\t\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.Subsystem)); | 
 | 	  // FIXME: Decode the characteristics. | 
 | 	  printf (_("DllCharacteristics:\t\t%#x\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.DllCharacteristics)); | 
 | 	  printf (_("Size Of Stack Reserve:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackReserve)); | 
 | 	  printf (_("Size Of Stack Commit:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackCommit)); | 
 | 	  printf (_("Size Of Heap Reserve:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapReserve)); | 
 | 	  printf (_("Size Of Heap Commit:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapCommit)); | 
 | 	  printf (_("Loader Flags:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.LoaderFlags)); | 
 | 	  printf (_("Number Of Rva and Sizes:\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.NumberOfRvaAndSizes)); | 
 |  | 
 | 	  // FIXME: Decode the Data Directory. | 
 | 	} | 
 |     } | 
 |   else if (opt_header_size == AOUTSZ) | 
 |     { | 
 |       PEAOUTHDR xhdr; | 
 |  | 
 |       /* Different architectures have different sizes of AOUT header.  */ | 
 |       unsigned int aout_hdr_size = get_target_specific_info (machine)->aout_hdr_size; | 
 |  | 
 |       unsigned long off  = ihdr_off + sizeof (* ihdr); | 
 |       unsigned long size = sizeof (xhdr.standard); | 
 |  | 
 |       printf (_("\n  Optional 32-bit AOUT Header (at offset %#lx, size %d):\n"), | 
 | 	      off, aout_hdr_size); | 
 |  | 
 |       if (bfd_seek (abfd, off, SEEK_SET) != 0 | 
 | 	  || bfd_read (&xhdr.standard, size, abfd) != size) | 
 | 	printf (_("error: unable to seek to/read AOUT header\n")); | 
 |       else | 
 | 	{ | 
 | 	  data = (int) bfd_h_get_16 (abfd, xhdr.standard.magic); | 
 | 	  printf (_("Magic:\t\t\t\t%x\t\t- %s\n"), data, | 
 | 		    data == 0x010b ? "PE32" : _("Unknown")); | 
 | 	   | 
 | 	  printf (_("Version:\t\t\t%x\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.standard.vstamp)); | 
 |  | 
 | 	  printf (_("Text Size:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.tsize)); | 
 | 	  printf (_("Data Size:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.dsize)); | 
 | 	  printf (_("BSS Size:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.bsize)); | 
 | 	  printf (_("Entry Point:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.entry)); | 
 | 	  printf (_("Text Start:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.text_start)); | 
 | 	  printf (_("Data Start:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.standard.data_start)); | 
 | 	} | 
 |  | 
 |       off  = ihdr_off + sizeof (* ihdr) + aout_hdr_size; | 
 |       size = sizeof (xhdr) - sizeof (xhdr.standard); | 
 |  | 
 |       printf (_("\n  Optional PE Header (at offset %#lx):\n"), off); | 
 |  | 
 |       /* FIXME: Sanitizers might complain about reading more bytes than | 
 | 	 fit into the ImageBase field.  Find a way to solve this.  */ | 
 |       if (bfd_seek (abfd, off, SEEK_SET) != 0 | 
 | 	  || bfd_read (&xhdr.ImageBase, size, abfd) != size) | 
 | 	printf (_("error: unable to seek to/read PE header\n")); | 
 |       else | 
 | 	{ | 
 | 	  printf (_("Image Base:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.ImageBase)); | 
 | 	  printf (_("Section Alignment:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SectionAlignment)); | 
 | 	  printf (_("File Alignment:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.FileAlignment)); | 
 | 	  printf (_("Major OS Version:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MajorOperatingSystemVersion)); | 
 | 	  printf (_("Minor OS ersion:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MinorOperatingSystemVersion)); | 
 | 	  printf (_("Major Image Version:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MajorImageVersion)); | 
 | 	  printf (_("Minor Image Version:\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MinorImageVersion)); | 
 | 	  printf (_("Major Subsystem Version:\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MajorSubsystemVersion)); | 
 | 	  printf (_("Minor Subsystem Version:\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.MinorSubsystemVersion)); | 
 | 	  printf (_("Size Of Image:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfImage)); | 
 | 	  printf (_("Size Of Headers:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeaders)); | 
 | 	  printf (_("CheckSum:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.CheckSum)); | 
 | 	  printf (_("Subsystem:\t\t\t%d\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.Subsystem)); | 
 | 	  // FIXME: Decode the characteristics. | 
 | 	  printf (_("DllCharacteristics:\t\t%#x\n"), | 
 | 		  (int) bfd_h_get_16 (abfd, xhdr.DllCharacteristics)); | 
 | 	  printf (_("Size Of Stack Reserve:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackReserve)); | 
 | 	  printf (_("Size Of Stack Commit:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackCommit)); | 
 | 	  printf (_("Size Of Heap Reserve:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapReserve)); | 
 | 	  printf (_("Size Of Heap Commit:\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapCommit)); | 
 | 	  printf (_("Loader Flags:\t\t\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.LoaderFlags)); | 
 | 	  printf (_("Number Of Rva and Sizes:\t%#lx\n"), | 
 | 		  (long) bfd_h_get_32 (abfd, xhdr.NumberOfRvaAndSizes)); | 
 |  | 
 | 	  // FIXME: Decode the Data Directory. | 
 | 	} | 
 |     } | 
 |   else if (opt_header_size != 0) | 
 |     { | 
 |       printf (_("\nUnsupported size of Optional Header\n")); | 
 |     } | 
 |   else | 
 |     printf (_("\n  Optional header not present\n")); | 
 | } | 
 |  | 
 | /* Dump the sections header.  */ | 
 |  | 
 | static void | 
 | dump_pe_sections_header (bfd *                            abfd, | 
 | 			 struct external_PEI_filehdr *    fhdr, | 
 | 			 struct external_PEI_IMAGE_hdr *  ihdr) | 
 | { | 
 |   unsigned int opthdr = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr); | 
 |   unsigned int n_scns = (int) bfd_h_get_16 (abfd, ihdr->f_nscns); | 
 |   unsigned int off; | 
 |  | 
 |   /* The section header starts after the file, image and optional headers.  */   | 
 |   if (fhdr == NULL) | 
 |     off = sizeof (struct external_filehdr) + opthdr; | 
 |   else | 
 |     off = (int) bfd_h_get_16 (abfd, fhdr->e_lfanew) + sizeof (* ihdr) + opthdr; | 
 |  | 
 |   printf (_("\nSection headers (at offset 0x%08x):\n"), off); | 
 |  | 
 |   if (n_scns == 0) | 
 |     { | 
 |       printf (_("  No section headers\n")); | 
 |       return; | 
 |     } | 
 |   if (bfd_seek (abfd, off, SEEK_SET) != 0) | 
 |     { | 
 |       non_fatal (_("cannot seek to section headers start\n")); | 
 |       return; | 
 |     } | 
 |  | 
 |   /* We don't translate this string as it consists of field names.  */ | 
 |   if (wide_output) | 
 |     printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr   nrel nlnno   Flags\n"); | 
 |   else | 
 |     printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr   nrel nlnno\n"); | 
 |  | 
 |   unsigned int i; | 
 |   for (i = 0; i < n_scns; i++) | 
 |     { | 
 |       struct external_scnhdr scn; | 
 |       unsigned int flags; | 
 |  | 
 |       if (bfd_read (&scn, sizeof (scn), abfd) != sizeof (scn)) | 
 |         { | 
 |           non_fatal (_("cannot read section header")); | 
 |           return; | 
 |         } | 
 |  | 
 |       printf ("%2d %-8.8s %08x %08x %08x %08x %08x %08x %5d %5d", | 
 |               i + 1, scn.s_name, | 
 |               (unsigned int) bfd_h_get_32 (abfd, scn.s_paddr), | 
 |               (unsigned int) bfd_h_get_32 (abfd, scn.s_vaddr), | 
 |               (unsigned int) bfd_h_get_32 (abfd, scn.s_size), | 
 |               (unsigned int) bfd_h_get_32 (abfd, scn.s_scnptr), | 
 |               (unsigned int) bfd_h_get_32 (abfd, scn.s_relptr), | 
 |               (unsigned int) bfd_h_get_32 (abfd, scn.s_lnnoptr), | 
 |               (unsigned int) bfd_h_get_16 (abfd, scn.s_nreloc), | 
 |               (unsigned int) bfd_h_get_16 (abfd, scn.s_nlnno)); | 
 |  | 
 |       flags = bfd_h_get_32 (abfd, scn.s_flags); | 
 |       if (wide_output) | 
 | 	printf (_("   %08x "), flags); | 
 |       else | 
 | 	printf (_("\n            Flags: %08x: "), flags); | 
 |  | 
 |       if (flags != 0) | 
 |         { | 
 | 	  /* Skip the alignment bits.  */ | 
 | 	  flags &= ~ IMAGE_SCN_ALIGN_POWER_BIT_MASK; | 
 |           dump_flags (section_flag_xlat, flags); | 
 |         } | 
 |  | 
 |       putchar ('\n'); | 
 |     } | 
 | } | 
 |  | 
 | /* Handle a PE format file.  */ | 
 |  | 
 | static void | 
 | dump_pe (bfd *                            abfd, | 
 | 	 struct external_PEI_filehdr *    fhdr, | 
 | 	 struct external_PEI_IMAGE_hdr *  ihdr) | 
 | { | 
 |   if (options[OPT_FILE_HEADER].selected) | 
 |     dump_pe_file_header (abfd, fhdr, ihdr); | 
 |    | 
 |   if (options[OPT_SECTIONS].selected) | 
 |     dump_pe_sections_header (abfd, fhdr, ihdr); | 
 | } | 
 |  | 
 | /* Dump ABFD (according to the options[] array).  */ | 
 |  | 
 | static void | 
 | pe_dump_obj (bfd *abfd) | 
 | { | 
 |   struct external_PEI_filehdr fhdr; | 
 |  | 
 |   /* Read file header.  */ | 
 |   if (bfd_seek (abfd, 0, SEEK_SET) != 0 | 
 |       || bfd_read (&fhdr, sizeof (fhdr), abfd) != sizeof (fhdr)) | 
 |     { | 
 |       non_fatal (_("cannot seek to/read file header")); | 
 |       return; | 
 |     } | 
 |  | 
 |   unsigned short magic = bfd_h_get_16 (abfd, fhdr.e_magic); | 
 |  | 
 |   /* PE format executable files have a full external_PEI_filehdr structure | 
 |      at the start.  PE format object files just have an external_filehdr | 
 |      structure at the start.  */ | 
 |   if (magic == IMAGE_DOS_SIGNATURE) | 
 |     { | 
 |       unsigned int ihdr_offset = (int) bfd_h_get_16 (abfd, fhdr.e_lfanew); | 
 |  | 
 |       /* FIXME: We could reuse the fields in fhdr, but that might | 
 | 	 confuse various sanitization and memory checker tools.  */ | 
 |       struct external_PEI_IMAGE_hdr ihdr; | 
 |  | 
 |       if (bfd_seek (abfd, ihdr_offset, SEEK_SET) != 0 | 
 | 	  || bfd_read (&ihdr, sizeof (ihdr), abfd) != sizeof (ihdr)) | 
 | 	{ | 
 | 	  non_fatal (_("cannot seek to/read image header at offset %#x"), | 
 | 		     ihdr_offset); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       unsigned int signature = (int) bfd_h_get_16 (abfd, ihdr.nt_signature); | 
 |       if (signature != IMAGE_NT_SIGNATURE) | 
 | 	{ | 
 | 	  non_fatal ("file does not have an NT format signature: %#x", | 
 | 		     signature); | 
 | 	  return; | 
 | 	} | 
 |    | 
 |       dump_pe (abfd, &fhdr, &ihdr); | 
 |     } | 
 |   /* See if we recognise this particular PE object file.  */ | 
 |   else if (get_target_specific_info (magic)->machine_number) | 
 |     { | 
 |       struct external_filehdr ehdr; | 
 |  | 
 |       if (bfd_seek (abfd, 0, SEEK_SET) != 0 | 
 | 	  || bfd_read (&ehdr, sizeof (ehdr), abfd) != sizeof (ehdr)) | 
 | 	{ | 
 | 	  non_fatal (_("cannot seek to/read image header")); | 
 | 	  return; | 
 | 	} | 
 |  | 
 |       struct external_PEI_IMAGE_hdr ihdr; | 
 |       memcpy (&ihdr.f_magic, &ehdr, sizeof (ehdr)); | 
 |       dump_pe (abfd, NULL, &ihdr); | 
 |     } | 
 |   else | 
 |     { | 
 |       non_fatal ("unknown PE format binary - unsupported magic number: %#x", | 
 | 		 magic); | 
 |       return; | 
 |     } | 
 | } | 
 |  | 
 | /* Dump a PE file.  */ | 
 |  | 
 | static void | 
 | pe_dump (bfd *abfd) | 
 | { | 
 |   /* We rely on BFD to decide if the file is a core file.  Note that core | 
 |      files are only supported on native environment by BFD.  */ | 
 |   switch (bfd_get_format (abfd)) | 
 |     { | 
 |     case bfd_core: | 
 |       // FIXME: Handle PE format core files ? | 
 |       break; | 
 |     default: | 
 |       pe_dump_obj (abfd); | 
 |       break; | 
 |     } | 
 | } | 
 |  | 
 | /* Vector for pe.  */ | 
 |  | 
 | const struct objdump_private_desc objdump_private_desc_pe = | 
 | { | 
 |   pe_help, | 
 |   pe_filter, | 
 |   pe_dump, | 
 |   options | 
 | }; |