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_metadata
) {
353 errors
= mono_image_verify_tables (image
, flags
);
355 for (tmp
= errors
; tmp
; tmp
= tmp
->next
) {
356 MonoVerifyInfo
*info
= tmp
->data
;
357 g_print ("%s: %s\n", desc
[info
->status
], info
->message
);
358 if (info
->status
== MONO_VERIFY_ERROR
)
361 mono_free_verify_list (errors
);
364 if (verify_code
) { /* verify code */
366 MonoTableInfo
*m
= &image
->tables
[MONO_TABLE_METHOD
];
368 for (i
= 0; i
< m
->rows
; ++i
) {
370 mono_loader_clear_error ();
372 method
= mono_get_method (image
, MONO_TOKEN_METHOD_DEF
| (i
+1), NULL
);
374 g_print ("Warning: Cannot lookup method with token 0x%08x\n", i
+ 1);
377 errors
= mono_method_verify (method
, flags
);
379 MonoClass
*klass
= mono_method_get_class (method
);
380 char *name
= mono_type_full_name (&klass
->byval_arg
);
381 if (mono_method_signature (method
) == NULL
) {
382 g_print ("In method: %s::%s(ERROR)\n", name
, mono_method_get_name (method
));
385 sig
= mono_signature_get_desc (mono_method_signature (method
), FALSE
);
386 g_print ("In method: %s::%s(%s)\n", name
, mono_method_get_name (method
), sig
);
392 for (tmp
= errors
; tmp
; tmp
= tmp
->next
) {
393 MonoVerifyInfo
*info
= tmp
->data
;
394 g_print ("%s: %s\n", desc
[info
->status
], info
->message
);
395 if (info
->status
== MONO_VERIFY_ERROR
) {
399 if(info
->status
== MONO_VERIFY_NOT_VERIFIABLE
) {
404 mono_free_verify_list (errors
);
409 g_print ("Error count: %d\n", count
);
416 printf ("Usage is: pedump [--verify error,warn,cls,all,code,fail-on-verifiable,non-strict,valid-only,metadata] file.exe\n");
421 verify_image_file (const char *fname
)
423 GSList
*errors
= NULL
, *tmp
;
425 MonoTableInfo
*table
;
426 MonoAssembly
*assembly
;
427 MonoImageOpenStatus status
;
429 const char* desc
[] = {
430 "Ok", "Error", "Warning", NULL
, "CLS", NULL
, NULL
, NULL
, "Not Verifiable"
433 image
= mono_image_open_raw (fname
, &status
);
435 printf ("Could not open %s\n", fname
);
439 if (!mono_verifier_verify_pe_data (image
, &errors
))
442 if (!mono_image_load_pe_data (image
)) {
443 printf ("Could not load pe data for assembly %s\n", fname
);
447 if (!mono_verifier_verify_cli_data (image
, &errors
))
450 if (!mono_image_load_cli_data (image
)) {
451 printf ("Could not load cli data for assembly %s\n", fname
);
455 if (!mono_verifier_verify_table_data (image
, &errors
))
458 mono_image_load_names (image
);
460 if (!verify_partial_md
&& !mono_verifier_verify_full_table_data (image
, &errors
))
463 /*fake an assembly for class loading to work*/
464 assembly
= g_new0 (MonoAssembly
, 1);
465 assembly
->in_gac
= FALSE
;
466 assembly
->image
= image
;
467 image
->assembly
= assembly
;
469 table
= &image
->tables
[MONO_TABLE_TYPEDEF
];
470 for (i
= 1; i
<= table
->rows
; ++i
) {
471 guint32 token
= i
| MONO_TOKEN_TYPE_DEF
;
472 MonoClass
*class = mono_class_get (image
, token
);
474 printf ("Could not load class with token %x\n", token
);
477 mono_class_init (class);
478 if (class->exception_type
!= MONO_EXCEPTION_NONE
|| mono_loader_get_last_error ()) {
479 printf ("Error verifying class(0x%08x) %s.%s a type load error happened\n", token
, class->name_space
, class->name
);
480 mono_loader_clear_error ();
489 for (tmp
= errors
; tmp
; tmp
= tmp
->next
) {
490 MonoVerifyInfo
*info
= tmp
->data
;
491 g_print ("%s: %s\n", desc
[info
->status
], info
->message
);
492 if (info
->status
== MONO_VERIFY_ERROR
)
495 mono_free_verify_list (errors
);
497 g_print ("Error count: %d\n", count
);
502 try_load_from (MonoAssembly
**assembly
, const gchar
*path1
, const gchar
*path2
,
503 const gchar
*path3
, const gchar
*path4
, gboolean refonly
)
508 fullpath
= g_build_filename (path1
, path2
, path3
, path4
, NULL
);
509 if (g_file_test (fullpath
, G_FILE_TEST_IS_REGULAR
))
510 *assembly
= mono_assembly_open_full (fullpath
, NULL
, refonly
);
513 return (*assembly
!= NULL
);
516 static MonoAssembly
*
517 real_load (gchar
**search_path
, const gchar
*culture
, const gchar
*name
, gboolean refonly
)
519 MonoAssembly
*result
= NULL
;
522 const gchar
*local_culture
;
525 if (!culture
|| *culture
== '\0') {
528 local_culture
= culture
;
531 filename
= g_strconcat (name
, ".dll", NULL
);
532 len
= strlen (filename
);
534 for (path
= search_path
; *path
; path
++) {
536 continue; /* Ignore empty ApplicationBase */
538 /* See test cases in bug #58992 and bug #57710 */
539 /* 1st try: [culture]/[name].dll (culture may be empty) */
540 strcpy (filename
+ len
- 4, ".dll");
541 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
))
544 /* 2nd try: [culture]/[name].exe (culture may be empty) */
545 strcpy (filename
+ len
- 4, ".exe");
546 if (try_load_from (&result
, *path
, local_culture
, "", filename
, refonly
))
549 /* 3rd try: [culture]/[name]/[name].dll (culture may be empty) */
550 strcpy (filename
+ len
- 4, ".dll");
551 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
))
554 /* 4th try: [culture]/[name]/[name].exe (culture may be empty) */
555 strcpy (filename
+ len
- 4, ".exe");
556 if (try_load_from (&result
, *path
, local_culture
, name
, filename
, refonly
))
565 * Try to load referenced assemblies from assemblies_path.
567 static MonoAssembly
*
568 pedump_preload (MonoAssemblyName
*aname
,
569 gchar
**assemblies_path
,
572 MonoAssembly
*result
= NULL
;
573 gboolean refonly
= GPOINTER_TO_UINT (user_data
);
575 if (assemblies_path
&& assemblies_path
[0] != NULL
) {
576 result
= real_load (assemblies_path
, aname
->culture
, aname
->name
, refonly
);
582 static GList
*loaded_assemblies
= NULL
;
585 pedump_assembly_load_hook (MonoAssembly
*assembly
, gpointer user_data
)
587 loaded_assemblies
= g_list_prepend (loaded_assemblies
, assembly
);
590 static MonoAssembly
*
591 pedump_assembly_search_hook (MonoAssemblyName
*aname
, gpointer user_data
)
595 for (tmp
= loaded_assemblies
; tmp
; tmp
= tmp
->next
) {
596 MonoAssembly
*ass
= tmp
->data
;
597 if (mono_assembly_names_equal (aname
, &ass
->aname
))
603 #define VALID_ONLY_FLAG 0x08000000
604 #define VERIFY_CODE_ONLY MONO_VERIFY_ALL + 1
605 #define VERIFY_METADATA_ONLY VERIFY_CODE_ONLY + 1
606 #define VERIFY_PARTIAL_METADATA VERIFY_CODE_ONLY + 2
609 main (int argc
, char *argv
[])
611 int image_result
= 0;
615 MiniVerifierMode verifier_mode
= MONO_VERIFIER_MODE_VERIFIABLE
;
616 const char *flag_desc
[] = {"error", "warn", "cls", "all", "code", "fail-on-verifiable", "non-strict", "valid-only", "metadata", "partial-md", NULL
};
617 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};
618 int i
, verify_flags
= MONO_VERIFY_REPORT_ALL_ERRORS
, run_new_metadata_verifier
= 0;
620 for (i
= 1; i
< argc
; i
++){
621 if (argv
[i
][0] != '-'){
626 if (strcmp (argv
[i
], "--help") == 0)
628 else if (strcmp (argv
[i
], "--verify") == 0) {
641 mono_perfcounters_init ();
642 mono_metadata_init ();
644 mono_assemblies_init ();
648 char *tok
= strtok (flags
, ",");
653 for (i
= 0; flag_desc
[i
]; ++i
) {
654 if (strcmp (tok
, flag_desc
[i
]) == 0) {
655 if (flag_vals
[i
] == VERIFY_CODE_ONLY
) {
658 } else if(flag_vals
[i
] == MONO_VERIFY_ALL
) {
660 } else if(flag_vals
[i
] == VERIFY_METADATA_ONLY
) {
662 run_new_metadata_verifier
= 1;
663 } else if(flag_vals
[i
] == VERIFY_PARTIAL_METADATA
) {
664 verify_partial_md
= 1;
666 if (flag_vals
[i
] == VALID_ONLY_FLAG
)
667 verifier_mode
= MONO_VERIFIER_MODE_VALID
;
669 verify_flags
|= flag_vals
[i
];
674 g_print ("Unknown verify flag %s\n", tok
);
675 tok
= strtok (NULL
, ",");
678 mono_verifier_set_mode (verifier_mode
);
682 if (verify_pe
|| run_new_metadata_verifier
) {
683 mono_install_assembly_load_hook (pedump_assembly_load_hook
, NULL
);
684 mono_install_assembly_search_hook (pedump_assembly_search_hook
, NULL
);
686 mono_init_version ("pedump", "v2.0.50727");
688 mono_install_assembly_preload_hook (pedump_preload
, GUINT_TO_POINTER (FALSE
));
690 mono_marshal_init ();
691 run_new_metadata_verifier
= 1;
694 if (run_new_metadata_verifier
) {
695 mono_verifier_set_mode (MONO_VERIFIER_MODE_VERIFIABLE
);
697 image_result
= verify_image_file (file
);
698 if (image_result
== 1 || !verify_code
)
702 image
= mono_image_open (file
, NULL
);
704 fprintf (stderr
, "Cannot open image %s\n", file
);
709 dump_dotnet_iinfo (image
);
711 MonoAssembly
*assembly
;
713 MonoImageOpenStatus status
;
716 mono_verifier_set_mode (verifier_mode
);
718 assembly
= mono_assembly_open (file
, NULL
);
719 /*fake an assembly for netmodules so the verifier works*/
720 if (!assembly
&& (image
= mono_image_open (file
, &status
)) && image
->tables
[MONO_TABLE_ASSEMBLY
].rows
== 0) {
721 assembly
= g_new0 (MonoAssembly
, 1);
722 assembly
->in_gac
= FALSE
;
723 assembly
->image
= image
;
724 image
->assembly
= assembly
;
728 g_print ("Could not open assembly %s\n", file
);
732 code_result
= dump_verify_info (assembly
->image
, verify_flags
);
733 return code_result
? code_result
: image_result
;
735 mono_image_close (image
);