xref: /netbsd-src/external/gpl3/binutils/dist/binutils/od-pe.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* od-pe.c -- dump information about a PE object file.
2    Copyright (C) 2011-2024 Free Software Foundation, Inc.
3    Written by Tristan Gingold, Adacore and Nick Clifton, Red Hat.
4 
5    This file is part of GNU Binutils.
6 
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3, or (at your option)
10    any later version.
11 
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21 
22 #include "sysdep.h"
23 #include <stddef.h>
24 #include <time.h>
25 #include "safe-ctype.h"
26 #include "bfd.h"
27 #include "objdump.h"
28 #include "bucomm.h"
29 #include "bfdlink.h"
30 #include "coff/internal.h"
31 #define L_LNNO_SIZE 4 /* FIXME: which value should we use ?  */
32 #include "coff/external.h"
33 #include "coff/pe.h"
34 #include "libcoff.h"
35 #include "libpei.h"
36 #include "libiberty.h"
37 
38 /* Index of the options in the options[] array.  */
39 #define OPT_FILE_HEADER 0
40 #define OPT_AOUT 1
41 #define OPT_SECTIONS 2
42 #define OPT_SYMS 3
43 #define OPT_RELOCS 4
44 #define OPT_LINENO 5
45 #define OPT_LOADER 6
46 #define OPT_EXCEPT 7
47 #define OPT_TYPCHK 8
48 #define OPT_TRACEBACK 9
49 #define OPT_TOC 10
50 #define OPT_LDINFO 11
51 
52 /* List of actions.  */
53 static struct objdump_private_option options[] =
54 {
55   { "header", 0 },
56   { "aout", 0 },
57   { "sections", 0 },
58   { "syms", 0 },
59   { "relocs", 0 },
60   { "lineno", 0 },
61   { "loader", 0 },
62   { "except", 0 },
63   { "typchk", 0 },
64   { "traceback", 0 },
65   { "toc", 0 },
66   { "ldinfo", 0 },
67   { NULL, 0 }
68 };
69 
70 /* Simplified section header.  */
71 struct pe_section
72 {
73   /* NUL terminated name.  */
74   char name[9];
75 
76   /* Section flags.  */
77   unsigned int flags;
78 
79   /* Offsets in file.  */
80   ufile_ptr scnptr;
81   ufile_ptr relptr;
82   ufile_ptr lnnoptr;
83 
84   /* Number of relocs and line numbers.  */
85   unsigned int nreloc;
86   unsigned int nlnno;
87 };
88 
89 /* Translation entry type.  The last entry must be {0, NULL}.  */
90 
91 struct xlat_table
92 {
93   unsigned int  val;
94   const char *  name;
95 };
96 
97 /* PE file flags.  */
98 static const struct xlat_table file_flag_xlat[] =
99 {
100   { IMAGE_FILE_RELOCS_STRIPPED,     "RELOCS STRIPPED"},
101   { IMAGE_FILE_EXECUTABLE_IMAGE,    "EXECUTABLE"},
102   { IMAGE_FILE_LINE_NUMS_STRIPPED,  "LINE NUMS STRIPPED"},
103   { IMAGE_FILE_LOCAL_SYMS_STRIPPED, "LOCAL SYMS STRIPPED"},
104   { IMAGE_FILE_AGGRESSIVE_WS_TRIM,  "AGGRESSIVE WS TRIM"},
105   { IMAGE_FILE_LARGE_ADDRESS_AWARE, "LARGE ADDRESS AWARE"},
106   { IMAGE_FILE_16BIT_MACHINE,       "16BIT MACHINE"},
107   { IMAGE_FILE_BYTES_REVERSED_LO,   "BYTES REVERSED LO"},
108   { IMAGE_FILE_32BIT_MACHINE,       "32BIT MACHINE"},
109   { IMAGE_FILE_DEBUG_STRIPPED,      "DEBUG STRIPPED"},
110   { IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP, "REMOVABLE RUN FROM SWAP"},
111   { IMAGE_FILE_NET_RUN_FROM_SWAP,   "NET RUN FROM SWAP"},
112   { IMAGE_FILE_SYSTEM,              "SYSTEM"},
113   { IMAGE_FILE_DLL,                 "DLL"},
114   { IMAGE_FILE_UP_SYSTEM_ONLY,      "UP SYSTEM ONLY"},
115   { IMAGE_FILE_BYTES_REVERSED_HI,   "BYTES REVERSED HI"},
116   { 0, NULL }
117 };
118 
119 /* PE section flags.  */
120 static const struct xlat_table section_flag_xlat[] =
121 {
122   { IMAGE_SCN_MEM_DISCARDABLE, "DISCARDABLE" },
123   { IMAGE_SCN_MEM_EXECUTE,     "EXECUTE" },
124   { IMAGE_SCN_MEM_READ,        "READ" },
125   { IMAGE_SCN_MEM_WRITE,       "WRITE" },
126   { IMAGE_SCN_TYPE_NO_PAD,     "NO PAD" },
127   { IMAGE_SCN_CNT_CODE,        "CODE" },
128   { IMAGE_SCN_CNT_INITIALIZED_DATA,   "INITIALIZED DATA" },
129   { IMAGE_SCN_CNT_UNINITIALIZED_DATA, "UNINITIALIZED DATA" },
130   { IMAGE_SCN_LNK_OTHER,       "OTHER" },
131   { IMAGE_SCN_LNK_INFO,        "INFO" },
132   { IMAGE_SCN_LNK_REMOVE,      "REMOVE" },
133   { IMAGE_SCN_LNK_COMDAT,      "COMDAT" },
134   { IMAGE_SCN_MEM_FARDATA,     "FARDATA" },
135   { IMAGE_SCN_MEM_PURGEABLE,   "PURGEABLE" },
136   { IMAGE_SCN_MEM_LOCKED,      "LOCKED" },
137   { IMAGE_SCN_MEM_PRELOAD,     "PRELOAD" },
138   { IMAGE_SCN_LNK_NRELOC_OVFL, "NRELOC OVFL" },
139   { IMAGE_SCN_MEM_NOT_CACHED,  "NOT CACHED" },
140   { IMAGE_SCN_MEM_NOT_PAGED,   "NOT PAGED" },
141   { IMAGE_SCN_MEM_SHARED,      "SHARED" },
142   { 0, NULL }
143 };
144 
145 typedef struct target_specific_info
146 {
147   unsigned int  machine_number;
148   const char *  name;
149   unsigned int  aout_hdr_size;
150 } target_specific_info;
151 
152 const struct target_specific_info targ_info[] =
153 {
154   { IMAGE_FILE_MACHINE_ALPHA, "ALPHA", 80 },
155   { IMAGE_FILE_MACHINE_ALPHA64, "ALPHA64", 80 },
156   { IMAGE_FILE_MACHINE_AM33, "AM33", AOUTHDRSZ },
157   { IMAGE_FILE_MACHINE_AMD64, "AMD64", AOUTHDRSZ },
158   { IMAGE_FILE_MACHINE_ARM, "ARM", AOUTHDRSZ },
159   { IMAGE_FILE_MACHINE_ARM64, "ARM64", AOUTHDRSZ },
160   { IMAGE_FILE_MACHINE_ARMNT, "ARM NT", AOUTHDRSZ },
161   { IMAGE_FILE_MACHINE_CEE, "CEE", AOUTHDRSZ },
162   { IMAGE_FILE_MACHINE_CEF, "CEF", AOUTHDRSZ },
163   { IMAGE_FILE_MACHINE_EBC, "EBC", AOUTHDRSZ },
164   { IMAGE_FILE_MACHINE_I386, "I386", AOUTHDRSZ },
165   { IMAGE_FILE_MACHINE_IA64, "IA64", 108 },
166   { IMAGE_FILE_MACHINE_LOONGARCH64, "LOONGARCH64", AOUTHDRSZ },
167   { IMAGE_FILE_MACHINE_M32R, "M32R", AOUTHDRSZ },
168   { IMAGE_FILE_MACHINE_M68K, "M68K", AOUTHDRSZ },
169   { IMAGE_FILE_MACHINE_MIPS16, "MIPS16", 56 },
170   { IMAGE_FILE_MACHINE_MIPSFPU, "MIPSFPU", 56 },
171   { IMAGE_FILE_MACHINE_MIPSFPU16, "MIPSFPU16", 56 },
172   { IMAGE_FILE_MACHINE_POWERPC, "POWERPC", 72 },
173   { IMAGE_FILE_MACHINE_POWERPCFP, "POWERPCFP", 72 },
174   { IMAGE_FILE_MACHINE_R10000, "R10000", AOUTHDRSZ },
175   { IMAGE_FILE_MACHINE_R3000, "R3000", AOUTHDRSZ },
176   { IMAGE_FILE_MACHINE_R4000, "R4000", AOUTHDRSZ },
177   { IMAGE_FILE_MACHINE_SH3, "SH3", AOUTHDRSZ },
178   { IMAGE_FILE_MACHINE_SH3DSP, "SH3DSP", AOUTHDRSZ },
179   { IMAGE_FILE_MACHINE_SH3E, "SH3E", AOUTHDRSZ },
180   { IMAGE_FILE_MACHINE_SH4, "SH4", AOUTHDRSZ },
181   { IMAGE_FILE_MACHINE_SH5, "SH5", AOUTHDRSZ },
182   { IMAGE_FILE_MACHINE_THUMB, "THUMB", AOUTHDRSZ },
183   { IMAGE_FILE_MACHINE_TRICORE, "TRICORE", AOUTHDRSZ },
184   { IMAGE_FILE_MACHINE_WCEMIPSV2, "WCEMIPSV2", AOUTHDRSZ },
185 
186   { 0x0093, "TI C4X", 28 },
187   { 0x00C1, "TI C4X", 28 },
188   { 0x00C2, "TI C4X", 28 },
189   { 0x0500, "SH (big endian)", AOUTHDRSZ },
190   { 0x0550, "SH (little endian)", AOUTHDRSZ },
191   { 0x0a00, "ARM", AOUTHDRSZ },
192   { 0x0b00, "MCore", AOUTHDRSZ }
193 };
194 
195 static const struct target_specific_info unknown_info =
196   { 0, "unknown", AOUTHDRSZ };
197 
198 static const struct target_specific_info *
get_target_specific_info(unsigned int machine)199 get_target_specific_info (unsigned int machine)
200 {
201   unsigned int i;
202 
203   for (i = ARRAY_SIZE (targ_info); i--;)
204     if (targ_info[i].machine_number == machine)
205       return targ_info + i;
206 
207   return &unknown_info;
208 }
209 
210 /* Display help.  */
211 
212 static void
pe_help(FILE * stream)213 pe_help (FILE *stream)
214 {
215   fprintf (stream, _("\
216 For PE files:\n\
217   header      Display the file header\n\
218   sections    Display the section headers\n\
219 "));
220 }
221 
222 /* Return true if ABFD is handled.  */
223 
224 static int
pe_filter(bfd * abfd)225 pe_filter (bfd *abfd)
226 {
227   return bfd_get_flavour (abfd) == bfd_target_coff_flavour;
228 }
229 
230 /* Display the list of name (from TABLE) for FLAGS, using comma to
231    separate them.  A name is displayed if FLAGS & VAL is not 0.  */
232 
233 static void
dump_flags(const struct xlat_table * table,unsigned int flags)234 dump_flags (const struct xlat_table * table, unsigned int flags)
235 {
236   unsigned int r = flags;
237   bool first = true;
238   const struct xlat_table *t;
239 
240   for (t = table; t->name; t++)
241     if ((flags & t->val) != 0)
242       {
243         r &= ~t->val;
244 
245         if (first)
246           first = false;
247         else
248           putchar (',');
249         fputs (t->name, stdout);
250       }
251 
252   /* Undecoded flags.  */
253   if (r != 0)
254     {
255       if (!first)
256         putchar (',');
257       printf (_("unknown: 0x%x"), r);
258     }
259 }
260 
261 /* Dump the file header.  */
262 
263 static void
dump_pe_file_header(bfd * abfd,struct external_PEI_filehdr * fhdr,struct external_PEI_IMAGE_hdr * ihdr)264 dump_pe_file_header (bfd *                            abfd,
265 		     struct external_PEI_filehdr *    fhdr,
266 		     struct external_PEI_IMAGE_hdr *  ihdr)
267 {
268   unsigned int data;
269   unsigned long ldata;
270   unsigned long ihdr_off = 0;
271 
272   if (fhdr == NULL)
273     printf (_("\n  File header not present\n"));
274   else
275     {
276       printf (_("\n  File Header (at offset 0):\n"));
277 
278       // The values of the following fields are normally fixed.
279       // But we display them anyway, in case there are discrepancies.
280 
281       data = bfd_h_get_16 (abfd, fhdr->e_cblp);
282       printf (_("Bytes on Last Page:\t\t%d\n"), data);
283 
284       data = bfd_h_get_16 (abfd, fhdr->e_cp);
285       printf (_("Pages In File:\t\t\t%d\n"), data);
286 
287       data = bfd_h_get_16 (abfd, fhdr->e_crlc);
288       printf (_("Relocations:\t\t\t%d\n"), data);
289 
290       data = bfd_h_get_16 (abfd, fhdr->e_cparhdr);
291       printf (_("Size of header in paragraphs:\t%d\n"), data);
292 
293       data = bfd_h_get_16 (abfd, fhdr->e_minalloc);
294       printf (_("Min extra paragraphs needed:\t%d\n"), data);
295 
296       data = bfd_h_get_16 (abfd, fhdr->e_maxalloc);
297       printf (_("Max extra paragraphs needed:\t%d\n"), data);
298 
299       data = bfd_h_get_16 (abfd, fhdr->e_ss);
300       printf (_("Initial (relative) SS value:\t%d\n"), data);
301 
302       data = bfd_h_get_16 (abfd, fhdr->e_sp);
303       printf (_("Initial SP value:\t\t%d\n"), data);
304 
305       data = bfd_h_get_16 (abfd, fhdr->e_csum);
306       printf (_("Checksum:\t\t\t%#x\n"), data);
307 
308       data = bfd_h_get_16 (abfd, fhdr->e_ip);
309       printf (_("Initial IP value:\t\t%d\n"), data);
310 
311       data = bfd_h_get_16 (abfd, fhdr->e_cs);
312       printf (_("Initial (relative) CS value:\t%d\n"), data);
313 
314       data = bfd_h_get_16 (abfd, fhdr->e_lfarlc);
315       printf (_("File address of reloc table:\t%d\n"), data);
316 
317       data = bfd_h_get_16 (abfd, fhdr->e_ovno);
318       printf (_("Overlay number:\t\t\t%d\n"), data);
319 
320       data = bfd_h_get_16 (abfd, fhdr->e_oemid);
321       printf (_("OEM identifier:\t\t\t%d\n"), data);
322 
323       data = bfd_h_get_16 (abfd, fhdr->e_oeminfo);
324       printf (_("OEM information:\t\t%#x\n"), data);
325 
326       ldata = bfd_h_get_32 (abfd, fhdr->e_lfanew);
327       printf (_("File address of new exe header:\t%#lx\n"), ldata);
328 
329       /* Display the first string found in the stub.
330 	 FIXME: Look for more than one string ?
331 	 FIXME: Strictly speaking we may not have read the full stub, since
332 	 it can be longer than the dos_message array in the PEI_fileheader
333 	 structure.  */
334       const unsigned char * message = (const unsigned char *) fhdr->dos_message;
335       unsigned int len = sizeof (fhdr->dos_message);
336       unsigned int i;
337       unsigned int seen_count = 0;
338       unsigned int string_start = 0;
339 
340       for (i = 0; i < len; i++)
341 	{
342 	  if (ISPRINT (message[i]))
343 	    {
344 	      if (string_start == 0)
345 		string_start = i;
346 	      ++ seen_count;
347 	      if (seen_count > 4)
348 		break;
349 	    }
350 	  else
351 	    {
352 	      seen_count = string_start = 0;
353 	    }
354 	}
355 
356       if (seen_count > 4)
357 	{
358 	  printf (_("Stub message:\t\t\t"));
359 	  while (string_start < len)
360 	    {
361 	      char c = message[string_start ++];
362 	      if (! ISPRINT (c))
363 		break;
364 	      putchar (c);
365 	    }
366 	  putchar ('\n');
367 	}
368 
369       ihdr_off = (long) bfd_h_get_32 (abfd, fhdr->e_lfanew);
370     }
371 
372   printf (_("\n  Image Header (at offset %#lx):\n"), ihdr_off);
373 
374   /* Note - we try to make this output use the same format as the output from -p.
375      But since there are multiple headers to display and the order of the fields
376      in the headers do not match the order of information displayed by -p, there
377      are some discrepancies.  */
378 
379   unsigned int machine = (int) bfd_h_get_16 (abfd, ihdr->f_magic);
380   printf (_("Machine Number:\t\t\t%#x\t\t- %s\n"), machine,
381 	  get_target_specific_info (machine)->name);
382 
383   printf (_("Number of sections:\t\t\%d\n"), (int) bfd_h_get_16 (abfd, ihdr->f_nscns));
384 
385   long timedat = bfd_h_get_32 (abfd, ihdr->f_timdat);
386   printf (_("Time/Date:\t\t\t%#08lx\t- "), timedat);
387   if (timedat == 0)
388     printf (_("not set\n"));
389   else
390     {
391       /* Not correct on all platforms, but works on unix.  */
392       time_t t = timedat;
393       fputs (ctime (&t), stdout);
394     }
395 
396   printf (_("Symbol table offset:\t\t%#08lx\n"),
397 	  (long) bfd_h_get_32 (abfd, ihdr->f_symptr));
398   printf (_("Number of symbols:\t\t\%ld\n"),
399 	  (long) bfd_h_get_32 (abfd, ihdr->f_nsyms));
400 
401   unsigned int opt_header_size = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr);
402   printf (_("Optional header size:\t\t%#x\n"), opt_header_size);
403 
404   unsigned int flags = (int) bfd_h_get_16 (abfd, ihdr->f_flags);
405   printf (_("Flags:\t\t\t\t0x%04x\t\t- "), flags);
406   dump_flags (file_flag_xlat, flags);
407   putchar ('\n');
408 
409   if (opt_header_size == PEPAOUTSZ)
410     {
411       PEPAOUTHDR xhdr;
412 
413       printf (_("\n  Optional 64-bit AOUT Header (at offset %#lx):\n"),
414 	      ihdr_off + sizeof (* ihdr));
415 
416       // Fortunately, it appears that the size and layout of the
417       // PEPAOUTHDR header is consistent across all architectures.
418       if (bfd_seek (abfd, ihdr_off + sizeof (* ihdr), SEEK_SET) != 0
419 	  || bfd_read (&xhdr, sizeof (xhdr), abfd) != sizeof (xhdr))
420 	printf (_("error: unable to read AOUT and PE+ headers\n"));
421       else
422 	{
423 	  data = (int) bfd_h_get_16 (abfd, xhdr.standard.magic);
424 	  printf (_("Magic:\t\t\t\t%x\t\t- %s\n"), data,
425 		    data == 0x020b ? "PE32+" : _("Unknown"));
426 
427 	  printf (_("Version:\t\t\t%x\n"),
428 		  (int) bfd_h_get_16 (abfd, xhdr.standard.vstamp));
429 
430 	  printf (_("Text Size:\t\t\t%#lx\n"),
431 		  (long) bfd_h_get_32 (abfd, xhdr.standard.tsize));
432 	  printf (_("Data Size:\t\t\t%#lx\n"),
433 		  (long) bfd_h_get_32 (abfd, xhdr.standard.dsize));
434 	  printf (_("BSS Size:\t\t\t%#lx\n"),
435 		  (long) bfd_h_get_32 (abfd, xhdr.standard.bsize));
436 	  printf (_("Entry Point:\t\t\t%#lx\n"),
437 		  (long) bfd_h_get_32 (abfd, xhdr.standard.entry));
438 	  printf (_("Text Start:\t\t\t%#lx\n"),
439 		  (long) bfd_h_get_32 (abfd, xhdr.standard.text_start));
440 	  /* There is no data_start field in the PE+ standard header.  */
441 
442 	  printf (_("\n  Optional PE+ Header (at offset %#lx):\n"),
443 		  ihdr_off + sizeof (* ihdr) + sizeof (xhdr.standard));
444 
445 	  printf (_("Image Base:\t\t\t%#lx\n"),
446 		  (long) bfd_h_get_32 (abfd, xhdr.ImageBase));
447 	  printf (_("Section Alignment:\t\t%#lx\n"),
448 		  (long) bfd_h_get_32 (abfd, xhdr.SectionAlignment));
449 	  printf (_("File Alignment:\t\t\t%#lx\n"),
450 		  (long) bfd_h_get_32 (abfd, xhdr.FileAlignment));
451 	  printf (_("Major OS Version:\t\t%d\n"),
452 		  (int) bfd_h_get_16 (abfd, xhdr.MajorOperatingSystemVersion));
453 	  printf (_("Minor OS ersion:\t\t%d\n"),
454 		  (int) bfd_h_get_16 (abfd, xhdr.MinorOperatingSystemVersion));
455 	  printf (_("Major Image Version:\t\t%d\n"),
456 		  (int) bfd_h_get_16 (abfd, xhdr.MajorImageVersion));
457 	  printf (_("Minor Image Version:\t\t%d\n"),
458 		  (int) bfd_h_get_16 (abfd, xhdr.MinorImageVersion));
459 	  printf (_("Major Subsystem Version:\t%d\n"),
460 		  (int) bfd_h_get_16 (abfd, xhdr.MajorSubsystemVersion));
461 	  printf (_("Minor Subsystem Version:\t%d\n"),
462 		  (int) bfd_h_get_16 (abfd, xhdr.MinorSubsystemVersion));
463 	  printf (_("Size Of Image:\t\t\t%#lx\n"),
464 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfImage));
465 	  printf (_("Size Of Headers:\t\t%#lx\n"),
466 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeaders));
467 	  printf (_("CheckSum:\t\t\t%#lx\n"),
468 		  (long) bfd_h_get_32 (abfd, xhdr.CheckSum));
469 	  printf (_("Subsystem:\t\t\t%d\n"),
470 		  (int) bfd_h_get_16 (abfd, xhdr.Subsystem));
471 	  // FIXME: Decode the characteristics.
472 	  printf (_("DllCharacteristics:\t\t%#x\n"),
473 		  (int) bfd_h_get_16 (abfd, xhdr.DllCharacteristics));
474 	  printf (_("Size Of Stack Reserve:\t\t%#lx\n"),
475 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackReserve));
476 	  printf (_("Size Of Stack Commit:\t\t%#lx\n"),
477 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackCommit));
478 	  printf (_("Size Of Heap Reserve:\t\t%#lx\n"),
479 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapReserve));
480 	  printf (_("Size Of Heap Commit:\t\t%#lx\n"),
481 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapCommit));
482 	  printf (_("Loader Flags:\t\t\t%#lx\n"),
483 		  (long) bfd_h_get_32 (abfd, xhdr.LoaderFlags));
484 	  printf (_("Number Of Rva and Sizes:\t%#lx\n"),
485 		  (long) bfd_h_get_32 (abfd, xhdr.NumberOfRvaAndSizes));
486 
487 	  // FIXME: Decode the Data Directory.
488 	}
489     }
490   else if (opt_header_size == AOUTSZ)
491     {
492       PEAOUTHDR xhdr;
493 
494       /* Different architectures have different sizes of AOUT header.  */
495       unsigned int aout_hdr_size = get_target_specific_info (machine)->aout_hdr_size;
496 
497       unsigned long off  = ihdr_off + sizeof (* ihdr);
498       unsigned long size = sizeof (xhdr.standard);
499 
500       printf (_("\n  Optional 32-bit AOUT Header (at offset %#lx, size %d):\n"),
501 	      off, aout_hdr_size);
502 
503       if (bfd_seek (abfd, off, SEEK_SET) != 0
504 	  || bfd_read (&xhdr.standard, size, abfd) != size)
505 	printf (_("error: unable to seek to/read AOUT header\n"));
506       else
507 	{
508 	  data = (int) bfd_h_get_16 (abfd, xhdr.standard.magic);
509 	  printf (_("Magic:\t\t\t\t%x\t\t- %s\n"), data,
510 		    data == 0x010b ? "PE32" : _("Unknown"));
511 
512 	  printf (_("Version:\t\t\t%x\n"),
513 		  (int) bfd_h_get_16 (abfd, xhdr.standard.vstamp));
514 
515 	  printf (_("Text Size:\t\t\t%#lx\n"),
516 		  (long) bfd_h_get_32 (abfd, xhdr.standard.tsize));
517 	  printf (_("Data Size:\t\t\t%#lx\n"),
518 		  (long) bfd_h_get_32 (abfd, xhdr.standard.dsize));
519 	  printf (_("BSS Size:\t\t\t%#lx\n"),
520 		  (long) bfd_h_get_32 (abfd, xhdr.standard.bsize));
521 	  printf (_("Entry Point:\t\t\t%#lx\n"),
522 		  (long) bfd_h_get_32 (abfd, xhdr.standard.entry));
523 	  printf (_("Text Start:\t\t\t%#lx\n"),
524 		  (long) bfd_h_get_32 (abfd, xhdr.standard.text_start));
525 	  printf (_("Data Start:\t\t\t%#lx\n"),
526 		  (long) bfd_h_get_32 (abfd, xhdr.standard.data_start));
527 	}
528 
529       off  = ihdr_off + sizeof (* ihdr) + aout_hdr_size;
530       size = sizeof (xhdr) - sizeof (xhdr.standard);
531 
532       printf (_("\n  Optional PE Header (at offset %#lx):\n"), off);
533 
534       /* FIXME: Sanitizers might complain about reading more bytes than
535 	 fit into the ImageBase field.  Find a way to solve this.  */
536       if (bfd_seek (abfd, off, SEEK_SET) != 0
537 	  || bfd_read (&xhdr.ImageBase, size, abfd) != size)
538 	printf (_("error: unable to seek to/read PE header\n"));
539       else
540 	{
541 	  printf (_("Image Base:\t\t\t%#lx\n"),
542 		  (long) bfd_h_get_32 (abfd, xhdr.ImageBase));
543 	  printf (_("Section Alignment:\t\t%#lx\n"),
544 		  (long) bfd_h_get_32 (abfd, xhdr.SectionAlignment));
545 	  printf (_("File Alignment:\t\t\t%#lx\n"),
546 		  (long) bfd_h_get_32 (abfd, xhdr.FileAlignment));
547 	  printf (_("Major OS Version:\t\t%d\n"),
548 		  (int) bfd_h_get_16 (abfd, xhdr.MajorOperatingSystemVersion));
549 	  printf (_("Minor OS ersion:\t\t%d\n"),
550 		  (int) bfd_h_get_16 (abfd, xhdr.MinorOperatingSystemVersion));
551 	  printf (_("Major Image Version:\t\t%d\n"),
552 		  (int) bfd_h_get_16 (abfd, xhdr.MajorImageVersion));
553 	  printf (_("Minor Image Version:\t\t%d\n"),
554 		  (int) bfd_h_get_16 (abfd, xhdr.MinorImageVersion));
555 	  printf (_("Major Subsystem Version:\t%d\n"),
556 		  (int) bfd_h_get_16 (abfd, xhdr.MajorSubsystemVersion));
557 	  printf (_("Minor Subsystem Version:\t%d\n"),
558 		  (int) bfd_h_get_16 (abfd, xhdr.MinorSubsystemVersion));
559 	  printf (_("Size Of Image:\t\t\t%#lx\n"),
560 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfImage));
561 	  printf (_("Size Of Headers:\t\t%#lx\n"),
562 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeaders));
563 	  printf (_("CheckSum:\t\t\t%#lx\n"),
564 		  (long) bfd_h_get_32 (abfd, xhdr.CheckSum));
565 	  printf (_("Subsystem:\t\t\t%d\n"),
566 		  (int) bfd_h_get_16 (abfd, xhdr.Subsystem));
567 	  // FIXME: Decode the characteristics.
568 	  printf (_("DllCharacteristics:\t\t%#x\n"),
569 		  (int) bfd_h_get_16 (abfd, xhdr.DllCharacteristics));
570 	  printf (_("Size Of Stack Reserve:\t\t%#lx\n"),
571 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackReserve));
572 	  printf (_("Size Of Stack Commit:\t\t%#lx\n"),
573 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackCommit));
574 	  printf (_("Size Of Heap Reserve:\t\t%#lx\n"),
575 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapReserve));
576 	  printf (_("Size Of Heap Commit:\t\t%#lx\n"),
577 		  (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapCommit));
578 	  printf (_("Loader Flags:\t\t\t%#lx\n"),
579 		  (long) bfd_h_get_32 (abfd, xhdr.LoaderFlags));
580 	  printf (_("Number Of Rva and Sizes:\t%#lx\n"),
581 		  (long) bfd_h_get_32 (abfd, xhdr.NumberOfRvaAndSizes));
582 
583 	  // FIXME: Decode the Data Directory.
584 	}
585     }
586   else if (opt_header_size != 0)
587     {
588       printf (_("\nUnsupported size of Optional Header\n"));
589     }
590   else
591     printf (_("\n  Optional header not present\n"));
592 }
593 
594 /* Dump the sections header.  */
595 
596 static void
dump_pe_sections_header(bfd * abfd,struct external_PEI_filehdr * fhdr,struct external_PEI_IMAGE_hdr * ihdr)597 dump_pe_sections_header (bfd *                            abfd,
598 			 struct external_PEI_filehdr *    fhdr,
599 			 struct external_PEI_IMAGE_hdr *  ihdr)
600 {
601   unsigned int opthdr = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr);
602   unsigned int n_scns = (int) bfd_h_get_16 (abfd, ihdr->f_nscns);
603   unsigned int off;
604 
605   /* The section header starts after the file, image and optional headers.  */
606   if (fhdr == NULL)
607     off = sizeof (struct external_filehdr) + opthdr;
608   else
609     off = (int) bfd_h_get_16 (abfd, fhdr->e_lfanew) + sizeof (* ihdr) + opthdr;
610 
611   printf (_("\nSection headers (at offset 0x%08x):\n"), off);
612 
613   if (n_scns == 0)
614     {
615       printf (_("  No section headers\n"));
616       return;
617     }
618   if (bfd_seek (abfd, off, SEEK_SET) != 0)
619     {
620       non_fatal (_("cannot seek to section headers start\n"));
621       return;
622     }
623 
624   /* We don't translate this string as it consists of field names.  */
625   if (wide_output)
626     printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr   nrel nlnno   Flags\n");
627   else
628     printf (" # Name     paddr    vaddr    size     scnptr   relptr   lnnoptr   nrel nlnno\n");
629 
630   unsigned int i;
631   for (i = 0; i < n_scns; i++)
632     {
633       struct external_scnhdr scn;
634       unsigned int flags;
635 
636       if (bfd_read (&scn, sizeof (scn), abfd) != sizeof (scn))
637         {
638           non_fatal (_("cannot read section header"));
639           return;
640         }
641 
642       printf ("%2d %-8.8s %08x %08x %08x %08x %08x %08x %5d %5d",
643               i + 1, scn.s_name,
644               (unsigned int) bfd_h_get_32 (abfd, scn.s_paddr),
645               (unsigned int) bfd_h_get_32 (abfd, scn.s_vaddr),
646               (unsigned int) bfd_h_get_32 (abfd, scn.s_size),
647               (unsigned int) bfd_h_get_32 (abfd, scn.s_scnptr),
648               (unsigned int) bfd_h_get_32 (abfd, scn.s_relptr),
649               (unsigned int) bfd_h_get_32 (abfd, scn.s_lnnoptr),
650               (unsigned int) bfd_h_get_16 (abfd, scn.s_nreloc),
651               (unsigned int) bfd_h_get_16 (abfd, scn.s_nlnno));
652 
653       flags = bfd_h_get_32 (abfd, scn.s_flags);
654       if (wide_output)
655 	printf (_("   %08x "), flags);
656       else
657 	printf (_("\n            Flags: %08x: "), flags);
658 
659       if (flags != 0)
660         {
661 	  /* Skip the alignment bits.  */
662 	  flags &= ~ IMAGE_SCN_ALIGN_POWER_BIT_MASK;
663           dump_flags (section_flag_xlat, flags);
664         }
665 
666       putchar ('\n');
667     }
668 }
669 
670 /* Handle a PE format file.  */
671 
672 static void
dump_pe(bfd * abfd,struct external_PEI_filehdr * fhdr,struct external_PEI_IMAGE_hdr * ihdr)673 dump_pe (bfd *                            abfd,
674 	 struct external_PEI_filehdr *    fhdr,
675 	 struct external_PEI_IMAGE_hdr *  ihdr)
676 {
677   if (options[OPT_FILE_HEADER].selected)
678     dump_pe_file_header (abfd, fhdr, ihdr);
679 
680   if (options[OPT_SECTIONS].selected)
681     dump_pe_sections_header (abfd, fhdr, ihdr);
682 }
683 
684 /* Dump ABFD (according to the options[] array).  */
685 
686 static void
pe_dump_obj(bfd * abfd)687 pe_dump_obj (bfd *abfd)
688 {
689   struct external_PEI_filehdr fhdr;
690 
691   /* Read file header.  */
692   if (bfd_seek (abfd, 0, SEEK_SET) != 0
693       || bfd_read (&fhdr, sizeof (fhdr), abfd) != sizeof (fhdr))
694     {
695       non_fatal (_("cannot seek to/read file header"));
696       return;
697     }
698 
699   unsigned short magic = bfd_h_get_16 (abfd, fhdr.e_magic);
700 
701   /* PE format executable files have a full external_PEI_filehdr structure
702      at the start.  PE format object files just have an external_filehdr
703      structure at the start.  */
704   if (magic == IMAGE_DOS_SIGNATURE)
705     {
706       unsigned int ihdr_offset = (int) bfd_h_get_16 (abfd, fhdr.e_lfanew);
707 
708       /* FIXME: We could reuse the fields in fhdr, but that might
709 	 confuse various sanitization and memory checker tools.  */
710       struct external_PEI_IMAGE_hdr ihdr;
711 
712       if (bfd_seek (abfd, ihdr_offset, SEEK_SET) != 0
713 	  || bfd_read (&ihdr, sizeof (ihdr), abfd) != sizeof (ihdr))
714 	{
715 	  non_fatal (_("cannot seek to/read image header at offset %#x"),
716 		     ihdr_offset);
717 	  return;
718 	}
719 
720       unsigned int signature = (int) bfd_h_get_16 (abfd, ihdr.nt_signature);
721       if (signature != IMAGE_NT_SIGNATURE)
722 	{
723 	  non_fatal ("file does not have an NT format signature: %#x",
724 		     signature);
725 	  return;
726 	}
727 
728       dump_pe (abfd, &fhdr, &ihdr);
729     }
730   /* See if we recognise this particular PE object file.  */
731   else if (get_target_specific_info (magic)->machine_number)
732     {
733       struct external_filehdr ehdr;
734 
735       if (bfd_seek (abfd, 0, SEEK_SET) != 0
736 	  || bfd_read (&ehdr, sizeof (ehdr), abfd) != sizeof (ehdr))
737 	{
738 	  non_fatal (_("cannot seek to/read image header"));
739 	  return;
740 	}
741 
742       struct external_PEI_IMAGE_hdr ihdr;
743       memcpy (&ihdr.f_magic, &ehdr, sizeof (ehdr));
744       dump_pe (abfd, NULL, &ihdr);
745     }
746   else
747     {
748       non_fatal ("unknown PE format binary - unsupported magic number: %#x",
749 		 magic);
750       return;
751     }
752 }
753 
754 /* Dump a PE file.  */
755 
756 static void
pe_dump(bfd * abfd)757 pe_dump (bfd *abfd)
758 {
759   /* We rely on BFD to decide if the file is a core file.  Note that core
760      files are only supported on native environment by BFD.  */
761   switch (bfd_get_format (abfd))
762     {
763     case bfd_core:
764       // FIXME: Handle PE format core files ?
765       break;
766     default:
767       pe_dump_obj (abfd);
768       break;
769     }
770 }
771 
772 /* Vector for pe.  */
773 
774 const struct objdump_private_desc objdump_private_desc_pe =
775 {
776   pe_help,
777   pe_filter,
778   pe_dump,
779   options
780 };
781