2 * pedump.c: Dumps the contents of an extended PE/COFF file
5 * Miguel de Icaza (miguel@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
17 #include "mono-endian.h"
19 #include <mono/metadata/class.h>
20 #include <mono/metadata/debug-helpers.h>
21 #include <mono/metadata/tokentype.h>
22 #include <mono/metadata/appdomain.h>
23 #include <mono/metadata/assembly.h>
24 #include <mono/metadata/metadata-internals.h>
25 #include <mono/metadata/class-internals.h>
26 #include <mono/metadata/verify-internals.h>
27 #include <mono/metadata/marshal.h>
28 #include "mono/utils/mono-digest.h"
29 #include <mono/utils/mono-mmap.h>
30 #include <sys/types.h>
36 gboolean dump_data
= TRUE
;
37 gboolean verify_pe
= FALSE
;
38 gboolean verify_metadata
= FALSE
;
39 gboolean verify_code
= FALSE
;
40 gboolean verify_partial_md
= FALSE
;
44 hex_dump (const char *buffer, int base, int count)
48 for (i = 0; i < count; i++){
50 printf ("\n0x%08x: ", (unsigned char) base + i);
52 printf ("%02x ", (unsigned char) (buffer [i]));
58 hex8 (const char *label
, unsigned char x
)
60 printf ("\t%s: 0x%02x\n", label
, (unsigned char) x
);
64 hex16 (const char *label
, guint16 x
)
66 printf ("\t%s: 0x%04x\n", label
, x
);
70 hex32 (const char *label
, guint32 x
)
72 printf ("\t%s: 0x%08x\n", label
, x
);
76 dump_coff_header (MonoCOFFHeader
*coff
)
78 printf ("\nCOFF Header:\n");
79 hex16 (" Machine", coff
->coff_machine
);
80 hex16 (" Sections", coff
->coff_sections
);
81 hex32 (" Time stamp", coff
->coff_time
);
82 hex32 ("Pointer to Symbol Table", coff
->coff_symptr
);
83 hex32 (" Symbol Count", coff
->coff_symcount
);
84 hex16 (" Optional Header Size", coff
->coff_opt_header_size
);
85 hex16 (" Characteristics", coff
->coff_attributes
);
90 dump_pe_header (MonoPEHeader
*pe
)
92 printf ("\nPE Header:\n");
93 hex16 (" Magic (0x010b)", pe
->pe_magic
);
94 hex8 (" LMajor (6)", pe
->pe_major
);
95 hex8 (" LMinor (0)", pe
->pe_minor
);
96 hex32 (" Code Size", pe
->pe_code_size
);
97 hex32 (" Initialized Data Size", pe
->pe_data_size
);
98 hex32 ("Uninitialized Data Size", pe
->pe_uninit_data_size
);
99 hex32 (" Entry Point RVA", pe
->pe_rva_entry_point
);
100 hex32 (" Code Base RVA", pe
->pe_rva_code_base
);
101 hex32 (" Data Base RVA", pe
->pe_rva_data_base
);
106 dump_nt_header (MonoPEHeaderNT
*nt
)
108 printf ("\nNT Header:\n");
110 hex32 (" Image Base (0x400000)", nt
->pe_image_base
);
111 hex32 ("Section Alignment (8192)", nt
->pe_section_align
);
112 hex32 (" File Align (512/4096)", nt
->pe_file_alignment
);
113 hex16 (" OS Major (4)", nt
->pe_os_major
);
114 hex16 (" OS Minor (0)", nt
->pe_os_minor
);
115 hex16 (" User Major (0)", nt
->pe_user_major
);
116 hex16 (" User Minor (0)", nt
->pe_user_minor
);
117 hex16 (" Subsys major (4)", nt
->pe_subsys_major
);
118 hex16 (" Subsys minor (0)", nt
->pe_subsys_minor
);
119 hex32 (" Reserverd", nt
->pe_reserved_1
);
120 hex32 (" Image Size", nt
->pe_image_size
);
121 hex32 (" Header Size", nt
->pe_header_size
);
122 hex32 (" Checksum (0)", nt
->pe_checksum
);
123 hex16 (" Subsystem", nt
->pe_subsys_required
);
124 hex16 (" DLL Flags (0)", nt
->pe_dll_flags
);
125 hex32 (" Stack Reserve Size (1M)", nt
->pe_stack_reserve
);
126 hex32 ("Stack commit Size (4096)", nt
->pe_stack_commit
);
127 hex32 (" Heap Reserve Size (1M)", nt
->pe_heap_reserve
);
128 hex32 (" Heap Commit Size (4096)", nt
->pe_heap_commit
);
129 hex32 (" Loader flags (0x1)", nt
->pe_loader_flags
);
130 hex32 (" Data Directories (16)", nt
->pe_data_dir_count
);
134 dent (const char *label
, MonoPEDirEntry de
)
136 printf ("\t%s: 0x%08x [0x%08x]\n", label
, de
.rva
, de
.size
);
140 dump_blob (const char *desc
, const char* p
, guint32 size
)
150 for (i
= 0; i
< size
; ++i
) {
153 printf (" %02X", p
[i
] & 0xFF);
159 dump_public_key (MonoImage
*m
)
164 p
= mono_image_get_public_key (m
, &size
);
165 dump_blob ("\nPublic key:", p
, size
);
169 dump_strong_name (MonoImage
*m
)
174 p
= mono_image_get_strong_name (m
, &size
);
175 dump_blob ("\nStrong name:", p
, size
);
179 dump_datadir (MonoPEDatadir
*dd
)
181 printf ("\nData directories:\n");
182 dent (" Export Table", dd
->pe_export_table
);
183 dent (" Import Table", dd
->pe_import_table
);
184 dent (" Resource Table", dd
->pe_resource_table
);
185 dent (" Exception Table", dd
->pe_exception_table
);
186 dent ("Certificate Table", dd
->pe_certificate_table
);
187 dent (" Reloc Table", dd
->pe_reloc_table
);
188 dent (" Debug", dd
->pe_debug
);
189 dent (" Copyright", dd
->pe_copyright
);
190 dent (" Global Ptr", dd
->pe_global_ptr
);
191 dent (" TLS Table", dd
->pe_tls_table
);
192 dent ("Load Config Table", dd
->pe_load_config_table
);
193 dent (" Bound Import", dd
->pe_bound_import
);
194 dent (" IAT", dd
->pe_iat
);
195 dent ("Delay Import Desc", dd
->pe_delay_import_desc
);
196 dent (" CLI Header", dd
->pe_cli_header
);
200 dump_dotnet_header (MonoDotNetHeader
*header
)
202 dump_coff_header (&header
->coff
);
203 dump_pe_header (&header
->pe
);
204 dump_nt_header (&header
->nt
);
205 dump_datadir (&header
->datadir
);
209 dump_section_table (MonoSectionTable
*st
)
211 guint32 flags
= st
->st_flags
;
213 printf ("\n\tName: %s\n", st
->st_name
);
214 hex32 (" Virtual Size", st
->st_virtual_size
);
215 hex32 ("Virtual Address", st
->st_virtual_address
);
216 hex32 (" Raw Data Size", st
->st_raw_data_size
);
217 hex32 (" Raw Data Ptr", st
->st_raw_data_ptr
);
218 hex32 (" Reloc Ptr", st
->st_reloc_ptr
);
219 hex32 (" LineNo Ptr", st
->st_lineno_ptr
);
220 hex16 (" Reloc Count", st
->st_reloc_count
);
221 hex16 (" Line Count", st
->st_line_count
);
223 printf ("\tFlags: %s%s%s%s%s%s%s%s%s%s\n",
224 (flags
& SECT_FLAGS_HAS_CODE
) ? "code, " : "",
225 (flags
& SECT_FLAGS_HAS_INITIALIZED_DATA
) ? "data, " : "",
226 (flags
& SECT_FLAGS_HAS_UNINITIALIZED_DATA
) ? "bss, " : "",
227 (flags
& SECT_FLAGS_MEM_DISCARDABLE
) ? "discard, " : "",
228 (flags
& SECT_FLAGS_MEM_NOT_CACHED
) ? "nocache, " : "",
229 (flags
& SECT_FLAGS_MEM_NOT_PAGED
) ? "nopage, " : "",
230 (flags
& SECT_FLAGS_MEM_SHARED
) ? "shared, " : "",
231 (flags
& SECT_FLAGS_MEM_EXECUTE
) ? "exec, " : "",
232 (flags
& SECT_FLAGS_MEM_READ
) ? "read, " : "",
233 (flags
& SECT_FLAGS_MEM_WRITE
) ? "write" : "");
237 dump_sections (MonoCLIImageInfo
*iinfo
)
239 const int top
= iinfo
->cli_header
.coff
.coff_sections
;
242 for (i
= 0; i
< top
; i
++)
243 dump_section_table (&iinfo
->cli_section_tables
[i
]);
247 dump_cli_header (MonoCLIHeader
*ch
)
250 printf (" CLI header size: %d\n", ch
->ch_size
);
251 printf (" Runtime required: %d.%d\n", ch
->ch_runtime_major
, ch
->ch_runtime_minor
);
252 printf (" Flags: %s, %s, %s, %s\n",
253 (ch
->ch_flags
& CLI_FLAGS_ILONLY
? "ilonly" : "contains native"),
254 (ch
->ch_flags
& CLI_FLAGS_32BITREQUIRED
? "32bits" : "32/64"),
255 (ch
->ch_flags
& CLI_FLAGS_TRACKDEBUGDATA
? "trackdebug" : "no-trackdebug"),
256 (ch
->ch_flags
& CLI_FLAGS_STRONGNAMESIGNED
? "strongnamesigned" : "notsigned"));
257 dent (" Metadata", ch
->ch_metadata
);
258 hex32 ("Entry Point Token", ch
->ch_entry_point
);
259 dent (" Resources at", ch
->ch_resources
);
260 dent (" Strong Name at", ch
->ch_strong_name
);
261 dent (" Code Manager at", ch
->ch_code_manager_table
);
262 dent (" VTableFixups at", ch
->ch_vtable_fixups
);
263 dent (" EAT jumps at", ch
->ch_export_address_table_jumps
);
267 dsh (const char *label
, MonoImage
*meta
, MonoStreamHeader
*sh
)
269 printf ("%s: 0x%08x - 0x%08x [%d == 0x%08x]\n",
271 (int)(sh
->data
- meta
->raw_metadata
), (int)(sh
->data
+ sh
->size
- meta
->raw_metadata
),
276 dump_metadata_header (MonoImage
*meta
)
278 printf ("\nMetadata header:\n");
279 printf (" Version: %d.%d\n", meta
->md_version_major
, meta
->md_version_minor
);
280 printf (" Version string: %s\n", meta
->version
);
284 dump_metadata_ptrs (MonoImage
*meta
)
286 printf ("\nMetadata pointers:\n");
287 dsh ("\tTables (#~)", meta
, &meta
->heap_tables
);
288 dsh ("\t Strings", meta
, &meta
->heap_strings
);
289 dsh ("\t Blob", meta
, &meta
->heap_blob
);
290 dsh ("\tUser string", meta
, &meta
->heap_us
);
291 dsh ("\t GUID", meta
, &meta
->heap_guid
);
295 dump_metadata (MonoImage
*meta
)
299 dump_metadata_header (meta
);
301 dump_metadata_ptrs (meta
);
304 for (table
= 0; table
< MONO_TABLE_NUM
; table
++){
305 if (meta
->tables
[table
].rows
== 0)
307 printf ("Table %s: %d records (%d bytes, at %x)\n",
308 mono_meta_table_name (table
),
309 meta
->tables
[table
].rows
,
310 meta
->tables
[table
].row_size
,
311 (unsigned int)(meta
->tables
[table
].base
- meta
->raw_data
)
317 dump_methoddef (MonoImage
*metadata
, guint32 token
)
323 loc
= mono_metadata_locate_token (metadata
, token
);
325 printf ("RVA for Entry Point: 0x%08x\n", read32 (loc
));
329 dump_dotnet_iinfo (MonoImage
*image
)
331 MonoCLIImageInfo
*iinfo
= image
->image_info
;
333 dump_dotnet_header (&iinfo
->cli_header
);
334 dump_sections (iinfo
);
335 dump_cli_header (&iinfo
->cli_cli_header
);
336 dump_strong_name (image
);
337 dump_public_key (image
);
338 dump_metadata (image
);
340 dump_methoddef (image
, iinfo
->cli_cli_header
.ch_entry_point
);
344 dump_verify_info (MonoImage
*image
, int flags
)
346 GSList
*errors
, *tmp
;
347 int count
= 0, verifiable
= 0;
348 const char* desc
[] = {
349 "Ok", "Error", "Warning", NULL
, "CLS", NULL
, NULL
, NULL
, "Not Verifiable"
352 if (verify_code
) { /* verify code */
354 MonoTableInfo
*m
= &image
->tables
[MONO_TABLE_METHOD
];
356 for (i
= 0; i
< m
->rows
; ++i
) {
358 mono_loader_clear_error ();
360 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+1), NULL
);
362 g_print ("Warning: Cannot lookup method with token 0x%08x\n", i
+ 1);
365 errors
= mono_method_verify (method
, flags
);
367 MonoClass
*klass
= mono_method_get_class (method
);
368 char *name
= mono_type_full_name (&klass
->byval_arg
);
369 if (mono_method_signature (method
) == NULL
) {
370 g_print ("In method: %s::%s(ERROR)\n", name
, mono_method_get_name (method
));
373 sig
= mono_signature_get_desc (mono_method_signature (method
), FALSE
);
374 g_print ("In method: %s::%s(%s)\n", name
, mono_method_get_name (method
), sig
);
380 for (tmp
= errors
; tmp
; tmp
= tmp
->next
) {
381 MonoVerifyInfo
*info
= tmp
->data
;
382 g_print ("%s: %s\n", desc
[info
->status
], info
->message
);
383 if (info
->status
== MONO_VERIFY_ERROR
) {
387 if(info
->status
== MONO_VERIFY_NOT_VERIFIABLE
) {
392 mono_free_verify_list (errors
);
397 g_print ("Error count: %d\n", count
);
404 printf ("Usage is: pedump [--verify error,warn,cls,all,code,fail-on-verifiable,non-strict,valid-only,metadata] file.exe\n");
409 verify_image_file (const char *fname
)
411 GSList
*errors
= NULL
, *tmp
;
413 MonoTableInfo
*table
;
414 MonoAssembly
*assembly
;
415 MonoImageOpenStatus status
;
417 const char* desc
[] = {
418 "Ok", "Error", "Warning", NULL
, "CLS", NULL
, NULL
, NULL
, "Not Verifiable"
421 image
= mono_image_open_raw (fname
, &status
);
423 printf ("Could not open %s\n", fname
);
427 if (!mono_verifier_verify_pe_data (image
, &errors
))
430 if (!mono_image_load_pe_data (image
)) {
431 printf ("Could not load pe data for assembly %s\n", fname
);
435 if (!mono_verifier_verify_cli_data (image
, &errors
))
438 if (!mono_image_load_cli_data (image
)) {
439 printf ("Could not load cli data for assembly %s\n", fname
);
443 if (!mono_verifier_verify_table_data (image
, &errors
))
446 mono_image_load_names (image
);
448 if (!verify_partial_md
&& !mono_verifier_verify_full_table_data (image
, &errors
))
451 /*fake an assembly for class loading to work*/
452 assembly
= g_new0 (MonoAssembly
, 1);
453 assembly
->in_gac
= FALSE
;
454 assembly
->image
= image
;
455 image
->assembly
= assembly
;
457 table
= &image
->tables
[MONO_TABLE_TYPEDEF
];
458 for (i
= 1; i
<= table
->rows
; ++i
) {
459 guint32 token
= i
| MONO_TOKEN_TYPE_DEF
;
460 MonoClass
*class = mono_class_get (image
, token
);
462 printf ("Could not load class with token %x\n", token
);
465 mono_class_init (class);
466 if (class->exception_type
!= MONO_EXCEPTION_NONE
|| mono_loader_get_last_error ()) {
467 printf ("Error verifying class(0x%08x) %s.%s a type load error happened\n", token
, class->name_space
, class->name
);
468 mono_loader_clear_error ();
477 for (tmp
= errors
; tmp
; tmp
= tmp
->next
) {
478 MonoVerifyInfo
*info
= tmp
->data
;
479 g_print ("%s: %s\n", desc
[info
->status
], info
->message
);
480 if (info
->status
== MONO_VERIFY_ERROR
)
483 mono_free_verify_list (errors
);
485 g_print ("Error count: %d\n", count
);
490 try_load_from (MonoAssembly
**assembly
, const gchar
*path1
, const gchar
*path2
,
491 const gchar
*path3
, const gchar
*path4
, gboolean refonly
)
496 fullpath
= g_build_filename (path1
, path2
, path3
, path4
, NULL
);
497 if (g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
))
498 *assembly
= mono_assembly_open_full (fullpath
, NULL
, refonly
);
501 return (*assembly
!= NULL
);
504 static MonoAssembly
*
505 real_load (gchar
**search_path
, const gchar
*culture
, const gchar
*name
, gboolean refonly
)
507 MonoAssembly
*result
= NULL
;
510 const gchar
*local_culture
;
513 if (!culture
|| *culture
== '\0') {
516 local_culture
= culture
;
519 filename
= g_strconcat (name
, ".dll", NULL
);
520 len
= strlen (filename
);
522 for (path
= search_path
; *path
; path
++) {
524 continue; /* Ignore empty ApplicationBase */
526 /* See test cases in bug #58992 and bug #57710 */
527 /* 1st try: [culture]/[name].dll (culture may be empty) */
528 strcpy (filename
+ len
- 4, ".dll");
529 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
))
532 /* 2nd try: [culture]/[name].exe (culture may be empty) */
533 strcpy (filename
+ len
- 4, ".exe");
534 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
))
537 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
538 strcpy (filename
+ len
- 4, ".dll");
539 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
))
542 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
543 strcpy (filename
+ len
- 4, ".exe");
544 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
))
553 * Try to load referenced assemblies from assemblies_path.
555 static MonoAssembly
*
556 pedump_preload (MonoAssemblyName
*aname
,
557 gchar
**assemblies_path
,
560 MonoAssembly
*result
= NULL
;
561 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
563 if (assemblies_path
&& assemblies_path
[0] != NULL
) {
564 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, refonly
);
570 static GList
*loaded_assemblies
= NULL
;
573 pedump_assembly_load_hook (MonoAssembly
*assembly
, gpointer user_data
)
575 loaded_assemblies
= g_list_prepend (loaded_assemblies
, assembly
);
578 static MonoAssembly
*
579 pedump_assembly_search_hook (MonoAssemblyName
*aname
, gpointer user_data
)
583 for (tmp
= loaded_assemblies
; tmp
; tmp
= tmp
->next
) {
584 MonoAssembly
*ass
= tmp
->data
;
585 if (mono_assembly_names_equal (aname
, &ass
->aname
))
591 #define VALID_ONLY_FLAG 0x08000000
592 #define VERIFY_CODE_ONLY MONO_VERIFY_ALL + 1
593 #define VERIFY_METADATA_ONLY VERIFY_CODE_ONLY + 1
594 #define VERIFY_PARTIAL_METADATA VERIFY_CODE_ONLY + 2
597 main (int argc
, char *argv
[])
599 int image_result
= 0;
603 MiniVerifierMode verifier_mode
= MONO_VERIFIER_MODE_VERIFIABLE
;
604 const char *flag_desc
[] = {"error", "warn", "cls", "all", "code", "fail-on-verifiable", "non-strict", "valid-only", "metadata", "partial-md", NULL
};
605 guint flag_vals
[] = {MONO_VERIFY_ERROR
, MONO_VERIFY_WARNING
, MONO_VERIFY_CLS
, MONO_VERIFY_ALL
, VERIFY_CODE_ONLY
, MONO_VERIFY_FAIL_FAST
, MONO_VERIFY_NON_STRICT
, VALID_ONLY_FLAG
, VERIFY_METADATA_ONLY
, VERIFY_PARTIAL_METADATA
, 0};
606 int i
, verify_flags
= MONO_VERIFY_REPORT_ALL_ERRORS
, run_new_metadata_verifier
= 0;
608 for (i
= 1; i
< argc
; i
++){
609 if (argv
[i
][0] != '-'){
614 if (strcmp (argv
[i
], "--help") == 0)
616 else if (strcmp (argv
[i
], "--verify") == 0) {
629 mono_perfcounters_init ();
630 mono_metadata_init ();
632 mono_assemblies_init ();
636 char *tok
= strtok (flags
, ",");
641 for (i
= 0; flag_desc
[i
]; ++i
) {
642 if (strcmp (tok
, flag_desc
[i
]) == 0) {
643 if (flag_vals
[i
] == VERIFY_CODE_ONLY
) {
646 } else if(flag_vals
[i
] == MONO_VERIFY_ALL
) {
648 } else if(flag_vals
[i
] == VERIFY_METADATA_ONLY
) {
650 run_new_metadata_verifier
= 1;
651 } else if(flag_vals
[i
] == VERIFY_PARTIAL_METADATA
) {
652 verify_partial_md
= 1;
654 if (flag_vals
[i
] == VALID_ONLY_FLAG
)
655 verifier_mode
= MONO_VERIFIER_MODE_VALID
;
657 verify_flags
|= flag_vals
[i
];
662 g_print ("Unknown verify flag %s\n", tok
);
663 tok
= strtok (NULL
, ",");
666 mono_verifier_set_mode (verifier_mode
);
670 if (verify_pe
|| run_new_metadata_verifier
) {
671 mono_install_assembly_load_hook (pedump_assembly_load_hook
, NULL
);
672 mono_install_assembly_search_hook (pedump_assembly_search_hook
, NULL
);
674 mono_init_version ("pedump", "v2.0.50727");
676 mono_install_assembly_preload_hook (pedump_preload
, GUINT_TO_POINTER (FALSE
));
678 mono_marshal_init ();
679 run_new_metadata_verifier
= 1;
682 if (run_new_metadata_verifier
) {
683 mono_verifier_set_mode (verifier_mode
);
685 image_result
= verify_image_file (file
);
686 if (image_result
== 1 || !verify_code
)
690 image
= mono_image_open (file
, NULL
);
692 fprintf (stderr
, "Cannot open image %s\n", file
);
697 dump_dotnet_iinfo (image
);
699 MonoAssembly
*assembly
;
701 MonoImageOpenStatus status
;
704 mono_verifier_set_mode (verifier_mode
);
706 assembly
= mono_assembly_open (file
, NULL
);
707 /*fake an assembly for netmodules so the verifier works*/
708 if (!assembly
&& (image
= mono_image_open (file
, &status
)) && image
->tables
[MONO_TABLE_ASSEMBLY
].rows
== 0) {
709 assembly
= g_new0 (MonoAssembly
, 1);
710 assembly
->in_gac
= FALSE
;
711 assembly
->image
= image
;
712 image
->assembly
= assembly
;
716 g_print ("Could not open assembly %s\n", file
);
720 code_result
= dump_verify_info (assembly
->image
, verify_flags
);
721 return code_result
? code_result
: image_result
;
723 mono_image_close (image
);