]>
Commit | Line | Data |
---|---|---|
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. */ | |
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 | ||
10d6a2b1 NC |
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 | ||
226f9f4f AM |
195 | static const struct target_specific_info unknown_info = |
196 | { 0, "unknown", AOUTHDRSZ }; | |
10d6a2b1 NC |
197 | |
198 | static const struct target_specific_info * | |
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 | ||
226f9f4f | 207 | return &unknown_info; |
10d6a2b1 | 208 | } |
45b8517a NC |
209 | |
210 | /* Display help. */ | |
211 | ||
212 | static void | |
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 | |
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 | |
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 | ||
45b8517a NC |
261 | /* Dump the file header. */ |
262 | ||
263 | static void | |
264 | dump_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 | ||
596 | static void | |
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 | ||
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 | ||
672 | static void | |
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 | ||
45b8517a NC |
684 | /* Dump ABFD (according to the options[] array). */ |
685 | ||
686 | static void | |
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 | |
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 | ||
756 | static void | |
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 | }; |