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_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1130 } IgnoredAssemblyNames;
1135 const char guid [40];
1140 guint16 major, minor, build, revision;
1141 } IgnoredAssemblyVersion;
1143 const char *ignored_assemblies_file_names[] = {
1144 "System.Runtime.InteropServices.RuntimeInformation.dll",
1145 "System.Globalization.Extensions.dll",
1146 "System.IO.Compression.dll",
1147 "System.Net.Http.dll",
1148 "System.Text.Encoding.CodePages.dll",
1149 "System.Threading.Overlapped.dll"
1152 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1154 static const IgnoredAssembly ignored_assemblies [] = {
1155 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1156 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1157 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1158 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1159 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1160 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1161 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1162 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1163 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1164 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1165 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1166 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1167 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1168 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1169 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1170 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1171 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1172 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46")
1176 const char *ignored_assemblies_names[] = {
1177 "System.Runtime.InteropServices.RuntimeInformation",
1178 "System.Globalization.Extensions",
1179 "System.IO.Compression",
1181 "System.Text.Encoding.CodePages",
1182 "System.Threading.Overlapped"
1185 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1187 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1188 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1189 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1190 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1191 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1192 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1193 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1194 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1195 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1196 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1197 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1198 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1199 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1200 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1201 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1202 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1203 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1204 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1208 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1210 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1211 if (ignored_assembly_versions [i].major != major ||
1212 ignored_assembly_versions [i].minor != minor ||
1213 ignored_assembly_versions [i].build != build ||
1214 ignored_assembly_versions [i].revision != revision)
1216 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1224 static void Main () {
1227 for (int i = 0; i < str.Length; ++i)
1228 h = ((h << 5) + h) ^ str[i];
1230 Console.WriteLine ("{0:X}", h);
1234 hash_guid (const char *str)
1238 h = ((h << 5) + h) ^ *str;
1246 is_problematic_image (MonoImage *image)
1248 int h = hash_guid (image->guid);
1250 //TODO make this more cache effiecient.
1251 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1252 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1253 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1254 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1255 size_t needle_len = strlen (needle);
1256 size_t asm_len = strlen (image->name);
1257 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1265 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1266 gboolean care_about_cli, gboolean care_about_pecoff)
1268 MonoCLIImageInfo *iinfo;
1269 MonoDotNetHeader *header;
1270 GSList *errors = NULL;
1273 MONO_PROFILER_RAISE (image_loading, (image));
1275 mono_image_init (image);
1277 iinfo = (MonoCLIImageInfo *)image->image_info;
1278 header = &iinfo->cli_header;
1280 if (!image->metadata_only) {
1281 for (l = image_loaders; l; l = l->next) {
1282 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1283 if (loader->match (image)) {
1284 image->loader = loader;
1288 if (!image->loader) {
1290 *status = MONO_IMAGE_IMAGE_INVALID;
1295 *status = MONO_IMAGE_IMAGE_INVALID;
1297 if (care_about_pecoff == FALSE)
1300 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1303 if (!mono_image_load_pe_data (image))
1306 image->loader = (MonoImageLoader*)&pe_loader;
1309 if (care_about_cli == FALSE) {
1313 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1316 if (!mono_image_load_cli_data (image))
1319 if (!image->ref_only && is_problematic_image (image)) {
1320 if (image->load_from_context) {
1321 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1323 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1324 *status = MONO_IMAGE_IMAGE_INVALID;
1329 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1332 mono_image_load_names (image);
1334 load_modules (image);
1337 MONO_PROFILER_RAISE (image_loaded, (image));
1339 *status = MONO_IMAGE_OK;
1345 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1346 g_warning ("Could not load image %s due to %s", image->name, info->message);
1347 mono_free_verify_list (errors);
1349 MONO_PROFILER_RAISE (image_failed, (image));
1350 mono_image_close (image);
1355 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1356 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1358 MonoCLIImageInfo *iinfo;
1362 if ((filed = mono_file_map_open (fname)) == NULL){
1363 if (IS_PORTABILITY_SET) {
1364 gchar *ffname = mono_portability_find_file (fname, TRUE);
1366 filed = mono_file_map_open (ffname);
1371 if (filed == NULL) {
1373 *status = MONO_IMAGE_ERROR_ERRNO;
1378 image = g_new0 (MonoImage, 1);
1379 image->raw_buffer_used = TRUE;
1380 image->raw_data_len = mono_file_map_size (filed);
1381 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);
1382 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1383 if (!image->raw_data) {
1384 image->fileio_used = TRUE;
1385 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);
1388 if (!image->raw_data) {
1389 mono_file_map_close (filed);
1392 *status = MONO_IMAGE_IMAGE_INVALID;
1395 iinfo = g_new0 (MonoCLIImageInfo, 1);
1396 image->image_info = iinfo;
1397 image->name = mono_path_resolve_symlinks (fname);
1398 image->ref_only = refonly;
1399 image->metadata_only = metadata_only;
1400 image->load_from_context = load_from_context;
1401 image->ref_count = 1;
1402 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1403 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1405 mono_file_map_close (filed);
1406 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1410 * mono_image_loaded_full:
1411 * \param name path or assembly name of the image to load
1412 * \param refonly Check with respect to reflection-only loads?
1414 * This routine verifies that the given image is loaded.
1415 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1417 * \returns the loaded \c MonoImage, or NULL on failure.
1420 mono_image_loaded_full (const char *name, gboolean refonly)
1424 mono_images_lock ();
1425 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1427 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1428 mono_images_unlock ();
1434 * mono_image_loaded:
1435 * \param name path or assembly name of the image to load
1436 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1437 * \returns the loaded \c MonoImage, or NULL on failure.
1440 mono_image_loaded (const char *name)
1442 return mono_image_loaded_full (name, FALSE);
1451 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1453 GuidData *data = (GuidData *)user_data;
1458 image = (MonoImage *)val;
1459 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1464 * mono_image_loaded_by_guid_full:
1467 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1470 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1474 mono_images_lock ();
1475 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1476 mono_images_unlock ();
1481 * mono_image_loaded_by_guid:
1484 mono_image_loaded_by_guid (const char *guid)
1486 return mono_image_loaded_by_guid_full (guid, FALSE);
1490 register_image (MonoImage *image)
1493 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1495 mono_images_lock ();
1496 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1499 /* Somebody else beat us to it */
1500 mono_image_addref (image2);
1501 mono_images_unlock ();
1502 mono_image_close (image);
1506 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1507 g_hash_table_insert (loaded_images, image->name, image);
1508 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1509 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1510 mono_images_unlock ();
1516 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1518 MonoCLIImageInfo *iinfo;
1522 if (!data || !data_len) {
1524 *status = MONO_IMAGE_IMAGE_INVALID;
1529 datac = (char *)g_try_malloc (data_len);
1532 *status = MONO_IMAGE_ERROR_ERRNO;
1535 memcpy (datac, data, data_len);
1538 image = g_new0 (MonoImage, 1);
1539 image->raw_data = datac;
1540 image->raw_data_len = data_len;
1541 image->raw_data_allocated = need_copy;
1542 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1543 iinfo = g_new0 (MonoCLIImageInfo, 1);
1544 image->image_info = iinfo;
1545 image->ref_only = refonly;
1546 image->metadata_only = metadata_only;
1547 image->ref_count = 1;
1549 image = do_mono_image_load (image, status, TRUE, TRUE);
1553 return register_image (image);
1557 * mono_image_open_from_data_with_name:
1560 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1562 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1566 * mono_image_open_from_data_full:
1569 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1571 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1575 * mono_image_open_from_data:
1578 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1580 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1584 /* fname is not duplicated. */
1586 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1589 MonoCLIImageInfo* iinfo;
1591 image = g_new0 (MonoImage, 1);
1592 image->raw_data = (char*) module_handle;
1593 image->is_module_handle = TRUE;
1594 iinfo = g_new0 (MonoCLIImageInfo, 1);
1595 image->image_info = iinfo;
1596 image->name = fname;
1597 image->ref_count = has_entry_point ? 0 : 1;
1598 image->has_entry_point = has_entry_point;
1600 image = do_mono_image_load (image, status, TRUE, TRUE);
1604 return register_image (image);
1609 * mono_image_open_full:
1612 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1614 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1618 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1621 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1624 g_return_val_if_fail (fname != NULL, NULL);
1627 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1628 // then assemblies need to be loaded with LoadLibrary:
1629 if (!refonly && coree_module_handle) {
1630 HMODULE module_handle;
1631 guint16 *fname_utf16;
1634 absfname = mono_path_resolve_symlinks (fname);
1637 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1638 mono_images_lock ();
1639 image = g_hash_table_lookup (loaded_images, absfname);
1640 if (image) { // Image already loaded
1641 g_assert (image->is_module_handle);
1642 if (image->has_entry_point && image->ref_count == 0) {
1643 /* Increment reference count on images loaded outside of the runtime. */
1644 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1645 /* The image is already loaded because _CorDllMain removes images from the hash. */
1646 module_handle = LoadLibrary (fname_utf16);
1647 g_assert (module_handle == (HMODULE) image->raw_data);
1649 mono_image_addref (image);
1650 mono_images_unlock ();
1652 g_free (fname_utf16);
1657 // Image not loaded, load it now
1658 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1659 module_handle = MonoLoadImage (fname_utf16);
1660 if (status && module_handle == NULL)
1661 last_error = mono_w32error_get_last ();
1663 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1664 image = g_hash_table_lookup (loaded_images, absfname);
1666 mono_image_addref (image);
1667 mono_images_unlock ();
1669 g_free (fname_utf16);
1671 if (module_handle == NULL) {
1675 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1676 *status = MONO_IMAGE_IMAGE_INVALID;
1678 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1688 g_assert (image->is_module_handle);
1689 g_assert (image->has_entry_point);
1694 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1698 absfname = mono_path_resolve_symlinks (fname);
1701 * The easiest solution would be to do all the loading inside the mutex,
1702 * but that would lead to scalability problems. So we let the loading
1703 * happen outside the mutex, and if multiple threads happen to load
1704 * the same image, we discard all but the first copy.
1706 mono_images_lock ();
1707 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1710 if (image) { // Image already loaded
1711 mono_image_addref (image);
1712 mono_images_unlock ();
1715 mono_images_unlock ();
1717 // Image not loaded, load it now
1718 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1722 return register_image (image);
1727 * \param fname filename that points to the module we want to open
1728 * \param status An error condition is returned in this field
1729 * \returns An open image of type \c MonoImage or NULL on error.
1730 * The caller holds a temporary reference to the returned image which should be cleared
1731 * when no longer needed by calling \c mono_image_close.
1732 * if NULL, then check the value of \p status for details on the error
1735 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1737 return mono_image_open_full (fname, status, FALSE);
1741 * mono_pe_file_open:
1742 * \param fname filename that points to the module we want to open
1743 * \param status An error condition is returned in this field
1744 * \returns An open image of type \c MonoImage or NULL on error. if
1745 * NULL, then check the value of \p status for details on the error.
1746 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
1747 * It's just a PE file loader, used for \c FileVersionInfo. It also does
1748 * not use the image cache.
1751 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1753 g_return_val_if_fail (fname != NULL, NULL);
1755 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1759 * mono_image_open_raw
1760 * \param fname filename that points to the module we want to open
1761 * \param status An error condition is returned in this field
1762 * \returns an image without loading neither pe or cli data.
1763 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1766 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1768 g_return_val_if_fail (fname != NULL, NULL);
1770 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1774 * mono_image_open_metadata_only:
1776 * Open an image which contains metadata only without a PE header.
1779 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1781 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1785 * mono_image_fixup_vtable:
1788 mono_image_fixup_vtable (MonoImage *image)
1791 MonoCLIImageInfo *iinfo;
1793 MonoVTableFixup *vtfixup;
1799 g_assert (image->is_module_handle);
1801 iinfo = image->image_info;
1802 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1803 if (!de->rva || !de->size)
1805 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1809 count = de->size / sizeof (MonoVTableFixup);
1811 if (!vtfixup->rva || !vtfixup->count)
1814 slot = mono_image_rva_map (image, vtfixup->rva);
1816 slot_type = vtfixup->type;
1817 slot_count = vtfixup->count;
1818 if (slot_type & VTFIXUP_TYPE_32BIT)
1819 while (slot_count--) {
1820 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1821 slot = ((guint32*) slot) + 1;
1823 else if (slot_type & VTFIXUP_TYPE_64BIT)
1824 while (slot_count--) {
1825 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1826 slot = ((guint32*) slot) + 1;
1829 g_assert_not_reached();
1834 g_assert_not_reached();
1839 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1841 g_hash_table_destroy ((GHashTable*)val);
1846 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1848 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1853 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1855 g_slist_free ((GSList*)val);
1859 * mono_image_addref:
1860 * \param image The image file we wish to add a reference to
1861 * Increases the reference count of an image.
1864 mono_image_addref (MonoImage *image)
1866 InterlockedIncrement (&image->ref_count);
1870 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1872 stream->alloc_size = stream->index = stream->offset = 0;
1873 g_free (stream->data);
1874 stream->data = NULL;
1876 g_hash_table_destroy (stream->hash);
1877 stream->hash = NULL;
1882 free_hash (GHashTable *hash)
1885 g_hash_table_destroy (hash);
1889 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1891 free_hash (cache->delegate_invoke_cache);
1892 free_hash (cache->delegate_begin_invoke_cache);
1893 free_hash (cache->delegate_end_invoke_cache);
1894 free_hash (cache->runtime_invoke_cache);
1895 free_hash (cache->runtime_invoke_vtype_cache);
1897 free_hash (cache->delegate_abstract_invoke_cache);
1899 free_hash (cache->runtime_invoke_direct_cache);
1900 free_hash (cache->managed_wrapper_cache);
1902 free_hash (cache->native_wrapper_cache);
1903 free_hash (cache->native_wrapper_aot_cache);
1904 free_hash (cache->native_wrapper_check_cache);
1905 free_hash (cache->native_wrapper_aot_check_cache);
1907 free_hash (cache->native_func_wrapper_aot_cache);
1908 free_hash (cache->remoting_invoke_cache);
1909 free_hash (cache->synchronized_cache);
1910 free_hash (cache->unbox_wrapper_cache);
1911 free_hash (cache->cominterop_invoke_cache);
1912 free_hash (cache->cominterop_wrapper_cache);
1913 free_hash (cache->thunk_invoke_cache);
1917 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1919 for (int i = 0; i < image_count; ++i) {
1921 if (!mono_image_close_except_pools (images [i]))
1928 * Returns whether mono_image_close_finish() must be called as well.
1929 * We must unload images in two steps because clearing the domain in
1930 * SGen requires the class metadata to be intact, but we need to free
1931 * the mono_g_hash_tables in case a collection occurs during domain
1932 * unloading and the roots would trip up the GC.
1935 mono_image_close_except_pools (MonoImage *image)
1938 GHashTable *loaded_images, *loaded_images_by_name;
1941 g_return_val_if_fail (image != NULL, FALSE);
1944 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1945 * register_image () can't grab an image which is being closed.
1947 mono_images_lock ();
1949 if (InterlockedDecrement (&image->ref_count) > 0) {
1950 mono_images_unlock ();
1954 loaded_images = get_loaded_images_hash (image->ref_only);
1955 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1956 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1957 if (image == image2) {
1958 /* This is not true if we are called from mono_image_open () */
1959 g_hash_table_remove (loaded_images, image->name);
1961 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1962 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1964 mono_images_unlock ();
1967 if (image->is_module_handle && image->has_entry_point) {
1968 mono_images_lock ();
1969 if (image->ref_count == 0) {
1970 /* Image will be closed by _CorDllMain. */
1971 FreeLibrary ((HMODULE) image->raw_data);
1972 mono_images_unlock ();
1975 mono_images_unlock ();
1979 MONO_PROFILER_RAISE (image_unloading, (image));
1981 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1983 mono_image_invoke_unload_hook (image);
1985 mono_metadata_clean_for_image (image);
1988 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1989 * assemblies, so we can't release these references in mono_assembly_close () since the
1990 * MonoImage might outlive its associated MonoAssembly.
1992 if (image->references && !image_is_dynamic (image)) {
1993 for (i = 0; i < image->nreferences; i++) {
1994 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1995 if (!mono_assembly_close_except_image_pools (image->references [i]))
1996 image->references [i] = NULL;
2000 if (image->references) {
2001 g_free (image->references);
2002 image->references = NULL;
2007 mono_images_lock ();
2008 if (image->is_module_handle && !image->has_entry_point)
2009 FreeLibrary ((HMODULE) image->raw_data);
2010 mono_images_unlock ();
2013 if (image->raw_buffer_used) {
2014 if (image->raw_data != NULL) {
2016 if (image->fileio_used)
2017 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
2020 mono_file_unmap (image->raw_data, image->raw_data_handle);
2024 if (image->raw_data_allocated) {
2025 /* FIXME: do we need this? (image is disposed anyway) */
2026 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2027 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2029 if ((image->raw_metadata > image->raw_data) &&
2030 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2031 image->raw_metadata = NULL;
2033 for (i = 0; i < ii->cli_section_count; i++)
2034 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2035 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2036 ii->cli_sections [i] = NULL;
2038 g_free (image->raw_data);
2041 if (debug_assembly_unload) {
2042 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2044 g_free (image->name);
2045 g_free (image->guid);
2046 g_free (image->version);
2049 if (image->method_cache)
2050 g_hash_table_destroy (image->method_cache);
2051 if (image->methodref_cache)
2052 g_hash_table_destroy (image->methodref_cache);
2053 mono_internal_hash_table_destroy (&image->class_cache);
2054 mono_conc_hashtable_destroy (image->field_cache);
2055 if (image->array_cache) {
2056 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2057 g_hash_table_destroy (image->array_cache);
2059 if (image->szarray_cache)
2060 g_hash_table_destroy (image->szarray_cache);
2061 if (image->ptr_cache)
2062 g_hash_table_destroy (image->ptr_cache);
2063 if (image->name_cache) {
2064 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2065 g_hash_table_destroy (image->name_cache);
2068 free_hash (image->delegate_bound_static_invoke_cache);
2069 free_hash (image->runtime_invoke_vcall_cache);
2070 free_hash (image->ldfld_wrapper_cache);
2071 free_hash (image->ldflda_wrapper_cache);
2072 free_hash (image->stfld_wrapper_cache);
2073 free_hash (image->isinst_cache);
2074 free_hash (image->castclass_cache);
2075 free_hash (image->icall_wrapper_cache);
2076 free_hash (image->proxy_isinst_cache);
2077 free_hash (image->var_cache_slow);
2078 free_hash (image->mvar_cache_slow);
2079 free_hash (image->var_cache_constrained);
2080 free_hash (image->mvar_cache_constrained);
2081 free_hash (image->wrapper_param_names);
2082 free_hash (image->pinvoke_scopes);
2083 free_hash (image->pinvoke_scope_filenames);
2084 free_hash (image->native_func_wrapper_cache);
2085 mono_conc_hashtable_destroy (image->typespec_cache);
2087 mono_wrapper_caches_free (&image->wrapper_caches);
2089 for (i = 0; i < image->gshared_types_len; ++i)
2090 free_hash (image->gshared_types [i]);
2091 g_free (image->gshared_types);
2093 /* The ownership of signatures is not well defined */
2094 g_hash_table_destroy (image->memberref_signatures);
2095 g_hash_table_destroy (image->helper_signatures);
2096 g_hash_table_destroy (image->method_signatures);
2098 if (image->rgctx_template_hash)
2099 g_hash_table_destroy (image->rgctx_template_hash);
2101 if (image->property_hash)
2102 mono_property_hash_destroy (image->property_hash);
2105 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2106 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2108 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2109 image->reflection_info_unregister_classes = NULL;
2111 if (image->interface_bitset) {
2112 mono_unload_interface_ids (image->interface_bitset);
2113 mono_bitset_free (image->interface_bitset);
2115 if (image->image_info){
2116 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2118 if (ii->cli_section_tables)
2119 g_free (ii->cli_section_tables);
2120 if (ii->cli_sections)
2121 g_free (ii->cli_sections);
2122 g_free (image->image_info);
2125 mono_image_close_except_pools_all (image->files, image->file_count);
2126 mono_image_close_except_pools_all (image->modules, image->module_count);
2127 if (image->modules_loaded)
2128 g_free (image->modules_loaded);
2130 mono_os_mutex_destroy (&image->szarray_cache_lock);
2131 mono_os_mutex_destroy (&image->lock);
2133 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2134 if (image_is_dynamic (image)) {
2135 /* Dynamic images are GC_MALLOCed */
2136 g_free ((char*)image->module_name);
2137 mono_dynamic_image_free ((MonoDynamicImage*)image);
2140 MONO_PROFILER_RAISE (image_unloaded, (image));
2146 mono_image_close_all (MonoImage**images, int image_count)
2148 for (int i = 0; i < image_count; ++i) {
2150 mono_image_close_finish (images [i]);
2157 mono_image_close_finish (MonoImage *image)
2161 if (image->references && !image_is_dynamic (image)) {
2162 for (i = 0; i < image->nreferences; i++) {
2163 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2164 mono_assembly_close_finish (image->references [i]);
2167 g_free (image->references);
2168 image->references = NULL;
2171 mono_image_close_all (image->files, image->file_count);
2172 mono_image_close_all (image->modules, image->module_count);
2174 #ifndef DISABLE_PERFCOUNTERS
2175 /* FIXME: use an explicit subtraction method as soon as it's available */
2176 InterlockedAdd (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2179 if (!image_is_dynamic (image)) {
2180 if (debug_assembly_unload)
2181 mono_mempool_invalidate (image->mempool);
2183 mono_mempool_destroy (image->mempool);
2187 if (debug_assembly_unload)
2188 mono_mempool_invalidate (image->mempool);
2190 mono_mempool_destroy (image->mempool);
2191 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2198 * \param image The image file we wish to close
2199 * Closes an image file, deallocates all memory consumed and
2200 * unmaps all possible sections of the file
2203 mono_image_close (MonoImage *image)
2205 if (mono_image_close_except_pools (image))
2206 mono_image_close_finish (image);
2210 * mono_image_strerror:
2211 * \param status an code indicating the result from a recent operation
2212 * \returns a string describing the error
2215 mono_image_strerror (MonoImageOpenStatus status)
2220 case MONO_IMAGE_ERROR_ERRNO:
2221 return strerror (errno);
2222 case MONO_IMAGE_IMAGE_INVALID:
2223 return "File does not contain a valid CIL image";
2224 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2225 return "An assembly was referenced, but could not be found";
2227 return "Internal error";
2231 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2232 guint32 lang_id, gunichar2 *name,
2233 MonoPEResourceDirEntry *entry,
2234 MonoPEResourceDir *root, guint32 level)
2236 gboolean is_string, is_dir;
2237 guint32 name_offset, dir_offset;
2239 /* Level 0 holds a directory entry for each type of resource
2240 * (identified by ID or name).
2242 * Level 1 holds a directory entry for each named resource
2243 * item, and each "anonymous" item of a particular type of
2246 * Level 2 holds a directory entry for each language pointing to
2249 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2250 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2252 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2253 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2258 } else if (level==1) {
2259 if (res_id != name_offset)
2263 is_string==TRUE && name!=lookup (name_offset)) {
2267 } else if (level==2) {
2268 if (is_string || (lang_id != 0 && name_offset != lang_id))
2271 g_assert_not_reached ();
2275 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2276 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2279 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2281 for(i=0; i<entries; i++) {
2282 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2285 ret=mono_image_walk_resource_tree (info, res_id,
2296 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2297 MonoPEResourceDataEntry *res;
2299 res = g_new0 (MonoPEResourceDataEntry, 1);
2301 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2302 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2303 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2304 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2311 * mono_image_lookup_resource:
2312 * \param image the image to look up the resource in
2313 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2314 * \param lang_id The language id.
2315 * \param name the resource name to lookup.
2316 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2317 * of the given resource. The caller should free it using \c g_free when no longer
2321 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2323 MonoCLIImageInfo *info;
2324 MonoDotNetHeader *header;
2325 MonoPEDatadir *datadir;
2326 MonoPEDirEntry *rsrc;
2327 MonoPEResourceDir *resource_dir;
2328 MonoPEResourceDirEntry *res_entries;
2335 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2337 info = (MonoCLIImageInfo *)image->image_info;
2342 header=&info->cli_header;
2347 datadir=&header->datadir;
2352 rsrc=&datadir->pe_resource_table;
2357 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2358 if(resource_dir==NULL) {
2362 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2363 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2365 for(i=0; i<entries; i++) {
2366 MonoPEResourceDirEntry *entry=&res_entries[i];
2369 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2370 name, entry, resource_dir,
2381 * mono_image_get_entry_point:
2382 * \param image the image where the entry point will be looked up.
2383 * Use this routine to determine the metadata token for method that
2384 * has been flagged as the entry point.
2385 * \returns the token for the entry point method in the image
2388 mono_image_get_entry_point (MonoImage *image)
2390 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2394 * mono_image_get_resource:
2395 * \param image the image where the resource will be looked up.
2396 * \param offset The offset to add to the resource
2397 * \param size a pointer to an int where the size of the resource will be stored
2399 * This is a low-level routine that fetches a resource from the
2400 * metadata that starts at a given \p offset. The \p size parameter is
2401 * filled with the data field as encoded in the metadata.
2403 * \returns the pointer to the resource whose offset is \p offset.
2406 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2408 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2409 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2412 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2415 data = mono_image_rva_map (image, ch->ch_resources.rva);
2420 *size = read32 (data);
2425 // Returning NULL with no error set will be interpeted as "not found"
2427 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2429 char *base_dir, *name;
2431 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2437 if (fileidx < 1 || fileidx > t->rows)
2440 mono_image_lock (image);
2441 if (image->files && image->files [fileidx - 1]) {
2442 mono_image_unlock (image);
2443 return image->files [fileidx - 1];
2445 mono_image_unlock (image);
2447 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2448 fname = mono_metadata_string_heap (image, fname_id);
2449 base_dir = g_path_get_dirname (image->name);
2450 name = g_build_filename (base_dir, fname, NULL);
2451 res = mono_image_open (name, NULL);
2455 mono_image_lock (image);
2456 if (image->files && image->files [fileidx - 1]) {
2457 MonoImage *old = res;
2458 res = image->files [fileidx - 1];
2459 mono_image_unlock (image);
2460 mono_image_close (old);
2463 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2464 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2465 mono_image_unlock (image);
2466 mono_image_close (res);
2470 for (i = 0; i < res->module_count; ++i) {
2471 if (res->modules [i] && !res->modules [i]->assembly)
2472 res->modules [i]->assembly = image->assembly;
2475 if (!image->files) {
2476 image->files = g_new0 (MonoImage*, t->rows);
2477 image->file_count = t->rows;
2479 image->files [fileidx - 1] = res;
2480 mono_image_unlock (image);
2481 /* vtable fixup can't happen with the image lock held */
2483 if (res->is_module_handle)
2484 mono_image_fixup_vtable (res);
2495 * mono_image_load_file_for_image:
2498 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2501 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2502 mono_error_assert_ok (&error);
2507 * mono_image_get_strong_name:
2508 * \param image a MonoImage
2509 * \param size a \c guint32 pointer, or NULL.
2511 * If the image has a strong name, and \p size is not NULL, the value
2512 * pointed to by size will have the size of the strong name.
2514 * \returns NULL if the image does not have a strong name, or a
2515 * pointer to the public key.
2518 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2520 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2521 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2524 if (!de->size || !de->rva)
2526 data = mono_image_rva_map (image, de->rva);
2535 * mono_image_strong_name_position:
2536 * \param image a \c MonoImage
2537 * \param size a \c guint32 pointer, or NULL.
2539 * If the image has a strong name, and \p size is not NULL, the value
2540 * pointed to by size will have the size of the strong name.
2542 * \returns the position within the image file where the strong name
2546 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2548 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2549 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2554 if (!de->size || !de->rva)
2556 pos = mono_cli_rva_image_map (image, de->rva);
2557 return pos == INVALID_ADDRESS ? 0 : pos;
2561 * mono_image_get_public_key:
2562 * \param image a \c MonoImage
2563 * \param size a \c guint32 pointer, or NULL.
2565 * This is used to obtain the public key in the \p image.
2567 * If the image has a public key, and \p size is not NULL, the value
2568 * pointed to by size will have the size of the public key.
2570 * \returns NULL if the image does not have a public key, or a pointer
2571 * to the public key.
2574 mono_image_get_public_key (MonoImage *image, guint32 *size)
2579 if (image_is_dynamic (image)) {
2581 *size = ((MonoDynamicImage*)image)->public_key_len;
2582 return (char*)((MonoDynamicImage*)image)->public_key;
2584 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2586 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2589 pubkey = mono_metadata_blob_heap (image, tok);
2590 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2597 * mono_image_get_name:
2598 * \param name a \c MonoImage
2599 * \returns the name of the assembly.
2602 mono_image_get_name (MonoImage *image)
2604 return image->assembly_name;
2608 * mono_image_get_filename:
2609 * \param image a \c MonoImage
2610 * Used to get the filename that hold the actual \c MonoImage
2611 * \returns the filename.
2614 mono_image_get_filename (MonoImage *image)
2620 * mono_image_get_guid:
2623 mono_image_get_guid (MonoImage *image)
2629 * mono_image_get_table_info:
2631 const MonoTableInfo*
2632 mono_image_get_table_info (MonoImage *image, int table_id)
2634 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2636 return &image->tables [table_id];
2640 * mono_image_get_table_rows:
2643 mono_image_get_table_rows (MonoImage *image, int table_id)
2645 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2647 return image->tables [table_id].rows;
2651 * mono_table_info_get_rows:
2654 mono_table_info_get_rows (const MonoTableInfo *table)
2660 * mono_image_get_assembly:
2661 * \param image the \c MonoImage .
2662 * Use this routine to get the assembly that owns this image.
2663 * \returns the assembly that holds this image.
2666 mono_image_get_assembly (MonoImage *image)
2668 return image->assembly;
2672 * mono_image_is_dynamic:
2673 * \param image the \c MonoImage
2675 * Determines if the given image was created dynamically through the
2676 * \c System.Reflection.Emit API
2677 * \returns TRUE if the image was created dynamically, FALSE if not.
2680 mono_image_is_dynamic (MonoImage *image)
2682 return image_is_dynamic (image);
2686 * mono_image_has_authenticode_entry:
2687 * \param image the \c MonoImage
2688 * Use this routine to determine if the image has a Authenticode
2689 * Certificate Table.
2690 * \returns TRUE if the image contains an authenticode entry in the PE
2694 mono_image_has_authenticode_entry (MonoImage *image)
2696 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2697 MonoDotNetHeader *header = &iinfo->cli_header;
2700 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2701 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2702 return ((de->rva != 0) && (de->size > 8));
2706 mono_image_alloc (MonoImage *image, guint size)
2710 #ifndef DISABLE_PERFCOUNTERS
2711 InterlockedAdd (&mono_perfcounters->loader_bytes, size);
2713 mono_image_lock (image);
2714 res = mono_mempool_alloc (image->mempool, size);
2715 mono_image_unlock (image);
2721 mono_image_alloc0 (MonoImage *image, guint size)
2725 #ifndef DISABLE_PERFCOUNTERS
2726 InterlockedAdd (&mono_perfcounters->loader_bytes, size);
2728 mono_image_lock (image);
2729 res = mono_mempool_alloc0 (image->mempool, size);
2730 mono_image_unlock (image);
2736 mono_image_strdup (MonoImage *image, const char *s)
2740 #ifndef DISABLE_PERFCOUNTERS
2741 InterlockedAdd (&mono_perfcounters->loader_bytes, strlen (s));
2743 mono_image_lock (image);
2744 res = mono_mempool_strdup (image->mempool, s);
2745 mono_image_unlock (image);
2751 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2754 mono_image_lock (image);
2755 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2756 mono_image_unlock (image);
2757 #ifndef DISABLE_PERFCOUNTERS
2758 InterlockedAdd (&mono_perfcounters->loader_bytes, strlen (buf));
2764 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2769 va_start (args, format);
2770 buf = mono_image_strdup_vprintf (image, format, args);
2776 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2780 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2781 new_list->data = data;
2782 new_list->prev = list ? list->prev : NULL;
2783 new_list->next = list;
2786 new_list->prev->next = new_list;
2788 list->prev = new_list;
2794 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2798 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2799 new_list->data = data;
2800 new_list->next = NULL;
2802 return g_slist_concat (list, new_list);
2806 mono_image_lock (MonoImage *image)
2808 mono_locks_os_acquire (&image->lock, ImageDataLock);
2812 mono_image_unlock (MonoImage *image)
2814 mono_locks_os_release (&image->lock, ImageDataLock);
2819 * mono_image_property_lookup:
2820 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2822 * LOCKING: Takes the image lock
2825 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2829 mono_image_lock (image);
2830 res = mono_property_hash_lookup (image->property_hash, subject, property);
2831 mono_image_unlock (image);
2837 * mono_image_property_insert:
2838 * Insert a new property \p property with value \p value on \p subject in \p
2839 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2841 * LOCKING: Takes the image lock
2844 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2846 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2847 mono_image_lock (image);
2848 mono_property_hash_insert (image->property_hash, subject, property, value);
2849 mono_image_unlock (image);
2853 * mono_image_property_remove:
2854 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2856 * LOCKING: Takes the image lock
2859 mono_image_property_remove (MonoImage *image, gpointer subject)
2861 mono_image_lock (image);
2862 mono_property_hash_remove_object (image->property_hash, subject);
2863 mono_image_unlock (image);
2867 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2869 MonoImage *image = klass->image;
2870 g_assert (image_is_dynamic (image));
2871 mono_image_lock (image);
2872 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2873 mono_image_unlock (image);
2876 // 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.
2879 * mono_find_image_owner:
2881 * Find the image, if any, which a given pointer is located in the memory of.
2884 mono_find_image_owner (void *ptr)
2886 mono_images_lock ();
2888 MonoImage *owner = NULL;
2890 // Iterate over both by-path image hashes
2891 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2893 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2895 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2896 GHashTableIter iter;
2899 // Iterate over images within a hash
2900 g_hash_table_iter_init (&iter, target);
2901 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2903 mono_image_lock (image);
2904 if (mono_mempool_contains_addr (image->mempool, ptr))
2906 mono_image_unlock (image);
2910 mono_images_unlock ();