3 * Routines for manipulating an image stored in an
4 * extended PE/COFF file.
7 * Miguel de Icaza (miguel@ximian.com)
8 * Paolo Molaro (lupus@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #include "mono-endian.h"
24 #include "tabledefs.h"
25 #include "tokentype.h"
26 #include "metadata-internals.h"
27 #include "profiler-private.h"
31 #include <mono/utils/checked-build.h>
32 #include <mono/utils/mono-logger-internals.h>
33 #include <mono/utils/mono-path.h>
34 #include <mono/utils/mono-mmap.h>
35 #include <mono/utils/mono-io-portability.h>
36 #include <mono/utils/atomic.h>
37 #include <mono/metadata/class-internals.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/object-internals.h>
40 #include <mono/metadata/security-core-clr.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/verify.h>
43 #include <mono/metadata/image-internals.h>
44 #include <sys/types.h>
49 #include <mono/metadata/w32error.h>
51 #define INVALID_ADDRESS 0xffffffff
53 // Amount initially reserved in each image's mempool.
54 // FIXME: This number is arbitrary, a more practical number should be found
55 #define INITIAL_IMAGE_SIZE 512
58 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
59 * There are four, for all combinations of [look up by path or assembly name?]
60 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
64 IMAGES_HASH_PATH_REFONLY = 1,
66 IMAGES_HASH_NAME_REFONLY = 3,
69 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
72 get_loaded_images_hash (gboolean refonly)
74 int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
75 return loaded_images_hashes [idx];
79 get_loaded_images_by_name_hash (gboolean refonly)
81 int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
82 return loaded_images_hashes [idx];
85 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
86 // Can be used on modules loaded through either the "file" or "module" mechanism
88 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
91 MonoAssembly *assembly = assemblyImage->assembly;
94 // Assembly currently assigned
95 MonoAssembly *assemblyOld = image->assembly;
97 if (assemblyOld == assembly)
99 mono_error_set_bad_image (error, assemblyImage, "Attempted to load module %s which has already been loaded by assembly %s. This is not supported in Mono.", image->name, assemblyOld->image->name);
102 gpointer result = InterlockedExchangePointer((gpointer *)&image->assembly, assembly);
103 if (result == assembly)
108 static gboolean debug_assembly_unload = FALSE;
110 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
111 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
112 static gboolean mutex_inited;
113 static mono_mutex_t images_mutex;
115 static void install_pe_loader (void);
117 typedef struct ImageUnloadHook ImageUnloadHook;
118 struct ImageUnloadHook {
119 MonoImageUnloadFunc func;
123 static GSList *image_unload_hooks;
126 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
128 ImageUnloadHook *hook;
130 g_return_if_fail (func != NULL);
132 hook = g_new0 (ImageUnloadHook, 1);
134 hook->user_data = user_data;
135 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
139 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
142 ImageUnloadHook *hook;
144 for (l = image_unload_hooks; l; l = l->next) {
145 hook = (ImageUnloadHook *)l->data;
147 if (hook->func == func && hook->user_data == user_data) {
149 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
156 mono_image_invoke_unload_hook (MonoImage *image)
159 ImageUnloadHook *hook;
161 for (l = image_unload_hooks; l; l = l->next) {
162 hook = (ImageUnloadHook *)l->data;
164 hook->func (image, hook->user_data);
168 static GSList *image_loaders;
171 mono_install_image_loader (const MonoImageLoader *loader)
173 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
176 /* returns offset relative to image->raw_data */
178 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
180 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
181 const int top = iinfo->cli_section_count;
182 MonoSectionTable *tables = iinfo->cli_section_tables;
185 if (image->metadata_only)
188 for (i = 0; i < top; i++){
189 if ((addr >= tables->st_virtual_address) &&
190 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
192 if (image->is_module_handle)
195 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
199 return INVALID_ADDRESS;
203 * mono_image_rva_map:
204 * \param image a \c MonoImage
205 * \param addr relative virtual address (RVA)
207 * This is a low-level routine used by the runtime to map relative
208 * virtual address (RVA) into their location in memory.
210 * \returns the address in memory for the given RVA, or NULL if the
211 * RVA is not valid for this image.
214 mono_image_rva_map (MonoImage *image, guint32 addr)
216 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
217 const int top = iinfo->cli_section_count;
218 MonoSectionTable *tables = iinfo->cli_section_tables;
222 if (image->is_module_handle) {
223 if (addr && addr < image->raw_data_len)
224 return image->raw_data + addr;
230 for (i = 0; i < top; i++){
231 if ((addr >= tables->st_virtual_address) &&
232 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
233 if (!iinfo->cli_sections [i]) {
234 if (!mono_image_ensure_section_idx (image, i))
237 return (char*)iinfo->cli_sections [i] +
238 (addr - tables->st_virtual_address);
248 * Initialize the global variables used by this module.
251 mono_images_init (void)
253 mono_os_mutex_init_recursive (&images_mutex);
256 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
257 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
259 debug_assembly_unload = g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
261 install_pe_loader ();
267 * mono_images_cleanup:
269 * Free all resources used by this module.
272 mono_images_cleanup (void)
277 mono_os_mutex_destroy (&images_mutex);
279 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
280 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
281 g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
282 while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
283 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
286 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
287 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
289 mutex_inited = FALSE;
293 * mono_image_ensure_section_idx:
294 * \param image The image we are operating on
295 * \param section section number that we will load/map into memory
297 * This routine makes sure that we have an in-memory copy of
298 * an image section (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
300 * \returns TRUE on success
303 mono_image_ensure_section_idx (MonoImage *image, int section)
305 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
306 MonoSectionTable *sect;
308 g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
310 if (iinfo->cli_sections [section] != NULL)
313 sect = &iinfo->cli_section_tables [section];
315 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
318 if (image->is_module_handle)
319 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
322 /* FIXME: we ignore the writable flag since we don't patch the binary */
323 iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
328 * mono_image_ensure_section:
329 * \param image The image we are operating on
330 * \param section section name that we will load/map into memory
332 * This routine makes sure that we have an in-memory copy of
333 * an image section (.text, .rsrc, .data).
335 * \returns TRUE on success
338 mono_image_ensure_section (MonoImage *image, const char *section)
340 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
343 for (i = 0; i < ii->cli_section_count; i++){
344 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
347 return mono_image_ensure_section_idx (image, i);
353 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
355 const int top = iinfo->cli_header.coff.coff_sections;
358 iinfo->cli_section_count = top;
359 iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
360 iinfo->cli_sections = g_new0 (void *, top);
362 for (i = 0; i < top; i++){
363 MonoSectionTable *t = &iinfo->cli_section_tables [i];
365 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
367 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
368 offset += sizeof (MonoSectionTable);
370 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
371 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
372 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
373 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
374 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
375 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
376 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
377 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
378 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
379 t->st_flags = GUINT32_FROM_LE (t->st_flags);
381 /* consistency checks here */
388 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
392 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
393 if (offset == INVALID_ADDRESS)
396 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
398 memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
400 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
401 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
402 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
403 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
404 SWAP32 (iinfo->cli_cli_header.ch_size);
405 SWAP32 (iinfo->cli_cli_header.ch_flags);
406 SWAP32 (iinfo->cli_cli_header.ch_entry_point);
407 SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
408 SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
409 SWAPPDE (iinfo->cli_cli_header.ch_metadata);
410 SWAPPDE (iinfo->cli_cli_header.ch_resources);
411 SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
412 SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
413 SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
414 SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
415 SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
416 SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
417 SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
418 SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
419 SWAPPDE (iinfo->cli_cli_header.ch_module_image);
420 SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
421 SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
422 SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
423 SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
428 /* Catch new uses of the fields that are supposed to be zero */
430 if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
431 (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
432 (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
433 (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
434 (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
435 (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
436 (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
437 (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
438 (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
441 * No need to scare people who are testing this, I am just
442 * labelling this as a LAMESPEC
444 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
452 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
454 guint32 offset, size;
460 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
461 if (offset == INVALID_ADDRESS)
464 size = iinfo->cli_cli_header.ch_metadata.size;
466 if (offset + size > image->raw_data_len)
468 image->raw_metadata = image->raw_data + offset;
470 /* 24.2.1: Metadata root starts here */
471 ptr = image->raw_metadata;
473 if (strncmp (ptr, "BSJB", 4) == 0){
474 guint32 version_string_len;
477 image->md_version_major = read16 (ptr);
479 image->md_version_minor = read16 (ptr);
482 version_string_len = read32 (ptr);
484 image->version = g_strndup (ptr, version_string_len);
485 ptr += version_string_len;
486 pad = ptr - image->raw_metadata;
488 ptr += 4 - (pad % 4);
492 /* skip over flags */
495 streams = read16 (ptr);
498 for (i = 0; i < streams; i++){
499 if (strncmp (ptr + 8, "#~", 3) == 0){
500 image->heap_tables.data = image->raw_metadata + read32 (ptr);
501 image->heap_tables.size = read32 (ptr + 4);
503 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
504 image->heap_strings.data = image->raw_metadata + read32 (ptr);
505 image->heap_strings.size = read32 (ptr + 4);
507 } else if (strncmp (ptr + 8, "#US", 4) == 0){
508 image->heap_us.data = image->raw_metadata + read32 (ptr);
509 image->heap_us.size = read32 (ptr + 4);
511 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
512 image->heap_blob.data = image->raw_metadata + read32 (ptr);
513 image->heap_blob.size = read32 (ptr + 4);
515 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
516 image->heap_guid.data = image->raw_metadata + read32 (ptr);
517 image->heap_guid.size = read32 (ptr + 4);
519 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
520 image->heap_tables.data = image->raw_metadata + read32 (ptr);
521 image->heap_tables.size = read32 (ptr + 4);
523 image->uncompressed_metadata = TRUE;
524 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name);
525 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
526 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
527 image->heap_pdb.size = read32 (ptr + 4);
530 g_message ("Unknown heap type: %s\n", ptr + 8);
531 ptr += 8 + strlen (ptr + 8) + 1;
533 pad = ptr - image->raw_metadata;
535 ptr += 4 - (pad % 4);
538 i = ((MonoImageLoader*)image->loader)->load_tables (image);
540 if (!image->metadata_only) {
541 g_assert (image->heap_guid.data);
542 g_assert (image->heap_guid.size >= 16);
544 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
546 /* PPDB files have no guid */
547 guint8 empty_guid [16];
549 memset (empty_guid, 0, sizeof (empty_guid));
551 image->guid = mono_guid_to_string (empty_guid);
558 * Load representation of logical metadata tables, from the "#~" stream
561 load_tables (MonoImage *image)
563 const char *heap_tables = image->heap_tables.data;
566 int valid = 0, table;
569 heap_sizes = heap_tables [6];
570 image->idx_string_wide = ((heap_sizes & 0x01) == 1);
571 image->idx_guid_wide = ((heap_sizes & 0x02) == 2);
572 image->idx_blob_wide = ((heap_sizes & 0x04) == 4);
574 valid_mask = read64 (heap_tables + 8);
575 rows = (const guint32 *) (heap_tables + 24);
577 for (table = 0; table < 64; table++){
578 if ((valid_mask & ((guint64) 1 << table)) == 0){
579 if (table > MONO_TABLE_LAST)
581 image->tables [table].rows = 0;
584 if (table > MONO_TABLE_LAST) {
585 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
587 image->tables [table].rows = read32 (rows);
593 image->tables_base = (heap_tables + 24) + (4 * valid);
595 /* They must be the same */
596 g_assert ((const void *) image->tables_base == (const void *) rows);
598 if (image->heap_pdb.size) {
600 * Obtain token sizes from the pdb stream.
602 /* 24 = guid + entry point */
604 image->referenced_tables = read64 (image->heap_pdb.data + pos);
606 image->referenced_table_rows = g_new0 (int, 64);
607 for (int i = 0; i < 64; ++i) {
608 if (image->referenced_tables & ((guint64)1 << i)) {
609 image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
615 mono_metadata_compute_table_bases (image);
620 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
622 if (!load_metadata_ptrs (image, iinfo))
625 return load_tables (image);
629 mono_image_check_for_module_cctor (MonoImage *image)
631 MonoTableInfo *t, *mt;
632 t = &image->tables [MONO_TABLE_TYPEDEF];
633 mt = &image->tables [MONO_TABLE_METHOD];
634 if (image_is_dynamic (image)) {
636 image->checked_module_cctor = TRUE;
640 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
641 const char *name = mono_metadata_string_heap (image, nameidx);
642 if (strcmp (name, "<Module>") == 0) {
643 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
646 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
648 last_method = mt->rows;
649 for (; first_method < last_method; first_method++) {
650 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
651 name = mono_metadata_string_heap (image, nameidx);
652 if (strcmp (name, ".cctor") == 0) {
653 image->has_module_cctor = TRUE;
654 image->checked_module_cctor = TRUE;
660 image->has_module_cctor = FALSE;
661 image->checked_module_cctor = TRUE;
665 load_modules (MonoImage *image)
672 t = &image->tables [MONO_TABLE_MODULEREF];
673 image->modules = g_new0 (MonoImage *, t->rows);
674 image->modules_loaded = g_new0 (gboolean, t->rows);
675 image->module_count = t->rows;
679 * mono_image_load_module_checked:
681 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
682 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
685 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
688 MonoTableInfo *file_table;
691 gboolean refonly = image->ref_only;
692 GList *list_iter, *valid_modules = NULL;
693 MonoImageOpenStatus status;
697 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
699 if (image->modules_loaded [idx - 1])
700 return image->modules [idx - 1];
702 file_table = &image->tables [MONO_TABLE_FILE];
703 for (i = 0; i < file_table->rows; i++) {
704 guint32 cols [MONO_FILE_SIZE];
705 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
706 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
708 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
711 t = &image->tables [MONO_TABLE_MODULEREF];
712 base_dir = g_path_get_dirname (image->name);
717 guint32 cols [MONO_MODULEREF_SIZE];
718 /* if there is no file table, we try to load the module... */
719 int valid = file_table->rows == 0;
721 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
722 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
723 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
724 /* be safe with string dups, but we could just compare string indexes */
725 if (strcmp (list_iter->data, name) == 0) {
731 module_ref = g_build_filename (base_dir, name, NULL);
732 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
734 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
735 mono_image_close (moduleImage);
738 g_list_free (valid_modules);
742 image->modules [idx - 1] = moduleImage;
745 if (image->modules [idx - 1]->is_module_handle)
746 mono_image_fixup_vtable (image->modules [idx - 1]);
748 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
754 image->modules_loaded [idx - 1] = TRUE;
757 g_list_free (valid_modules);
759 return image->modules [idx - 1];
763 * mono_image_load_module:
766 mono_image_load_module (MonoImage *image, int idx)
769 MonoImage *result = mono_image_load_module_checked (image, idx, &error);
770 mono_error_assert_ok (&error);
775 class_key_extract (gpointer value)
777 MonoClass *klass = (MonoClass *)value;
779 return GUINT_TO_POINTER (klass->type_token);
783 class_next_value (gpointer value)
785 MonoClassDef *klass = (MonoClassDef *)value;
787 return (gpointer*)&klass->next_class_cache;
794 mono_image_init (MonoImage *image)
796 mono_os_mutex_init_recursive (&image->lock);
797 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
799 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
800 mono_internal_hash_table_init (&image->class_cache,
804 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
806 image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
807 image->memberref_signatures = g_hash_table_new (NULL, NULL);
808 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
809 image->method_signatures = g_hash_table_new (NULL, NULL);
811 image->property_hash = mono_property_hash_new ();
814 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
815 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
816 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
817 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
818 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
827 * Returns < 0 to indicate an error.
830 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
832 MonoDotNetHeader64 header64;
835 if (!image->is_module_handle)
837 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
840 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
842 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
845 /* endian swap the fields common between PE and PE+ */
846 SWAP32 (header->coff.coff_time);
847 SWAP32 (header->coff.coff_symptr);
848 SWAP32 (header->coff.coff_symcount);
849 SWAP16 (header->coff.coff_machine);
850 SWAP16 (header->coff.coff_sections);
851 SWAP16 (header->coff.coff_opt_header_size);
852 SWAP16 (header->coff.coff_attributes);
854 SWAP32 (header->pe.pe_code_size);
855 SWAP32 (header->pe.pe_uninit_data_size);
856 SWAP32 (header->pe.pe_rva_entry_point);
857 SWAP32 (header->pe.pe_rva_code_base);
858 SWAP32 (header->pe.pe_rva_data_base);
859 SWAP16 (header->pe.pe_magic);
861 /* now we are ready for the basic tests */
863 if (header->pe.pe_magic == 0x10B) {
864 offset += sizeof (MonoDotNetHeader);
865 SWAP32 (header->pe.pe_data_size);
866 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
869 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
870 SWAP32 (header->nt.pe_stack_reserve);
871 SWAP32 (header->nt.pe_stack_commit);
872 SWAP32 (header->nt.pe_heap_reserve);
873 SWAP32 (header->nt.pe_heap_commit);
874 } else if (header->pe.pe_magic == 0x20B) {
875 /* PE32+ file format */
876 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
878 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
879 offset += sizeof (MonoDotNetHeader64);
880 /* copy the fields already swapped. the last field, pe_data_size, is missing */
881 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
882 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
883 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
885 SWAP64 (header64.nt.pe_image_base);
886 header->nt.pe_image_base = header64.nt.pe_image_base;
887 SWAP64 (header64.nt.pe_stack_reserve);
888 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
889 SWAP64 (header64.nt.pe_stack_commit);
890 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
891 SWAP64 (header64.nt.pe_heap_reserve);
892 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
893 SWAP64 (header64.nt.pe_heap_commit);
894 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
896 header->nt.pe_section_align = header64.nt.pe_section_align;
897 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
898 header->nt.pe_os_major = header64.nt.pe_os_major;
899 header->nt.pe_os_minor = header64.nt.pe_os_minor;
900 header->nt.pe_user_major = header64.nt.pe_user_major;
901 header->nt.pe_user_minor = header64.nt.pe_user_minor;
902 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
903 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
904 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
905 header->nt.pe_image_size = header64.nt.pe_image_size;
906 header->nt.pe_header_size = header64.nt.pe_header_size;
907 header->nt.pe_checksum = header64.nt.pe_checksum;
908 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
909 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
910 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
911 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
913 /* copy the datadir */
914 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
919 /* MonoPEHeaderNT: not used yet */
920 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
921 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
922 SWAP16 (header->nt.pe_os_major); /* must be 4 */
923 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
924 SWAP16 (header->nt.pe_user_major);
925 SWAP16 (header->nt.pe_user_minor);
926 SWAP16 (header->nt.pe_subsys_major);
927 SWAP16 (header->nt.pe_subsys_minor);
928 SWAP32 (header->nt.pe_reserved_1);
929 SWAP32 (header->nt.pe_image_size);
930 SWAP32 (header->nt.pe_header_size);
931 SWAP32 (header->nt.pe_checksum);
932 SWAP16 (header->nt.pe_subsys_required);
933 SWAP16 (header->nt.pe_dll_flags);
934 SWAP32 (header->nt.pe_loader_flags);
935 SWAP32 (header->nt.pe_data_dir_count);
937 /* MonoDotNetHeader: mostly unused */
938 SWAPPDE (header->datadir.pe_export_table);
939 SWAPPDE (header->datadir.pe_import_table);
940 SWAPPDE (header->datadir.pe_resource_table);
941 SWAPPDE (header->datadir.pe_exception_table);
942 SWAPPDE (header->datadir.pe_certificate_table);
943 SWAPPDE (header->datadir.pe_reloc_table);
944 SWAPPDE (header->datadir.pe_debug);
945 SWAPPDE (header->datadir.pe_copyright);
946 SWAPPDE (header->datadir.pe_global_ptr);
947 SWAPPDE (header->datadir.pe_tls_table);
948 SWAPPDE (header->datadir.pe_load_config_table);
949 SWAPPDE (header->datadir.pe_bound_import);
950 SWAPPDE (header->datadir.pe_iat);
951 SWAPPDE (header->datadir.pe_delay_import_desc);
952 SWAPPDE (header->datadir.pe_cli_header);
953 SWAPPDE (header->datadir.pe_reserved);
956 if (image->is_module_handle)
957 image->raw_data_len = header->nt.pe_image_size;
964 mono_image_load_pe_data (MonoImage *image)
966 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
970 pe_image_load_pe_data (MonoImage *image)
972 MonoCLIImageInfo *iinfo;
973 MonoDotNetHeader *header;
974 MonoMSDOSHeader msdos;
977 iinfo = (MonoCLIImageInfo *)image->image_info;
978 header = &iinfo->cli_header;
981 if (!image->is_module_handle)
983 if (offset + sizeof (msdos) > image->raw_data_len)
985 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
987 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
990 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
992 offset = msdos.pe_offset;
994 offset = do_load_header (image, header, offset);
999 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1000 * we skip this test.
1001 if (header->coff.coff_machine != 0x14c)
1007 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1008 * which produces binaries with 7.0. From Sergey:
1010 * The reason is that MSVC7 uses traditional compile/link
1011 * sequence for CIL executables, and VS.NET (and Framework
1012 * SDK) includes linker version 7, that puts 7.0 in this
1013 * field. That's why it's currently not possible to load VC
1014 * binaries with Mono. This field is pretty much meaningless
1015 * anyway (what linker?).
1017 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1022 * FIXME: byte swap all addresses here for header.
1025 if (!load_section_tables (image, iinfo, offset))
1035 mono_image_load_cli_data (MonoImage *image)
1037 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1041 pe_image_load_cli_data (MonoImage *image)
1043 MonoCLIImageInfo *iinfo;
1044 MonoDotNetHeader *header;
1046 iinfo = (MonoCLIImageInfo *)image->image_info;
1047 header = &iinfo->cli_header;
1049 /* Load the CLI header */
1050 if (!mono_image_load_cli_header (image, iinfo))
1053 if (!mono_image_load_metadata (image, iinfo))
1060 mono_image_load_names (MonoImage *image)
1062 /* modules don't have an assembly table row */
1063 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1064 image->assembly_name = mono_metadata_string_heap (image,
1065 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1066 0, MONO_ASSEMBLY_NAME));
1069 /* Portable pdb images don't have a MODULE row */
1070 if (image->tables [MONO_TABLE_MODULE].rows) {
1071 image->module_name = mono_metadata_string_heap (image,
1072 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1073 0, MONO_MODULE_NAME));
1078 pe_image_load_tables (MonoImage *image)
1084 pe_image_match (MonoImage *image)
1086 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1091 static const MonoImageLoader pe_loader = {
1093 pe_image_load_pe_data,
1094 pe_image_load_cli_data,
1095 pe_image_load_tables,
1099 install_pe_loader (void)
1101 mono_install_image_loader (&pe_loader);
1107 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1108 Mono provides its own implementation of those assemblies so it's safe to do so.
1110 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1112 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1114 This is to be removed once a proper fix is shipped through nuget.
1116 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1117 If any assemblies are added/removed, then this should be regenerated with:
1119 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1124 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1125 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1126 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1127 SYS_NET_HTTP = 3, //System.Net.Http
1128 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1129 SYS_REF_DISP_PROXY = 5, //System.Reflection.DispatchProxy
1130 SYS_THREADING_OVERLAPPED = 6, //System.Threading.Overlapped
1131 } IgnoredAssemblyNames;
1136 const char guid [40];
1141 guint16 major, minor, build, revision;
1142 } IgnoredAssemblyVersion;
1144 const char *ignored_assemblies_file_names[] = {
1145 "System.Runtime.InteropServices.RuntimeInformation.dll",
1146 "System.Globalization.Extensions.dll",
1147 "System.IO.Compression.dll",
1148 "System.Net.Http.dll",
1149 "System.Text.Encoding.CodePages.dll",
1150 "System.Reflection.DispatchProxy.dll",
1151 "System.Threading.Overlapped.dll"
1154 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1156 static const IgnoredAssembly ignored_assemblies [] = {
1157 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1158 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1159 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1160 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1161 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1162 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1163 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1164 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1165 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1166 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1167 IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1168 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1169 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1170 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1171 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1172 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1173 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1174 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1175 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1176 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46")
1180 const char *ignored_assemblies_names[] = {
1181 "System.Runtime.InteropServices.RuntimeInformation",
1182 "System.Globalization.Extensions",
1183 "System.IO.Compression",
1185 "System.Text.Encoding.CodePages",
1186 "System.Reflection.DispatchProxy",
1187 "System.Threading.Overlapped"
1190 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1192 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1193 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1194 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1195 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1196 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1197 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1198 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1199 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1200 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1201 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1202 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 0, 0),
1203 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 1, 0),
1204 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 2, 0),
1205 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1206 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1207 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1208 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1209 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1210 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1211 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1215 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1217 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1218 if (ignored_assembly_versions [i].major != major ||
1219 ignored_assembly_versions [i].minor != minor ||
1220 ignored_assembly_versions [i].build != build ||
1221 ignored_assembly_versions [i].revision != revision)
1223 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1231 static void Main () {
1234 for (int i = 0; i < str.Length; ++i)
1235 h = ((h << 5) + h) ^ str[i];
1237 Console.WriteLine ("{0:X}", h);
1241 hash_guid (const char *str)
1245 h = ((h << 5) + h) ^ *str;
1253 is_problematic_image (MonoImage *image)
1255 int h = hash_guid (image->guid);
1257 //TODO make this more cache effiecient.
1258 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1259 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1260 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1261 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1262 size_t needle_len = strlen (needle);
1263 size_t asm_len = strlen (image->name);
1264 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1272 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1273 gboolean care_about_cli, gboolean care_about_pecoff)
1275 MonoCLIImageInfo *iinfo;
1276 MonoDotNetHeader *header;
1277 GSList *errors = NULL;
1280 MONO_PROFILER_RAISE (image_loading, (image));
1282 mono_image_init (image);
1284 iinfo = (MonoCLIImageInfo *)image->image_info;
1285 header = &iinfo->cli_header;
1287 if (!image->metadata_only) {
1288 for (l = image_loaders; l; l = l->next) {
1289 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1290 if (loader->match (image)) {
1291 image->loader = loader;
1295 if (!image->loader) {
1297 *status = MONO_IMAGE_IMAGE_INVALID;
1302 *status = MONO_IMAGE_IMAGE_INVALID;
1304 if (care_about_pecoff == FALSE)
1307 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1310 if (!mono_image_load_pe_data (image))
1313 image->loader = (MonoImageLoader*)&pe_loader;
1316 if (care_about_cli == FALSE) {
1320 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1323 if (!mono_image_load_cli_data (image))
1326 if (!image->ref_only && is_problematic_image (image)) {
1327 if (image->load_from_context) {
1328 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1330 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1331 *status = MONO_IMAGE_IMAGE_INVALID;
1336 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1339 mono_image_load_names (image);
1341 load_modules (image);
1344 MONO_PROFILER_RAISE (image_loaded, (image));
1346 *status = MONO_IMAGE_OK;
1352 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1353 g_warning ("Could not load image %s due to %s", image->name, info->message);
1354 mono_free_verify_list (errors);
1356 MONO_PROFILER_RAISE (image_failed, (image));
1357 mono_image_close (image);
1362 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1363 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1365 MonoCLIImageInfo *iinfo;
1369 if ((filed = mono_file_map_open (fname)) == NULL){
1370 if (IS_PORTABILITY_SET) {
1371 gchar *ffname = mono_portability_find_file (fname, TRUE);
1373 filed = mono_file_map_open (ffname);
1378 if (filed == NULL) {
1380 *status = MONO_IMAGE_ERROR_ERRNO;
1385 image = g_new0 (MonoImage, 1);
1386 image->raw_buffer_used = TRUE;
1387 image->raw_data_len = mono_file_map_size (filed);
1388 image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1389 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1390 if (!image->raw_data) {
1391 image->fileio_used = TRUE;
1392 image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1395 if (!image->raw_data) {
1396 mono_file_map_close (filed);
1399 *status = MONO_IMAGE_IMAGE_INVALID;
1402 iinfo = g_new0 (MonoCLIImageInfo, 1);
1403 image->image_info = iinfo;
1404 image->name = mono_path_resolve_symlinks (fname);
1405 image->ref_only = refonly;
1406 image->metadata_only = metadata_only;
1407 image->load_from_context = load_from_context;
1408 image->ref_count = 1;
1409 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1410 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1412 mono_file_map_close (filed);
1413 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1417 * mono_image_loaded_full:
1418 * \param name path or assembly name of the image to load
1419 * \param refonly Check with respect to reflection-only loads?
1421 * This routine verifies that the given image is loaded.
1422 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1424 * \returns the loaded \c MonoImage, or NULL on failure.
1427 mono_image_loaded_full (const char *name, gboolean refonly)
1431 mono_images_lock ();
1432 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1434 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1435 mono_images_unlock ();
1441 * mono_image_loaded:
1442 * \param name path or assembly name of the image to load
1443 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1444 * \returns the loaded \c MonoImage, or NULL on failure.
1447 mono_image_loaded (const char *name)
1449 return mono_image_loaded_full (name, FALSE);
1458 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1460 GuidData *data = (GuidData *)user_data;
1465 image = (MonoImage *)val;
1466 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1471 * mono_image_loaded_by_guid_full:
1474 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1477 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1481 mono_images_lock ();
1482 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1483 mono_images_unlock ();
1488 * mono_image_loaded_by_guid:
1491 mono_image_loaded_by_guid (const char *guid)
1493 return mono_image_loaded_by_guid_full (guid, FALSE);
1497 register_image (MonoImage *image)
1500 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1502 mono_images_lock ();
1503 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1506 /* Somebody else beat us to it */
1507 mono_image_addref (image2);
1508 mono_images_unlock ();
1509 mono_image_close (image);
1513 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1514 g_hash_table_insert (loaded_images, image->name, image);
1515 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1516 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1517 mono_images_unlock ();
1523 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1525 MonoCLIImageInfo *iinfo;
1529 if (!data || !data_len) {
1531 *status = MONO_IMAGE_IMAGE_INVALID;
1536 datac = (char *)g_try_malloc (data_len);
1539 *status = MONO_IMAGE_ERROR_ERRNO;
1542 memcpy (datac, data, data_len);
1545 image = g_new0 (MonoImage, 1);
1546 image->raw_data = datac;
1547 image->raw_data_len = data_len;
1548 image->raw_data_allocated = need_copy;
1549 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1550 iinfo = g_new0 (MonoCLIImageInfo, 1);
1551 image->image_info = iinfo;
1552 image->ref_only = refonly;
1553 image->metadata_only = metadata_only;
1554 image->ref_count = 1;
1556 image = do_mono_image_load (image, status, TRUE, TRUE);
1560 return register_image (image);
1564 * mono_image_open_from_data_with_name:
1567 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1569 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1573 * mono_image_open_from_data_full:
1576 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1578 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1582 * mono_image_open_from_data:
1585 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1587 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1591 /* fname is not duplicated. */
1593 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1596 MonoCLIImageInfo* iinfo;
1598 image = g_new0 (MonoImage, 1);
1599 image->raw_data = (char*) module_handle;
1600 image->is_module_handle = TRUE;
1601 iinfo = g_new0 (MonoCLIImageInfo, 1);
1602 image->image_info = iinfo;
1603 image->name = fname;
1604 image->ref_count = has_entry_point ? 0 : 1;
1605 image->has_entry_point = has_entry_point;
1607 image = do_mono_image_load (image, status, TRUE, TRUE);
1611 return register_image (image);
1616 * mono_image_open_full:
1619 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1621 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1625 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1628 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1631 g_return_val_if_fail (fname != NULL, NULL);
1634 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1635 // then assemblies need to be loaded with LoadLibrary:
1636 if (!refonly && coree_module_handle) {
1637 HMODULE module_handle;
1638 guint16 *fname_utf16;
1641 absfname = mono_path_resolve_symlinks (fname);
1644 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1645 mono_images_lock ();
1646 image = g_hash_table_lookup (loaded_images, absfname);
1647 if (image) { // Image already loaded
1648 g_assert (image->is_module_handle);
1649 if (image->has_entry_point && image->ref_count == 0) {
1650 /* Increment reference count on images loaded outside of the runtime. */
1651 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1652 /* The image is already loaded because _CorDllMain removes images from the hash. */
1653 module_handle = LoadLibrary (fname_utf16);
1654 g_assert (module_handle == (HMODULE) image->raw_data);
1656 mono_image_addref (image);
1657 mono_images_unlock ();
1659 g_free (fname_utf16);
1664 // Image not loaded, load it now
1665 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1666 module_handle = MonoLoadImage (fname_utf16);
1667 if (status && module_handle == NULL)
1668 last_error = mono_w32error_get_last ();
1670 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1671 image = g_hash_table_lookup (loaded_images, absfname);
1673 mono_image_addref (image);
1674 mono_images_unlock ();
1676 g_free (fname_utf16);
1678 if (module_handle == NULL) {
1682 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1683 *status = MONO_IMAGE_IMAGE_INVALID;
1685 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1695 g_assert (image->is_module_handle);
1696 g_assert (image->has_entry_point);
1701 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1705 absfname = mono_path_resolve_symlinks (fname);
1708 * The easiest solution would be to do all the loading inside the mutex,
1709 * but that would lead to scalability problems. So we let the loading
1710 * happen outside the mutex, and if multiple threads happen to load
1711 * the same image, we discard all but the first copy.
1713 mono_images_lock ();
1714 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1717 if (image) { // Image already loaded
1718 mono_image_addref (image);
1719 mono_images_unlock ();
1722 mono_images_unlock ();
1724 // Image not loaded, load it now
1725 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1729 return register_image (image);
1734 * \param fname filename that points to the module we want to open
1735 * \param status An error condition is returned in this field
1736 * \returns An open image of type \c MonoImage or NULL on error.
1737 * The caller holds a temporary reference to the returned image which should be cleared
1738 * when no longer needed by calling \c mono_image_close.
1739 * if NULL, then check the value of \p status for details on the error
1742 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1744 return mono_image_open_full (fname, status, FALSE);
1748 * mono_pe_file_open:
1749 * \param fname filename that points to the module we want to open
1750 * \param status An error condition is returned in this field
1751 * \returns An open image of type \c MonoImage or NULL on error. if
1752 * NULL, then check the value of \p status for details on the error.
1753 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
1754 * It's just a PE file loader, used for \c FileVersionInfo. It also does
1755 * not use the image cache.
1758 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1760 g_return_val_if_fail (fname != NULL, NULL);
1762 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1766 * mono_image_open_raw
1767 * \param fname filename that points to the module we want to open
1768 * \param status An error condition is returned in this field
1769 * \returns an image without loading neither pe or cli data.
1770 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1773 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1775 g_return_val_if_fail (fname != NULL, NULL);
1777 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1781 * mono_image_open_metadata_only:
1783 * Open an image which contains metadata only without a PE header.
1786 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1788 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1792 * mono_image_fixup_vtable:
1795 mono_image_fixup_vtable (MonoImage *image)
1798 MonoCLIImageInfo *iinfo;
1800 MonoVTableFixup *vtfixup;
1806 g_assert (image->is_module_handle);
1808 iinfo = image->image_info;
1809 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1810 if (!de->rva || !de->size)
1812 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1816 count = de->size / sizeof (MonoVTableFixup);
1818 if (!vtfixup->rva || !vtfixup->count)
1821 slot = mono_image_rva_map (image, vtfixup->rva);
1823 slot_type = vtfixup->type;
1824 slot_count = vtfixup->count;
1825 if (slot_type & VTFIXUP_TYPE_32BIT)
1826 while (slot_count--) {
1827 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1828 slot = ((guint32*) slot) + 1;
1830 else if (slot_type & VTFIXUP_TYPE_64BIT)
1831 while (slot_count--) {
1832 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1833 slot = ((guint32*) slot) + 1;
1836 g_assert_not_reached();
1841 g_assert_not_reached();
1846 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1848 g_hash_table_destroy ((GHashTable*)val);
1853 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1855 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1860 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1862 g_slist_free ((GSList*)val);
1866 * mono_image_addref:
1867 * \param image The image file we wish to add a reference to
1868 * Increases the reference count of an image.
1871 mono_image_addref (MonoImage *image)
1873 InterlockedIncrement (&image->ref_count);
1877 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1879 stream->alloc_size = stream->index = stream->offset = 0;
1880 g_free (stream->data);
1881 stream->data = NULL;
1883 g_hash_table_destroy (stream->hash);
1884 stream->hash = NULL;
1889 free_hash (GHashTable *hash)
1892 g_hash_table_destroy (hash);
1896 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1898 free_hash (cache->delegate_invoke_cache);
1899 free_hash (cache->delegate_begin_invoke_cache);
1900 free_hash (cache->delegate_end_invoke_cache);
1901 free_hash (cache->runtime_invoke_cache);
1902 free_hash (cache->runtime_invoke_vtype_cache);
1904 free_hash (cache->delegate_abstract_invoke_cache);
1906 free_hash (cache->runtime_invoke_direct_cache);
1907 free_hash (cache->managed_wrapper_cache);
1909 free_hash (cache->native_wrapper_cache);
1910 free_hash (cache->native_wrapper_aot_cache);
1911 free_hash (cache->native_wrapper_check_cache);
1912 free_hash (cache->native_wrapper_aot_check_cache);
1914 free_hash (cache->native_func_wrapper_aot_cache);
1915 free_hash (cache->remoting_invoke_cache);
1916 free_hash (cache->synchronized_cache);
1917 free_hash (cache->unbox_wrapper_cache);
1918 free_hash (cache->cominterop_invoke_cache);
1919 free_hash (cache->cominterop_wrapper_cache);
1920 free_hash (cache->thunk_invoke_cache);
1924 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1926 for (int i = 0; i < image_count; ++i) {
1928 if (!mono_image_close_except_pools (images [i]))
1935 * Returns whether mono_image_close_finish() must be called as well.
1936 * We must unload images in two steps because clearing the domain in
1937 * SGen requires the class metadata to be intact, but we need to free
1938 * the mono_g_hash_tables in case a collection occurs during domain
1939 * unloading and the roots would trip up the GC.
1942 mono_image_close_except_pools (MonoImage *image)
1945 GHashTable *loaded_images, *loaded_images_by_name;
1948 g_return_val_if_fail (image != NULL, FALSE);
1951 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1952 * register_image () can't grab an image which is being closed.
1954 mono_images_lock ();
1956 if (InterlockedDecrement (&image->ref_count) > 0) {
1957 mono_images_unlock ();
1961 loaded_images = get_loaded_images_hash (image->ref_only);
1962 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1963 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1964 if (image == image2) {
1965 /* This is not true if we are called from mono_image_open () */
1966 g_hash_table_remove (loaded_images, image->name);
1968 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1969 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1971 mono_images_unlock ();
1974 if (image->is_module_handle && image->has_entry_point) {
1975 mono_images_lock ();
1976 if (image->ref_count == 0) {
1977 /* Image will be closed by _CorDllMain. */
1978 FreeLibrary ((HMODULE) image->raw_data);
1979 mono_images_unlock ();
1982 mono_images_unlock ();
1986 MONO_PROFILER_RAISE (image_unloading, (image));
1988 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1990 mono_image_invoke_unload_hook (image);
1992 mono_metadata_clean_for_image (image);
1995 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1996 * assemblies, so we can't release these references in mono_assembly_close () since the
1997 * MonoImage might outlive its associated MonoAssembly.
1999 if (image->references && !image_is_dynamic (image)) {
2000 for (i = 0; i < image->nreferences; i++) {
2001 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2002 if (!mono_assembly_close_except_image_pools (image->references [i]))
2003 image->references [i] = NULL;
2007 if (image->references) {
2008 g_free (image->references);
2009 image->references = NULL;
2014 mono_images_lock ();
2015 if (image->is_module_handle && !image->has_entry_point)
2016 FreeLibrary ((HMODULE) image->raw_data);
2017 mono_images_unlock ();
2020 if (image->raw_buffer_used) {
2021 if (image->raw_data != NULL) {
2023 if (image->fileio_used)
2024 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
2027 mono_file_unmap (image->raw_data, image->raw_data_handle);
2031 if (image->raw_data_allocated) {
2032 /* FIXME: do we need this? (image is disposed anyway) */
2033 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2034 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2036 if ((image->raw_metadata > image->raw_data) &&
2037 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2038 image->raw_metadata = NULL;
2040 for (i = 0; i < ii->cli_section_count; i++)
2041 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2042 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2043 ii->cli_sections [i] = NULL;
2045 g_free (image->raw_data);
2048 if (debug_assembly_unload) {
2049 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2051 g_free (image->name);
2052 g_free (image->guid);
2053 g_free (image->version);
2056 if (image->method_cache)
2057 g_hash_table_destroy (image->method_cache);
2058 if (image->methodref_cache)
2059 g_hash_table_destroy (image->methodref_cache);
2060 mono_internal_hash_table_destroy (&image->class_cache);
2061 mono_conc_hashtable_destroy (image->field_cache);
2062 if (image->array_cache) {
2063 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2064 g_hash_table_destroy (image->array_cache);
2066 if (image->szarray_cache)
2067 g_hash_table_destroy (image->szarray_cache);
2068 if (image->ptr_cache)
2069 g_hash_table_destroy (image->ptr_cache);
2070 if (image->name_cache) {
2071 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2072 g_hash_table_destroy (image->name_cache);
2075 free_hash (image->delegate_bound_static_invoke_cache);
2076 free_hash (image->runtime_invoke_vcall_cache);
2077 free_hash (image->ldfld_wrapper_cache);
2078 free_hash (image->ldflda_wrapper_cache);
2079 free_hash (image->stfld_wrapper_cache);
2080 free_hash (image->isinst_cache);
2081 free_hash (image->castclass_cache);
2082 free_hash (image->icall_wrapper_cache);
2083 free_hash (image->proxy_isinst_cache);
2084 free_hash (image->var_cache_slow);
2085 free_hash (image->mvar_cache_slow);
2086 free_hash (image->var_cache_constrained);
2087 free_hash (image->mvar_cache_constrained);
2088 free_hash (image->wrapper_param_names);
2089 free_hash (image->pinvoke_scopes);
2090 free_hash (image->pinvoke_scope_filenames);
2091 free_hash (image->native_func_wrapper_cache);
2092 mono_conc_hashtable_destroy (image->typespec_cache);
2094 mono_wrapper_caches_free (&image->wrapper_caches);
2096 for (i = 0; i < image->gshared_types_len; ++i)
2097 free_hash (image->gshared_types [i]);
2098 g_free (image->gshared_types);
2100 /* The ownership of signatures is not well defined */
2101 g_hash_table_destroy (image->memberref_signatures);
2102 g_hash_table_destroy (image->helper_signatures);
2103 g_hash_table_destroy (image->method_signatures);
2105 if (image->rgctx_template_hash)
2106 g_hash_table_destroy (image->rgctx_template_hash);
2108 if (image->property_hash)
2109 mono_property_hash_destroy (image->property_hash);
2112 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2113 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2115 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2116 image->reflection_info_unregister_classes = NULL;
2118 if (image->interface_bitset) {
2119 mono_unload_interface_ids (image->interface_bitset);
2120 mono_bitset_free (image->interface_bitset);
2122 if (image->image_info){
2123 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2125 if (ii->cli_section_tables)
2126 g_free (ii->cli_section_tables);
2127 if (ii->cli_sections)
2128 g_free (ii->cli_sections);
2129 g_free (image->image_info);
2132 mono_image_close_except_pools_all (image->files, image->file_count);
2133 mono_image_close_except_pools_all (image->modules, image->module_count);
2134 if (image->modules_loaded)
2135 g_free (image->modules_loaded);
2137 mono_os_mutex_destroy (&image->szarray_cache_lock);
2138 mono_os_mutex_destroy (&image->lock);
2140 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2141 if (image_is_dynamic (image)) {
2142 /* Dynamic images are GC_MALLOCed */
2143 g_free ((char*)image->module_name);
2144 mono_dynamic_image_free ((MonoDynamicImage*)image);
2147 MONO_PROFILER_RAISE (image_unloaded, (image));
2153 mono_image_close_all (MonoImage**images, int image_count)
2155 for (int i = 0; i < image_count; ++i) {
2157 mono_image_close_finish (images [i]);
2164 mono_image_close_finish (MonoImage *image)
2168 if (image->references && !image_is_dynamic (image)) {
2169 for (i = 0; i < image->nreferences; i++) {
2170 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2171 mono_assembly_close_finish (image->references [i]);
2174 g_free (image->references);
2175 image->references = NULL;
2178 mono_image_close_all (image->files, image->file_count);
2179 mono_image_close_all (image->modules, image->module_count);
2181 #ifndef DISABLE_PERFCOUNTERS
2182 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2185 if (!image_is_dynamic (image)) {
2186 if (debug_assembly_unload)
2187 mono_mempool_invalidate (image->mempool);
2189 mono_mempool_destroy (image->mempool);
2193 if (debug_assembly_unload)
2194 mono_mempool_invalidate (image->mempool);
2196 mono_mempool_destroy (image->mempool);
2197 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2204 * \param image The image file we wish to close
2205 * Closes an image file, deallocates all memory consumed and
2206 * unmaps all possible sections of the file
2209 mono_image_close (MonoImage *image)
2211 if (mono_image_close_except_pools (image))
2212 mono_image_close_finish (image);
2216 * mono_image_strerror:
2217 * \param status an code indicating the result from a recent operation
2218 * \returns a string describing the error
2221 mono_image_strerror (MonoImageOpenStatus status)
2226 case MONO_IMAGE_ERROR_ERRNO:
2227 return strerror (errno);
2228 case MONO_IMAGE_IMAGE_INVALID:
2229 return "File does not contain a valid CIL image";
2230 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2231 return "An assembly was referenced, but could not be found";
2233 return "Internal error";
2237 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2238 guint32 lang_id, gunichar2 *name,
2239 MonoPEResourceDirEntry *entry,
2240 MonoPEResourceDir *root, guint32 level)
2242 gboolean is_string, is_dir;
2243 guint32 name_offset, dir_offset;
2245 /* Level 0 holds a directory entry for each type of resource
2246 * (identified by ID or name).
2248 * Level 1 holds a directory entry for each named resource
2249 * item, and each "anonymous" item of a particular type of
2252 * Level 2 holds a directory entry for each language pointing to
2255 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2256 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2258 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2259 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2264 } else if (level==1) {
2265 if (res_id != name_offset)
2269 is_string==TRUE && name!=lookup (name_offset)) {
2273 } else if (level==2) {
2274 if (is_string || (lang_id != 0 && name_offset != lang_id))
2277 g_assert_not_reached ();
2281 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2282 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2285 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2287 for(i=0; i<entries; i++) {
2288 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2291 ret=mono_image_walk_resource_tree (info, res_id,
2302 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2303 MonoPEResourceDataEntry *res;
2305 res = g_new0 (MonoPEResourceDataEntry, 1);
2307 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2308 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2309 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2310 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2317 * mono_image_lookup_resource:
2318 * \param image the image to look up the resource in
2319 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2320 * \param lang_id The language id.
2321 * \param name the resource name to lookup.
2322 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2323 * of the given resource. The caller should free it using \c g_free when no longer
2327 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2329 MonoCLIImageInfo *info;
2330 MonoDotNetHeader *header;
2331 MonoPEDatadir *datadir;
2332 MonoPEDirEntry *rsrc;
2333 MonoPEResourceDir *resource_dir;
2334 MonoPEResourceDirEntry *res_entries;
2341 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2343 info = (MonoCLIImageInfo *)image->image_info;
2348 header=&info->cli_header;
2353 datadir=&header->datadir;
2358 rsrc=&datadir->pe_resource_table;
2363 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2364 if(resource_dir==NULL) {
2368 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2369 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2371 for(i=0; i<entries; i++) {
2372 MonoPEResourceDirEntry *entry=&res_entries[i];
2375 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2376 name, entry, resource_dir,
2387 * mono_image_get_entry_point:
2388 * \param image the image where the entry point will be looked up.
2389 * Use this routine to determine the metadata token for method that
2390 * has been flagged as the entry point.
2391 * \returns the token for the entry point method in the image
2394 mono_image_get_entry_point (MonoImage *image)
2396 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2400 * mono_image_get_resource:
2401 * \param image the image where the resource will be looked up.
2402 * \param offset The offset to add to the resource
2403 * \param size a pointer to an int where the size of the resource will be stored
2405 * This is a low-level routine that fetches a resource from the
2406 * metadata that starts at a given \p offset. The \p size parameter is
2407 * filled with the data field as encoded in the metadata.
2409 * \returns the pointer to the resource whose offset is \p offset.
2412 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2414 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2415 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2418 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2421 data = mono_image_rva_map (image, ch->ch_resources.rva);
2426 *size = read32 (data);
2431 // Returning NULL with no error set will be interpeted as "not found"
2433 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2435 char *base_dir, *name;
2437 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2443 if (fileidx < 1 || fileidx > t->rows)
2446 mono_image_lock (image);
2447 if (image->files && image->files [fileidx - 1]) {
2448 mono_image_unlock (image);
2449 return image->files [fileidx - 1];
2451 mono_image_unlock (image);
2453 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2454 fname = mono_metadata_string_heap (image, fname_id);
2455 base_dir = g_path_get_dirname (image->name);
2456 name = g_build_filename (base_dir, fname, NULL);
2457 res = mono_image_open (name, NULL);
2461 mono_image_lock (image);
2462 if (image->files && image->files [fileidx - 1]) {
2463 MonoImage *old = res;
2464 res = image->files [fileidx - 1];
2465 mono_image_unlock (image);
2466 mono_image_close (old);
2469 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2470 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2471 mono_image_unlock (image);
2472 mono_image_close (res);
2476 for (i = 0; i < res->module_count; ++i) {
2477 if (res->modules [i] && !res->modules [i]->assembly)
2478 res->modules [i]->assembly = image->assembly;
2481 if (!image->files) {
2482 image->files = g_new0 (MonoImage*, t->rows);
2483 image->file_count = t->rows;
2485 image->files [fileidx - 1] = res;
2486 mono_image_unlock (image);
2487 /* vtable fixup can't happen with the image lock held */
2489 if (res->is_module_handle)
2490 mono_image_fixup_vtable (res);
2501 * mono_image_load_file_for_image:
2504 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2507 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2508 mono_error_assert_ok (&error);
2513 * mono_image_get_strong_name:
2514 * \param image a MonoImage
2515 * \param size a \c guint32 pointer, or NULL.
2517 * If the image has a strong name, and \p size is not NULL, the value
2518 * pointed to by size will have the size of the strong name.
2520 * \returns NULL if the image does not have a strong name, or a
2521 * pointer to the public key.
2524 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2526 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2527 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2530 if (!de->size || !de->rva)
2532 data = mono_image_rva_map (image, de->rva);
2541 * mono_image_strong_name_position:
2542 * \param image a \c MonoImage
2543 * \param size a \c guint32 pointer, or NULL.
2545 * If the image has a strong name, and \p size is not NULL, the value
2546 * pointed to by size will have the size of the strong name.
2548 * \returns the position within the image file where the strong name
2552 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2554 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2555 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2560 if (!de->size || !de->rva)
2562 pos = mono_cli_rva_image_map (image, de->rva);
2563 return pos == INVALID_ADDRESS ? 0 : pos;
2567 * mono_image_get_public_key:
2568 * \param image a \c MonoImage
2569 * \param size a \c guint32 pointer, or NULL.
2571 * This is used to obtain the public key in the \p image.
2573 * If the image has a public key, and \p size is not NULL, the value
2574 * pointed to by size will have the size of the public key.
2576 * \returns NULL if the image does not have a public key, or a pointer
2577 * to the public key.
2580 mono_image_get_public_key (MonoImage *image, guint32 *size)
2585 if (image_is_dynamic (image)) {
2587 *size = ((MonoDynamicImage*)image)->public_key_len;
2588 return (char*)((MonoDynamicImage*)image)->public_key;
2590 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2592 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2595 pubkey = mono_metadata_blob_heap (image, tok);
2596 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2603 * mono_image_get_name:
2604 * \param name a \c MonoImage
2605 * \returns the name of the assembly.
2608 mono_image_get_name (MonoImage *image)
2610 return image->assembly_name;
2614 * mono_image_get_filename:
2615 * \param image a \c MonoImage
2616 * Used to get the filename that hold the actual \c MonoImage
2617 * \returns the filename.
2620 mono_image_get_filename (MonoImage *image)
2626 * mono_image_get_guid:
2629 mono_image_get_guid (MonoImage *image)
2635 * mono_image_get_table_info:
2637 const MonoTableInfo*
2638 mono_image_get_table_info (MonoImage *image, int table_id)
2640 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2642 return &image->tables [table_id];
2646 * mono_image_get_table_rows:
2649 mono_image_get_table_rows (MonoImage *image, int table_id)
2651 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2653 return image->tables [table_id].rows;
2657 * mono_table_info_get_rows:
2660 mono_table_info_get_rows (const MonoTableInfo *table)
2666 * mono_image_get_assembly:
2667 * \param image the \c MonoImage .
2668 * Use this routine to get the assembly that owns this image.
2669 * \returns the assembly that holds this image.
2672 mono_image_get_assembly (MonoImage *image)
2674 return image->assembly;
2678 * mono_image_is_dynamic:
2679 * \param image the \c MonoImage
2681 * Determines if the given image was created dynamically through the
2682 * \c System.Reflection.Emit API
2683 * \returns TRUE if the image was created dynamically, FALSE if not.
2686 mono_image_is_dynamic (MonoImage *image)
2688 return image_is_dynamic (image);
2692 * mono_image_has_authenticode_entry:
2693 * \param image the \c MonoImage
2694 * Use this routine to determine if the image has a Authenticode
2695 * Certificate Table.
2696 * \returns TRUE if the image contains an authenticode entry in the PE
2700 mono_image_has_authenticode_entry (MonoImage *image)
2702 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2703 MonoDotNetHeader *header = &iinfo->cli_header;
2706 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2707 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2708 return ((de->rva != 0) && (de->size > 8));
2712 mono_image_alloc (MonoImage *image, guint size)
2716 #ifndef DISABLE_PERFCOUNTERS
2717 mono_perfcounters->loader_bytes += size;
2719 mono_image_lock (image);
2720 res = mono_mempool_alloc (image->mempool, size);
2721 mono_image_unlock (image);
2727 mono_image_alloc0 (MonoImage *image, guint size)
2731 #ifndef DISABLE_PERFCOUNTERS
2732 mono_perfcounters->loader_bytes += size;
2734 mono_image_lock (image);
2735 res = mono_mempool_alloc0 (image->mempool, size);
2736 mono_image_unlock (image);
2742 mono_image_strdup (MonoImage *image, const char *s)
2746 #ifndef DISABLE_PERFCOUNTERS
2747 mono_perfcounters->loader_bytes += strlen (s);
2749 mono_image_lock (image);
2750 res = mono_mempool_strdup (image->mempool, s);
2751 mono_image_unlock (image);
2757 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2760 mono_image_lock (image);
2761 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2762 mono_image_unlock (image);
2763 #ifndef DISABLE_PERFCOUNTERS
2764 mono_perfcounters->loader_bytes += strlen (buf);
2770 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2775 va_start (args, format);
2776 buf = mono_image_strdup_vprintf (image, format, args);
2782 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2786 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2787 new_list->data = data;
2788 new_list->prev = list ? list->prev : NULL;
2789 new_list->next = list;
2792 new_list->prev->next = new_list;
2794 list->prev = new_list;
2800 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2804 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2805 new_list->data = data;
2806 new_list->next = NULL;
2808 return g_slist_concat (list, new_list);
2812 mono_image_lock (MonoImage *image)
2814 mono_locks_os_acquire (&image->lock, ImageDataLock);
2818 mono_image_unlock (MonoImage *image)
2820 mono_locks_os_release (&image->lock, ImageDataLock);
2825 * mono_image_property_lookup:
2826 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2828 * LOCKING: Takes the image lock
2831 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2835 mono_image_lock (image);
2836 res = mono_property_hash_lookup (image->property_hash, subject, property);
2837 mono_image_unlock (image);
2843 * mono_image_property_insert:
2844 * Insert a new property \p property with value \p value on \p subject in \p
2845 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2847 * LOCKING: Takes the image lock
2850 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2852 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2853 mono_image_lock (image);
2854 mono_property_hash_insert (image->property_hash, subject, property, value);
2855 mono_image_unlock (image);
2859 * mono_image_property_remove:
2860 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2862 * LOCKING: Takes the image lock
2865 mono_image_property_remove (MonoImage *image, gpointer subject)
2867 mono_image_lock (image);
2868 mono_property_hash_remove_object (image->property_hash, subject);
2869 mono_image_unlock (image);
2873 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2875 MonoImage *image = klass->image;
2876 g_assert (image_is_dynamic (image));
2877 mono_image_lock (image);
2878 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2879 mono_image_unlock (image);
2882 // This is support for the mempool reference tracking feature in checked-build, but lives in image.c due to use of static variables of this file.
2885 * mono_find_image_owner:
2887 * Find the image, if any, which a given pointer is located in the memory of.
2890 mono_find_image_owner (void *ptr)
2892 mono_images_lock ();
2894 MonoImage *owner = NULL;
2896 // Iterate over both by-path image hashes
2897 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2899 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2901 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2902 GHashTableIter iter;
2905 // Iterate over images within a hash
2906 g_hash_table_iter_init (&iter, target);
2907 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2909 mono_image_lock (image);
2910 if (mono_mempool_contains_addr (image->mempool, ptr))
2912 mono_image_unlock (image);
2916 mono_images_unlock ();