]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - binutils/od-pe.c
Add note about adding ChangeLog.git to src-release.sh
[thirdparty/binutils-gdb.git] / binutils / od-pe.c
1 /* od-pe.c -- dump information about a PE object file.
2 Copyright (C) 2011-2023 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 = { 0, "unknown", AOUTHDRSZ };
196
197 static const struct target_specific_info *
198 get_target_specific_info (unsigned int machine)
199 {
200 unsigned int i;
201
202 for (i = ARRAY_SIZE (targ_info); i--;)
203 if (targ_info[i].machine_number == machine)
204 return targ_info + i;
205
206 return & unknown_info;
207 }
208
209 /* Display help. */
210
211 static void
212 pe_help (FILE *stream)
213 {
214 fprintf (stream, _("\
215 For PE files:\n\
216 header Display the file header\n\
217 sections Display the section headers\n\
218 "));
219 }
220
221 /* Return true if ABFD is handled. */
222
223 static int
224 pe_filter (bfd *abfd)
225 {
226 return bfd_get_flavour (abfd) == bfd_target_coff_flavour;
227 }
228
229 /* Display the list of name (from TABLE) for FLAGS, using comma to
230 separate them. A name is displayed if FLAGS & VAL is not 0. */
231
232 static void
233 dump_flags (const struct xlat_table * table, unsigned int flags)
234 {
235 unsigned int r = flags;
236 bool first = true;
237 const struct xlat_table *t;
238
239 for (t = table; t->name; t++)
240 if ((flags & t->val) != 0)
241 {
242 r &= ~t->val;
243
244 if (first)
245 first = false;
246 else
247 putchar (',');
248 fputs (t->name, stdout);
249 }
250
251 /* Undecoded flags. */
252 if (r != 0)
253 {
254 if (!first)
255 putchar (',');
256 printf (_("unknown: 0x%x"), r);
257 }
258 }
259
260 /* Dump the file header. */
261
262 static void
263 dump_pe_file_header (bfd * abfd,
264 struct external_PEI_filehdr * fhdr,
265 struct external_PEI_IMAGE_hdr * ihdr)
266 {
267 unsigned int data;
268 unsigned long ldata;
269 unsigned long ihdr_off = 0;
270
271 if (fhdr == NULL)
272 printf (_("\n File header not present\n"));
273 else
274 {
275 printf (_("\n File Header (at offset 0):\n"));
276
277 // The values of the following fields are normally fixed.
278 // But we display them anyway, in case there are discrepancies.
279
280 data = bfd_h_get_16 (abfd, fhdr->e_cblp);
281 printf (_("Bytes on Last Page:\t\t%d\n"), data);
282
283 data = bfd_h_get_16 (abfd, fhdr->e_cp);
284 printf (_("Pages In File:\t\t\t%d\n"), data);
285
286 data = bfd_h_get_16 (abfd, fhdr->e_crlc);
287 printf (_("Relocations:\t\t\t%d\n"), data);
288
289 data = bfd_h_get_16 (abfd, fhdr->e_cparhdr);
290 printf (_("Size of header in paragraphs:\t%d\n"), data);
291
292 data = bfd_h_get_16 (abfd, fhdr->e_minalloc);
293 printf (_("Min extra paragraphs needed:\t%d\n"), data);
294
295 data = bfd_h_get_16 (abfd, fhdr->e_maxalloc);
296 printf (_("Max extra paragraphs needed:\t%d\n"), data);
297
298 data = bfd_h_get_16 (abfd, fhdr->e_ss);
299 printf (_("Initial (relative) SS value:\t%d\n"), data);
300
301 data = bfd_h_get_16 (abfd, fhdr->e_sp);
302 printf (_("Initial SP value:\t\t%d\n"), data);
303
304 data = bfd_h_get_16 (abfd, fhdr->e_csum);
305 printf (_("Checksum:\t\t\t%#x\n"), data);
306
307 data = bfd_h_get_16 (abfd, fhdr->e_ip);
308 printf (_("Initial IP value:\t\t%d\n"), data);
309
310 data = bfd_h_get_16 (abfd, fhdr->e_cs);
311 printf (_("Initial (relative) CS value:\t%d\n"), data);
312
313 data = bfd_h_get_16 (abfd, fhdr->e_lfarlc);
314 printf (_("File address of reloc table:\t%d\n"), data);
315
316 data = bfd_h_get_16 (abfd, fhdr->e_ovno);
317 printf (_("Overlay number:\t\t\t%d\n"), data);
318
319 data = bfd_h_get_16 (abfd, fhdr->e_oemid);
320 printf (_("OEM identifier:\t\t\t%d\n"), data);
321
322 data = bfd_h_get_16 (abfd, fhdr->e_oeminfo);
323 printf (_("OEM information:\t\t%#x\n"), data);
324
325 ldata = bfd_h_get_32 (abfd, fhdr->e_lfanew);
326 printf (_("File address of new exe header:\t%#lx\n"), ldata);
327
328 /* Display the first string found in the stub.
329 FIXME: Look for more than one string ?
330 FIXME: Strictly speaking we may not have read the full stub, since
331 it can be longer than the dos_message array in the PEI_fileheader
332 structure. */
333 const unsigned char * message = (const unsigned char *) fhdr->dos_message;
334 unsigned int len = sizeof (fhdr->dos_message);
335 unsigned int i;
336 unsigned int seen_count = 0;
337 unsigned int string_start = 0;
338
339 for (i = 0; i < len; i++)
340 {
341 if (ISPRINT (message[i]))
342 {
343 if (string_start == 0)
344 string_start = i;
345 ++ seen_count;
346 if (seen_count > 4)
347 break;
348 }
349 else
350 {
351 seen_count = string_start = 0;
352 }
353 }
354
355 if (seen_count > 4)
356 {
357 printf (_("Stub message:\t\t\t"));
358 while (string_start < len)
359 {
360 char c = message[string_start ++];
361 if (! ISPRINT (c))
362 break;
363 putchar (c);
364 }
365 putchar ('\n');
366 }
367
368 ihdr_off = (long) bfd_h_get_32 (abfd, fhdr->e_lfanew);
369 }
370
371 printf (_("\n Image Header (at offset %#lx):\n"), ihdr_off);
372
373 /* Note - we try to make this output use the same format as the output from -p.
374 But since there are multiple headers to display and the order of the fields
375 in the headers do not match the order of information displayed by -p, there
376 are some discrepancies. */
377
378 unsigned int machine = (int) bfd_h_get_16 (abfd, ihdr->f_magic);
379 printf (_("Machine Number:\t\t\t%#x\t\t- %s\n"), machine,
380 get_target_specific_info (machine)->name);
381
382 printf (_("Number of sections:\t\t\%d\n"), (int) bfd_h_get_16 (abfd, ihdr->f_nscns));
383
384 long timedat = bfd_h_get_32 (abfd, ihdr->f_timdat);
385 printf (_("Time/Date:\t\t\t%#08lx\t- "), timedat);
386 if (timedat == 0)
387 printf (_("not set\n"));
388 else
389 {
390 /* Not correct on all platforms, but works on unix. */
391 time_t t = timedat;
392 fputs (ctime (& t), stdout);
393 }
394
395 printf (_("Symbol table offset:\t\t%#08lx\n"),
396 (long) bfd_h_get_32 (abfd, ihdr->f_symptr));
397 printf (_("Number of symbols:\t\t\%ld\n"),
398 (long) bfd_h_get_32 (abfd, ihdr->f_nsyms));
399
400 unsigned int opt_header_size = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr);
401 printf (_("Optional header size:\t\t%#x\n"), opt_header_size);
402
403 unsigned int flags = (int) bfd_h_get_16 (abfd, ihdr->f_flags);
404 printf (_("Flags:\t\t\t\t0x%04x\t\t- "), flags);
405 dump_flags (file_flag_xlat, flags);
406 putchar ('\n');
407
408 if (opt_header_size == PEPAOUTSZ)
409 {
410 PEPAOUTHDR xhdr;
411
412 printf (_("\n Optional 64-bit AOUT Header (at offset %#lx):\n"),
413 ihdr_off + sizeof (* ihdr));
414
415 // Fortunately, it appears that the size and layout of the
416 // PEPAOUTHDR header is consistent across all architectures.
417 if (bfd_seek (abfd, ihdr_off + sizeof (* ihdr), SEEK_SET) != 0
418 || bfd_bread (& xhdr, sizeof (xhdr), abfd) != sizeof (xhdr))
419 printf (_("error: unable to read AOUT and PE+ headers\n"));
420 else
421 {
422 data = (int) bfd_h_get_16 (abfd, xhdr.standard.magic);
423 printf (_("Magic:\t\t\t\t%x\t\t- %s\n"), data,
424 data == 0x020b ? "PE32+" : _("Unknown"));
425
426 printf (_("Version:\t\t\t%x\n"),
427 (int) bfd_h_get_16 (abfd, xhdr.standard.vstamp));
428
429 printf (_("Text Size:\t\t\t%#lx\n"),
430 (long) bfd_h_get_32 (abfd, xhdr.standard.tsize));
431 printf (_("Data Size:\t\t\t%#lx\n"),
432 (long) bfd_h_get_32 (abfd, xhdr.standard.dsize));
433 printf (_("BSS Size:\t\t\t%#lx\n"),
434 (long) bfd_h_get_32 (abfd, xhdr.standard.bsize));
435 printf (_("Entry Point:\t\t\t%#lx\n"),
436 (long) bfd_h_get_32 (abfd, xhdr.standard.entry));
437 printf (_("Text Start:\t\t\t%#lx\n"),
438 (long) bfd_h_get_32 (abfd, xhdr.standard.text_start));
439 /* There is no data_start field in the PE+ standard header. */
440
441 printf (_("\n Optional PE+ Header (at offset %#lx):\n"),
442 ihdr_off + sizeof (* ihdr) + sizeof (xhdr.standard));
443
444 printf (_("Image Base:\t\t\t%#lx\n"),
445 (long) bfd_h_get_32 (abfd, xhdr.ImageBase));
446 printf (_("Section Alignment:\t\t%#lx\n"),
447 (long) bfd_h_get_32 (abfd, xhdr.SectionAlignment));
448 printf (_("File Alignment:\t\t\t%#lx\n"),
449 (long) bfd_h_get_32 (abfd, xhdr.FileAlignment));
450 printf (_("Major OS Version:\t\t%d\n"),
451 (int) bfd_h_get_16 (abfd, xhdr.MajorOperatingSystemVersion));
452 printf (_("Minor OS ersion:\t\t%d\n"),
453 (int) bfd_h_get_16 (abfd, xhdr.MinorOperatingSystemVersion));
454 printf (_("Major Image Version:\t\t%d\n"),
455 (int) bfd_h_get_16 (abfd, xhdr.MajorImageVersion));
456 printf (_("Minor Image Version:\t\t%d\n"),
457 (int) bfd_h_get_16 (abfd, xhdr.MinorImageVersion));
458 printf (_("Major Subsystem Version:\t%d\n"),
459 (int) bfd_h_get_16 (abfd, xhdr.MajorSubsystemVersion));
460 printf (_("Minor Subsystem Version:\t%d\n"),
461 (int) bfd_h_get_16 (abfd, xhdr.MinorSubsystemVersion));
462 printf (_("Size Of Image:\t\t\t%#lx\n"),
463 (long) bfd_h_get_32 (abfd, xhdr.SizeOfImage));
464 printf (_("Size Of Headers:\t\t%#lx\n"),
465 (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeaders));
466 printf (_("CheckSum:\t\t\t%#lx\n"),
467 (long) bfd_h_get_32 (abfd, xhdr.CheckSum));
468 printf (_("Subsystem:\t\t\t%d\n"),
469 (int) bfd_h_get_16 (abfd, xhdr.Subsystem));
470 // FIXME: Decode the characteristics.
471 printf (_("DllCharacteristics:\t\t%#x\n"),
472 (int) bfd_h_get_16 (abfd, xhdr.DllCharacteristics));
473 printf (_("Size Of Stack Reserve:\t\t%#lx\n"),
474 (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackReserve));
475 printf (_("Size Of Stack Commit:\t\t%#lx\n"),
476 (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackCommit));
477 printf (_("Size Of Heap Reserve:\t\t%#lx\n"),
478 (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapReserve));
479 printf (_("Size Of Heap Commit:\t\t%#lx\n"),
480 (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapCommit));
481 printf (_("Loader Flags:\t\t\t%#lx\n"),
482 (long) bfd_h_get_32 (abfd, xhdr.LoaderFlags));
483 printf (_("Number Of Rva and Sizes:\t%#lx\n"),
484 (long) bfd_h_get_32 (abfd, xhdr.NumberOfRvaAndSizes));
485
486 // FIXME: Decode the Data Directory.
487 }
488 }
489 else if (opt_header_size == AOUTSZ)
490 {
491 PEAOUTHDR xhdr;
492
493 /* Different architectures have different sizes of AOUT header. */
494 unsigned int aout_hdr_size = get_target_specific_info (machine)->aout_hdr_size;
495
496 unsigned long off = ihdr_off + sizeof (* ihdr);
497 unsigned long size = sizeof (xhdr.standard);
498
499 printf (_("\n Optional 32-bit AOUT Header (at offset %#lx, size %d):\n"),
500 off, aout_hdr_size);
501
502 if (bfd_seek (abfd, off, SEEK_SET) != 0
503 || bfd_bread (& xhdr.standard, size, abfd) != size)
504 printf (_("error: unable to seek to/read AOUT header\n"));
505 else
506 {
507 data = (int) bfd_h_get_16 (abfd, xhdr.standard.magic);
508 printf (_("Magic:\t\t\t\t%x\t\t- %s\n"), data,
509 data == 0x010b ? "PE32" : _("Unknown"));
510
511 printf (_("Version:\t\t\t%x\n"),
512 (int) bfd_h_get_16 (abfd, xhdr.standard.vstamp));
513
514 printf (_("Text Size:\t\t\t%#lx\n"),
515 (long) bfd_h_get_32 (abfd, xhdr.standard.tsize));
516 printf (_("Data Size:\t\t\t%#lx\n"),
517 (long) bfd_h_get_32 (abfd, xhdr.standard.dsize));
518 printf (_("BSS Size:\t\t\t%#lx\n"),
519 (long) bfd_h_get_32 (abfd, xhdr.standard.bsize));
520 printf (_("Entry Point:\t\t\t%#lx\n"),
521 (long) bfd_h_get_32 (abfd, xhdr.standard.entry));
522 printf (_("Text Start:\t\t\t%#lx\n"),
523 (long) bfd_h_get_32 (abfd, xhdr.standard.text_start));
524 printf (_("Data Start:\t\t\t%#lx\n"),
525 (long) bfd_h_get_32 (abfd, xhdr.standard.data_start));
526 }
527
528 off = ihdr_off + sizeof (* ihdr) + aout_hdr_size;
529 size = sizeof (xhdr) - sizeof (xhdr.standard);
530
531 printf (_("\n Optional PE Header (at offset %#lx):\n"), off);
532
533 /* FIXME: Sanitizers might complain about reading more bytes than
534 fit into the ImageBase field. Find a way to solve this. */
535 if (bfd_seek (abfd, off, SEEK_SET) != 0
536 || bfd_bread (& xhdr.ImageBase, size, abfd) != size)
537 printf (_("error: unable to seek to/read PE header\n"));
538 else
539 {
540 printf (_("Image Base:\t\t\t%#lx\n"),
541 (long) bfd_h_get_32 (abfd, xhdr.ImageBase));
542 printf (_("Section Alignment:\t\t%#lx\n"),
543 (long) bfd_h_get_32 (abfd, xhdr.SectionAlignment));
544 printf (_("File Alignment:\t\t\t%#lx\n"),
545 (long) bfd_h_get_32 (abfd, xhdr.FileAlignment));
546 printf (_("Major OS Version:\t\t%d\n"),
547 (int) bfd_h_get_16 (abfd, xhdr.MajorOperatingSystemVersion));
548 printf (_("Minor OS ersion:\t\t%d\n"),
549 (int) bfd_h_get_16 (abfd, xhdr.MinorOperatingSystemVersion));
550 printf (_("Major Image Version:\t\t%d\n"),
551 (int) bfd_h_get_16 (abfd, xhdr.MajorImageVersion));
552 printf (_("Minor Image Version:\t\t%d\n"),
553 (int) bfd_h_get_16 (abfd, xhdr.MinorImageVersion));
554 printf (_("Major Subsystem Version:\t%d\n"),
555 (int) bfd_h_get_16 (abfd, xhdr.MajorSubsystemVersion));
556 printf (_("Minor Subsystem Version:\t%d\n"),
557 (int) bfd_h_get_16 (abfd, xhdr.MinorSubsystemVersion));
558 printf (_("Size Of Image:\t\t\t%#lx\n"),
559 (long) bfd_h_get_32 (abfd, xhdr.SizeOfImage));
560 printf (_("Size Of Headers:\t\t%#lx\n"),
561 (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeaders));
562 printf (_("CheckSum:\t\t\t%#lx\n"),
563 (long) bfd_h_get_32 (abfd, xhdr.CheckSum));
564 printf (_("Subsystem:\t\t\t%d\n"),
565 (int) bfd_h_get_16 (abfd, xhdr.Subsystem));
566 // FIXME: Decode the characteristics.
567 printf (_("DllCharacteristics:\t\t%#x\n"),
568 (int) bfd_h_get_16 (abfd, xhdr.DllCharacteristics));
569 printf (_("Size Of Stack Reserve:\t\t%#lx\n"),
570 (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackReserve));
571 printf (_("Size Of Stack Commit:\t\t%#lx\n"),
572 (long) bfd_h_get_32 (abfd, xhdr.SizeOfStackCommit));
573 printf (_("Size Of Heap Reserve:\t\t%#lx\n"),
574 (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapReserve));
575 printf (_("Size Of Heap Commit:\t\t%#lx\n"),
576 (long) bfd_h_get_32 (abfd, xhdr.SizeOfHeapCommit));
577 printf (_("Loader Flags:\t\t\t%#lx\n"),
578 (long) bfd_h_get_32 (abfd, xhdr.LoaderFlags));
579 printf (_("Number Of Rva and Sizes:\t%#lx\n"),
580 (long) bfd_h_get_32 (abfd, xhdr.NumberOfRvaAndSizes));
581
582 // FIXME: Decode the Data Directory.
583 }
584 }
585 else if (opt_header_size != 0)
586 {
587 printf (_("\nUnsupported size of Optional Header\n"));
588 }
589 else
590 printf (_("\n Optional header not present\n"));
591 }
592
593 /* Dump the sections header. */
594
595 static void
596 dump_pe_sections_header (bfd * abfd,
597 struct external_PEI_filehdr * fhdr,
598 struct external_PEI_IMAGE_hdr * ihdr)
599 {
600 unsigned int opthdr = (int) bfd_h_get_16 (abfd, ihdr->f_opthdr);
601 unsigned int n_scns = (int) bfd_h_get_16 (abfd, ihdr->f_nscns);
602 unsigned int off;
603
604 /* The section header starts after the file, image and optional headers. */
605 if (fhdr == NULL)
606 off = sizeof (struct external_filehdr) + opthdr;
607 else
608 off = (int) bfd_h_get_16 (abfd, fhdr->e_lfanew) + sizeof (* ihdr) + opthdr;
609
610 printf (_("\nSection headers (at offset 0x%08x):\n"), off);
611
612 if (n_scns == 0)
613 {
614 printf (_(" No section headers\n"));
615 return;
616 }
617 if (bfd_seek (abfd, off, SEEK_SET) != 0)
618 {
619 non_fatal (_("cannot seek to section headers start\n"));
620 return;
621 }
622
623 /* We don't translate this string as it consists of field names. */
624 if (wide_output)
625 printf (" # Name paddr vaddr size scnptr relptr lnnoptr nrel nlnno Flags\n");
626 else
627 printf (" # Name paddr vaddr size scnptr relptr lnnoptr nrel nlnno\n");
628
629 unsigned int i;
630 for (i = 0; i < n_scns; i++)
631 {
632 struct external_scnhdr scn;
633 unsigned int flags;
634
635 if (bfd_bread (& scn, sizeof (scn), abfd) != sizeof (scn))
636 {
637 non_fatal (_("cannot read section header"));
638 return;
639 }
640
641 printf ("%2d %-8.8s %08x %08x %08x %08x %08x %08x %5d %5d",
642 i + 1, scn.s_name,
643 (unsigned int) bfd_h_get_32 (abfd, scn.s_paddr),
644 (unsigned int) bfd_h_get_32 (abfd, scn.s_vaddr),
645 (unsigned int) bfd_h_get_32 (abfd, scn.s_size),
646 (unsigned int) bfd_h_get_32 (abfd, scn.s_scnptr),
647 (unsigned int) bfd_h_get_32 (abfd, scn.s_relptr),
648 (unsigned int) bfd_h_get_32 (abfd, scn.s_lnnoptr),
649 (unsigned int) bfd_h_get_16 (abfd, scn.s_nreloc),
650 (unsigned int) bfd_h_get_16 (abfd, scn.s_nlnno));
651
652 flags = bfd_h_get_32 (abfd, scn.s_flags);
653 if (wide_output)
654 printf (_(" %08x "), flags);
655 else
656 printf (_("\n Flags: %08x: "), flags);
657
658 if (flags != 0)
659 {
660 /* Skip the alignment bits. */
661 flags &= ~ IMAGE_SCN_ALIGN_POWER_BIT_MASK;
662 dump_flags (section_flag_xlat, flags);
663 }
664
665 putchar ('\n');
666 }
667 }
668
669 /* Handle a PE format file. */
670
671 static void
672 dump_pe (bfd * abfd,
673 struct external_PEI_filehdr * fhdr,
674 struct external_PEI_IMAGE_hdr * ihdr)
675 {
676 if (options[OPT_FILE_HEADER].selected)
677 dump_pe_file_header (abfd, fhdr, ihdr);
678
679 if (options[OPT_SECTIONS].selected)
680 dump_pe_sections_header (abfd, fhdr, ihdr);
681 }
682
683 /* Dump ABFD (according to the options[] array). */
684
685 static void
686 pe_dump_obj (bfd *abfd)
687 {
688 struct external_PEI_filehdr fhdr;
689
690 /* Read file header. */
691 if (bfd_seek (abfd, 0, SEEK_SET) != 0
692 || bfd_bread (& fhdr, sizeof (fhdr), abfd) != sizeof (fhdr))
693 {
694 non_fatal (_("cannot seek to/read file header"));
695 return;
696 }
697
698 unsigned short magic = bfd_h_get_16 (abfd, fhdr.e_magic);
699
700 /* PE format executable files have a full external_PEI_filehdr structure
701 at the start. PE format object files just have an external_filehdr
702 structure at the start. */
703 if (magic == IMAGE_DOS_SIGNATURE)
704 {
705 unsigned int ihdr_offset = (int) bfd_h_get_16 (abfd, fhdr.e_lfanew);
706
707 /* FIXME: We could reuse the fields in fhdr, but that might
708 confuse various sanitization and memory checker tools. */
709 struct external_PEI_IMAGE_hdr ihdr;
710
711 if (bfd_seek (abfd, ihdr_offset, SEEK_SET) != 0
712 || bfd_bread (& ihdr, sizeof (ihdr), abfd) != sizeof (ihdr))
713 {
714 non_fatal (_("cannot seek to/read image header at offset %#x"),
715 ihdr_offset);
716 return;
717 }
718
719 unsigned int signature = (int) bfd_h_get_16 (abfd, ihdr.nt_signature);
720 if (signature != IMAGE_NT_SIGNATURE)
721 {
722 non_fatal ("file does not have an NT format signature: %#x",
723 signature);
724 return;
725 }
726
727 dump_pe (abfd, & fhdr, & ihdr);
728 }
729 /* See if we recognise this particular PE object file. */
730 else if (get_target_specific_info (magic)->machine_number)
731 {
732 struct external_filehdr ehdr;
733
734 if (bfd_seek (abfd, 0, SEEK_SET) != 0
735 || bfd_bread (& ehdr, sizeof (ehdr), abfd) != sizeof (ehdr))
736 {
737 non_fatal (_("cannot seek to/read image header"));
738 return;
739 }
740
741 struct external_PEI_IMAGE_hdr ihdr;
742 memcpy (& ihdr.f_magic, & ehdr, sizeof (ehdr));
743 dump_pe (abfd, NULL, & ihdr);
744 }
745 else
746 {
747 non_fatal ("unknown PE format binary - unsupported magic number: %#x",
748 magic);
749 return;
750 }
751 }
752
753 /* Dump a PE file. */
754
755 static void
756 pe_dump (bfd *abfd)
757 {
758 /* We rely on BFD to decide if the file is a core file. Note that core
759 files are only supported on native environment by BFD. */
760 switch (bfd_get_format (abfd))
761 {
762 case bfd_core:
763 // FIXME: Handle PE format core files ?
764 break;
765 default:
766 pe_dump_obj (abfd);
767 break;
768 }
769 }
770
771 /* Vector for pe. */
772
773 const struct objdump_private_desc objdump_private_desc_pe =
774 {
775 pe_help,
776 pe_filter,
777 pe_dump,
778 options
779 };