]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/od-pe.c
x86: Add NT_X86_SHSTK note
[thirdparty/binutils-gdb.git] / binutils / od-pe.c
CommitLineData
45b8517a
NC
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"
10d6a2b1 36#include "libiberty.h"
45b8517a
NC
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. */
53static 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. */
71struct 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
91struct xlat_table
92{
93 unsigned int val;
94 const char * name;
95};
96
97/* PE file flags. */
98static 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. */
120static 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
10d6a2b1
NC
145typedef 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
152const 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
226f9f4f
AM
195static const struct target_specific_info unknown_info =
196 { 0, "unknown", AOUTHDRSZ };
10d6a2b1
NC
197
198static const struct target_specific_info *
199get_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
226f9f4f 207 return &unknown_info;
10d6a2b1 208}
45b8517a
NC
209
210/* Display help. */
211
212static void
213pe_help (FILE *stream)
214{
215 fprintf (stream, _("\
216For 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
224static int
225pe_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
233static void
234dump_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
45b8517a
NC
261/* Dump the file header. */
262
263static void
264dump_pe_file_header (bfd * abfd,
265 struct external_PEI_filehdr * fhdr,
266 struct external_PEI_IMAGE_hdr * ihdr)
267{
10d6a2b1
NC
268 unsigned int data;
269 unsigned long ldata;
45b8517a
NC
270 unsigned long ihdr_off = 0;
271
10d6a2b1
NC
272 if (fhdr == NULL)
273 printf (_("\n File header not present\n"));
274 else
45b8517a 275 {
10d6a2b1
NC
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);
45b8517a 289
10d6a2b1
NC
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);
45b8517a 319
10d6a2b1
NC
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
45b8517a
NC
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 {
10d6a2b1 358 printf (_("Stub message:\t\t\t"));
45b8517a
NC
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
10d6a2b1
NC
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
45b8517a 379 unsigned int machine = (int) bfd_h_get_16 (abfd, ihdr->f_magic);
10d6a2b1
NC
380 printf (_("Machine Number:\t\t\t%#x\t\t- %s\n"), machine,
381 get_target_specific_info (machine)->name);
45b8517a 382
10d6a2b1 383 printf (_("Number of sections:\t\t\%d\n"), (int) bfd_h_get_16 (abfd, ihdr->f_nscns));
45b8517a
NC
384
385 long timedat = bfd_h_get_32 (abfd, ihdr->f_timdat);
10d6a2b1 386 printf (_("Time/Date:\t\t\t%#08lx\t- "), timedat);
45b8517a
NC
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;
226f9f4f 393 fputs (ctime (&t), stdout);
45b8517a 394 }
10d6a2b1
NC
395
396 printf (_("Symbol table offset:\t\t%#08lx\n"),
45b8517a 397 (long) bfd_h_get_32 (abfd, ihdr->f_symptr));
10d6a2b1 398 printf (_("Number of symbols:\t\t\%ld\n"),
45b8517a
NC
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);
10d6a2b1 402 printf (_("Optional header size:\t\t%#x\n"), opt_header_size);
45b8517a
NC
403
404 unsigned int flags = (int) bfd_h_get_16 (abfd, ihdr->f_flags);
10d6a2b1 405 printf (_("Flags:\t\t\t\t0x%04x\t\t- "), flags);
45b8517a
NC
406 dump_flags (file_flag_xlat, flags);
407 putchar ('\n');
408
409 if (opt_header_size == PEPAOUTSZ)
410 {
411 PEPAOUTHDR xhdr;
412
10d6a2b1 413 printf (_("\n Optional 64-bit AOUT Header (at offset %#lx):\n"),
45b8517a
NC
414 ihdr_off + sizeof (* ihdr));
415
10d6a2b1
NC
416 // Fortunately, it appears that the size and layout of the
417 // PEPAOUTHDR header is consistent across all architectures.
45b8517a 418 if (bfd_seek (abfd, ihdr_off + sizeof (* ihdr), SEEK_SET) != 0
226f9f4f 419 || bfd_read (&xhdr, sizeof (xhdr), abfd) != sizeof (xhdr))
10d6a2b1 420 printf (_("error: unable to read AOUT and PE+ headers\n"));
45b8517a
NC
421 else
422 {
10d6a2b1
NC
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.
45b8517a
NC
488 }
489 }
490 else if (opt_header_size == AOUTSZ)
491 {
492 PEAOUTHDR xhdr;
493
10d6a2b1
NC
494 /* Different architectures have different sizes of AOUT header. */
495 unsigned int aout_hdr_size = get_target_specific_info (machine)->aout_hdr_size;
45b8517a 496
10d6a2b1
NC
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
226f9f4f 504 || bfd_read (&xhdr.standard, size, abfd) != size)
10d6a2b1 505 printf (_("error: unable to seek to/read AOUT header\n"));
45b8517a
NC
506 else
507 {
10d6a2b1
NC
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
226f9f4f 537 || bfd_read (&xhdr.ImageBase, size, abfd) != size)
10d6a2b1
NC
538 printf (_("error: unable to seek to/read PE header\n"));
539 else
540 {
541 printf (_("Image Base:\t\t\t%#lx\n"),
45b8517a 542 (long) bfd_h_get_32 (abfd, xhdr.ImageBase));
10d6a2b1
NC
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.
45b8517a
NC
584 }
585 }
586 else if (opt_header_size != 0)
587 {
588 printf (_("\nUnsupported size of Optional Header\n"));
589 }
10d6a2b1
NC
590 else
591 printf (_("\n Optional header not present\n"));
45b8517a
NC
592}
593
594/* Dump the sections header. */
595
596static void
597dump_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
226f9f4f 636 if (bfd_read (&scn, sizeof (scn), abfd) != sizeof (scn))
45b8517a
NC
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
672static void
673dump_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
45b8517a
NC
684/* Dump ABFD (according to the options[] array). */
685
686static void
687pe_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
226f9f4f 693 || bfd_read (&fhdr, sizeof (fhdr), abfd) != sizeof (fhdr))
45b8517a
NC
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
226f9f4f 713 || bfd_read (&ihdr, sizeof (ihdr), abfd) != sizeof (ihdr))
45b8517a
NC
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
226f9f4f 728 dump_pe (abfd, &fhdr, &ihdr);
45b8517a 729 }
10d6a2b1
NC
730 /* See if we recognise this particular PE object file. */
731 else if (get_target_specific_info (magic)->machine_number)
45b8517a
NC
732 {
733 struct external_filehdr ehdr;
734
735 if (bfd_seek (abfd, 0, SEEK_SET) != 0
226f9f4f 736 || bfd_read (&ehdr, sizeof (ehdr), abfd) != sizeof (ehdr))
45b8517a
NC
737 {
738 non_fatal (_("cannot seek to/read image header"));
739 return;
740 }
741
742 struct external_PEI_IMAGE_hdr ihdr;
226f9f4f
AM
743 memcpy (&ihdr.f_magic, &ehdr, sizeof (ehdr));
744 dump_pe (abfd, NULL, &ihdr);
45b8517a
NC
745 }
746 else
747 {
10d6a2b1 748 non_fatal ("unknown PE format binary - unsupported magic number: %#x",
45b8517a
NC
749 magic);
750 return;
751 }
752}
753
754/* Dump a PE file. */
755
756static void
757pe_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
774const struct objdump_private_desc objdump_private_desc_pe =
775{
776 pe_help,
777 pe_filter,
778 pe_dump,
779 options
780};