2 * image.c: Routines for manipulating an image stored in an
3 * extended PE/COFF file.
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #include "mono-endian.h"
23 #include "tabledefs.h"
24 #include "tokentype.h"
25 #include "metadata-internals.h"
26 #include "profiler-private.h"
30 #include <mono/utils/checked-build.h>
31 #include <mono/utils/mono-logger-internals.h>
32 #include <mono/utils/mono-path.h>
33 #include <mono/utils/mono-mmap.h>
34 #include <mono/utils/mono-io-portability.h>
35 #include <mono/utils/atomic.h>
36 #include <mono/metadata/class-internals.h>
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/object-internals.h>
39 #include <mono/metadata/security-core-clr.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/verify.h>
42 #include <mono/metadata/image-internals.h>
43 #include <sys/types.h>
48 #include <mono/metadata/w32error.h>
50 #define INVALID_ADDRESS 0xffffffff
52 // Amount initially reserved in each image's mempool.
53 // FIXME: This number is arbitrary, a more practical number should be found
54 #define INITIAL_IMAGE_SIZE 512
57 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
58 * There are four, for all combinations of [look up by path or assembly name?]
59 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
63 IMAGES_HASH_PATH_REFONLY = 1,
65 IMAGES_HASH_NAME_REFONLY = 3,
68 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
71 get_loaded_images_hash (gboolean refonly)
73 int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
74 return loaded_images_hashes [idx];
78 get_loaded_images_by_name_hash (gboolean refonly)
80 int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
81 return loaded_images_hashes [idx];
84 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
85 // Can be used on modules loaded through either the "file" or "module" mechanism
87 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
90 MonoAssembly *assembly = assemblyImage->assembly;
93 // Assembly currently assigned
94 MonoAssembly *assemblyOld = image->assembly;
96 if (assemblyOld == assembly)
98 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);
101 gpointer result = InterlockedExchangePointer((gpointer *)&image->assembly, assembly);
102 if (result == assembly)
107 static gboolean debug_assembly_unload = FALSE;
109 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
110 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
111 static gboolean mutex_inited;
112 static mono_mutex_t images_mutex;
114 static void install_pe_loader (void);
116 typedef struct ImageUnloadHook ImageUnloadHook;
117 struct ImageUnloadHook {
118 MonoImageUnloadFunc func;
122 static GSList *image_unload_hooks;
125 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
127 ImageUnloadHook *hook;
129 g_return_if_fail (func != NULL);
131 hook = g_new0 (ImageUnloadHook, 1);
133 hook->user_data = user_data;
134 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
138 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
141 ImageUnloadHook *hook;
143 for (l = image_unload_hooks; l; l = l->next) {
144 hook = (ImageUnloadHook *)l->data;
146 if (hook->func == func && hook->user_data == user_data) {
148 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
155 mono_image_invoke_unload_hook (MonoImage *image)
158 ImageUnloadHook *hook;
160 for (l = image_unload_hooks; l; l = l->next) {
161 hook = (ImageUnloadHook *)l->data;
163 hook->func (image, hook->user_data);
167 static GSList *image_loaders;
170 mono_install_image_loader (const MonoImageLoader *loader)
172 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
175 /* returns offset relative to image->raw_data */
177 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
179 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
180 const int top = iinfo->cli_section_count;
181 MonoSectionTable *tables = iinfo->cli_section_tables;
184 if (image->metadata_only)
187 for (i = 0; i < top; i++){
188 if ((addr >= tables->st_virtual_address) &&
189 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
191 if (image->is_module_handle)
194 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
198 return INVALID_ADDRESS;
202 * mono_images_rva_map:
203 * @image: a MonoImage
204 * @addr: relative virtual address (RVA)
206 * This is a low-level routine used by the runtime to map relative
207 * virtual address (RVA) into their location in memory.
209 * Returns: the address in memory for the given RVA, or NULL if the
210 * RVA is not valid for this image.
213 mono_image_rva_map (MonoImage *image, guint32 addr)
215 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
216 const int top = iinfo->cli_section_count;
217 MonoSectionTable *tables = iinfo->cli_section_tables;
221 if (image->is_module_handle) {
222 if (addr && addr < image->raw_data_len)
223 return image->raw_data + addr;
229 for (i = 0; i < top; i++){
230 if ((addr >= tables->st_virtual_address) &&
231 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
232 if (!iinfo->cli_sections [i]) {
233 if (!mono_image_ensure_section_idx (image, i))
236 return (char*)iinfo->cli_sections [i] +
237 (addr - tables->st_virtual_address);
247 * Initialize the global variables used by this module.
250 mono_images_init (void)
252 mono_os_mutex_init_recursive (&images_mutex);
255 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
256 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
258 debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
260 install_pe_loader ();
266 * mono_images_cleanup:
268 * Free all resources used by this module.
271 mono_images_cleanup (void)
276 mono_os_mutex_destroy (&images_mutex);
278 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
279 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
280 g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
281 while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
282 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
285 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
286 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
288 mutex_inited = FALSE;
292 * mono_image_ensure_section_idx:
293 * @image: The image we are operating on
294 * @section: section number that we will load/map into memory
296 * This routine makes sure that we have an in-memory copy of
297 * an image section (.text, .rsrc, .data).
299 * Returns: TRUE on success
302 mono_image_ensure_section_idx (MonoImage *image, int section)
304 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
305 MonoSectionTable *sect;
307 g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
309 if (iinfo->cli_sections [section] != NULL)
312 sect = &iinfo->cli_section_tables [section];
314 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
317 if (image->is_module_handle)
318 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
321 /* FIXME: we ignore the writable flag since we don't patch the binary */
322 iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
327 * mono_image_ensure_section:
328 * @image: The image we are operating on
329 * @section: section name that we will load/map into memory
331 * This routine makes sure that we have an in-memory copy of
332 * an image section (.text, .rsrc, .data).
334 * Returns: TRUE on success
337 mono_image_ensure_section (MonoImage *image, const char *section)
339 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
342 for (i = 0; i < ii->cli_section_count; i++){
343 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
346 return mono_image_ensure_section_idx (image, i);
352 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
354 const int top = iinfo->cli_header.coff.coff_sections;
357 iinfo->cli_section_count = top;
358 iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
359 iinfo->cli_sections = g_new0 (void *, top);
361 for (i = 0; i < top; i++){
362 MonoSectionTable *t = &iinfo->cli_section_tables [i];
364 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
366 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
367 offset += sizeof (MonoSectionTable);
369 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
370 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
371 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
372 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
373 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
374 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
375 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
376 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
377 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
378 t->st_flags = GUINT32_FROM_LE (t->st_flags);
380 /* consistency checks here */
387 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
391 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
392 if (offset == INVALID_ADDRESS)
395 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
397 memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
399 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
400 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
401 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
402 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
403 SWAP32 (iinfo->cli_cli_header.ch_size);
404 SWAP32 (iinfo->cli_cli_header.ch_flags);
405 SWAP32 (iinfo->cli_cli_header.ch_entry_point);
406 SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
407 SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
408 SWAPPDE (iinfo->cli_cli_header.ch_metadata);
409 SWAPPDE (iinfo->cli_cli_header.ch_resources);
410 SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
411 SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
412 SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
413 SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
414 SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
415 SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
416 SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
417 SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
418 SWAPPDE (iinfo->cli_cli_header.ch_module_image);
419 SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
420 SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
421 SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
422 SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
427 /* Catch new uses of the fields that are supposed to be zero */
429 if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
430 (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
431 (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
432 (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
433 (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
434 (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
435 (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
436 (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
437 (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
440 * No need to scare people who are testing this, I am just
441 * labelling this as a LAMESPEC
443 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
451 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
453 guint32 offset, size;
459 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
460 if (offset == INVALID_ADDRESS)
463 size = iinfo->cli_cli_header.ch_metadata.size;
465 if (offset + size > image->raw_data_len)
467 image->raw_metadata = image->raw_data + offset;
469 /* 24.2.1: Metadata root starts here */
470 ptr = image->raw_metadata;
472 if (strncmp (ptr, "BSJB", 4) == 0){
473 guint32 version_string_len;
476 image->md_version_major = read16 (ptr);
478 image->md_version_minor = read16 (ptr);
481 version_string_len = read32 (ptr);
483 image->version = g_strndup (ptr, version_string_len);
484 ptr += version_string_len;
485 pad = ptr - image->raw_metadata;
487 ptr += 4 - (pad % 4);
491 /* skip over flags */
494 streams = read16 (ptr);
497 for (i = 0; i < streams; i++){
498 if (strncmp (ptr + 8, "#~", 3) == 0){
499 image->heap_tables.data = image->raw_metadata + read32 (ptr);
500 image->heap_tables.size = read32 (ptr + 4);
502 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
503 image->heap_strings.data = image->raw_metadata + read32 (ptr);
504 image->heap_strings.size = read32 (ptr + 4);
506 } else if (strncmp (ptr + 8, "#US", 4) == 0){
507 image->heap_us.data = image->raw_metadata + read32 (ptr);
508 image->heap_us.size = read32 (ptr + 4);
510 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
511 image->heap_blob.data = image->raw_metadata + read32 (ptr);
512 image->heap_blob.size = read32 (ptr + 4);
514 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
515 image->heap_guid.data = image->raw_metadata + read32 (ptr);
516 image->heap_guid.size = read32 (ptr + 4);
518 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
519 image->heap_tables.data = image->raw_metadata + read32 (ptr);
520 image->heap_tables.size = read32 (ptr + 4);
522 image->uncompressed_metadata = TRUE;
523 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);
524 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
525 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
526 image->heap_pdb.size = read32 (ptr + 4);
529 g_message ("Unknown heap type: %s\n", ptr + 8);
530 ptr += 8 + strlen (ptr + 8) + 1;
532 pad = ptr - image->raw_metadata;
534 ptr += 4 - (pad % 4);
537 i = ((MonoImageLoader*)image->loader)->load_tables (image);
538 g_assert (image->heap_guid.data);
540 if (!image->metadata_only) {
541 g_assert (image->heap_guid.size >= 16);
543 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
545 /* PPDB files have no guid */
546 guint8 empty_guid [16];
548 memset (empty_guid, 0, sizeof (empty_guid));
550 image->guid = mono_guid_to_string (empty_guid);
557 * Load representation of logical metadata tables, from the "#~" stream
560 load_tables (MonoImage *image)
562 const char *heap_tables = image->heap_tables.data;
565 int valid = 0, table;
568 heap_sizes = heap_tables [6];
569 image->idx_string_wide = ((heap_sizes & 0x01) == 1);
570 image->idx_guid_wide = ((heap_sizes & 0x02) == 2);
571 image->idx_blob_wide = ((heap_sizes & 0x04) == 4);
573 valid_mask = read64 (heap_tables + 8);
574 rows = (const guint32 *) (heap_tables + 24);
576 for (table = 0; table < 64; table++){
577 if ((valid_mask & ((guint64) 1 << table)) == 0){
578 if (table > MONO_TABLE_LAST)
580 image->tables [table].rows = 0;
583 if (table > MONO_TABLE_LAST) {
584 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
586 image->tables [table].rows = read32 (rows);
592 image->tables_base = (heap_tables + 24) + (4 * valid);
594 /* They must be the same */
595 g_assert ((const void *) image->tables_base == (const void *) rows);
597 if (image->heap_pdb.size) {
599 * Obtain token sizes from the pdb stream.
601 /* 24 = guid + entry point */
603 image->referenced_tables = read64 (image->heap_pdb.data + pos);
605 image->referenced_table_rows = g_new0 (int, 64);
606 for (int i = 0; i < 64; ++i) {
607 if (image->referenced_tables & ((guint64)1 << i)) {
608 image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
614 mono_metadata_compute_table_bases (image);
619 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
621 if (!load_metadata_ptrs (image, iinfo))
624 return load_tables (image);
628 mono_image_check_for_module_cctor (MonoImage *image)
630 MonoTableInfo *t, *mt;
631 t = &image->tables [MONO_TABLE_TYPEDEF];
632 mt = &image->tables [MONO_TABLE_METHOD];
633 if (image_is_dynamic (image)) {
635 image->checked_module_cctor = TRUE;
639 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
640 const char *name = mono_metadata_string_heap (image, nameidx);
641 if (strcmp (name, "<Module>") == 0) {
642 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
645 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
647 last_method = mt->rows;
648 for (; first_method < last_method; first_method++) {
649 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
650 name = mono_metadata_string_heap (image, nameidx);
651 if (strcmp (name, ".cctor") == 0) {
652 image->has_module_cctor = TRUE;
653 image->checked_module_cctor = TRUE;
659 image->has_module_cctor = FALSE;
660 image->checked_module_cctor = TRUE;
664 load_modules (MonoImage *image)
671 t = &image->tables [MONO_TABLE_MODULEREF];
672 image->modules = g_new0 (MonoImage *, t->rows);
673 image->modules_loaded = g_new0 (gboolean, t->rows);
674 image->module_count = t->rows;
678 * mono_image_load_module_checked:
680 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
681 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
684 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
687 MonoTableInfo *file_table;
690 gboolean refonly = image->ref_only;
691 GList *list_iter, *valid_modules = NULL;
692 MonoImageOpenStatus status;
696 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
698 if (image->modules_loaded [idx - 1])
699 return image->modules [idx - 1];
701 file_table = &image->tables [MONO_TABLE_FILE];
702 for (i = 0; i < file_table->rows; i++) {
703 guint32 cols [MONO_FILE_SIZE];
704 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
705 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
707 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
710 t = &image->tables [MONO_TABLE_MODULEREF];
711 base_dir = g_path_get_dirname (image->name);
716 guint32 cols [MONO_MODULEREF_SIZE];
717 /* if there is no file table, we try to load the module... */
718 int valid = file_table->rows == 0;
720 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
721 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
722 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
723 /* be safe with string dups, but we could just compare string indexes */
724 if (strcmp (list_iter->data, name) == 0) {
730 module_ref = g_build_filename (base_dir, name, NULL);
731 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
733 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
734 mono_image_close (moduleImage);
737 g_list_free (valid_modules);
741 image->modules [idx - 1] = moduleImage;
744 if (image->modules [idx - 1]->is_module_handle)
745 mono_image_fixup_vtable (image->modules [idx - 1]);
747 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
753 image->modules_loaded [idx - 1] = TRUE;
756 g_list_free (valid_modules);
758 return image->modules [idx - 1];
762 mono_image_load_module (MonoImage *image, int idx)
765 MonoImage *result = mono_image_load_module_checked (image, idx, &error);
766 mono_error_assert_ok (&error);
771 class_key_extract (gpointer value)
773 MonoClass *klass = (MonoClass *)value;
775 return GUINT_TO_POINTER (klass->type_token);
779 class_next_value (gpointer value)
781 MonoClassDef *klass = (MonoClassDef *)value;
783 return (gpointer*)&klass->next_class_cache;
787 mono_image_init (MonoImage *image)
789 mono_os_mutex_init_recursive (&image->lock);
790 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
792 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
793 mono_internal_hash_table_init (&image->class_cache,
797 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
799 image->typespec_cache = g_hash_table_new (NULL, NULL);
800 image->memberref_signatures = g_hash_table_new (NULL, NULL);
801 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
802 image->method_signatures = g_hash_table_new (NULL, NULL);
804 image->property_hash = mono_property_hash_new ();
807 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
808 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
809 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
810 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
811 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
820 * Returns < 0 to indicate an error.
823 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
825 MonoDotNetHeader64 header64;
828 if (!image->is_module_handle)
830 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
833 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
835 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
838 /* endian swap the fields common between PE and PE+ */
839 SWAP32 (header->coff.coff_time);
840 SWAP32 (header->coff.coff_symptr);
841 SWAP32 (header->coff.coff_symcount);
842 SWAP16 (header->coff.coff_machine);
843 SWAP16 (header->coff.coff_sections);
844 SWAP16 (header->coff.coff_opt_header_size);
845 SWAP16 (header->coff.coff_attributes);
847 SWAP32 (header->pe.pe_code_size);
848 SWAP32 (header->pe.pe_uninit_data_size);
849 SWAP32 (header->pe.pe_rva_entry_point);
850 SWAP32 (header->pe.pe_rva_code_base);
851 SWAP32 (header->pe.pe_rva_data_base);
852 SWAP16 (header->pe.pe_magic);
854 /* now we are ready for the basic tests */
856 if (header->pe.pe_magic == 0x10B) {
857 offset += sizeof (MonoDotNetHeader);
858 SWAP32 (header->pe.pe_data_size);
859 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
862 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
863 SWAP32 (header->nt.pe_stack_reserve);
864 SWAP32 (header->nt.pe_stack_commit);
865 SWAP32 (header->nt.pe_heap_reserve);
866 SWAP32 (header->nt.pe_heap_commit);
867 } else if (header->pe.pe_magic == 0x20B) {
868 /* PE32+ file format */
869 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
871 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
872 offset += sizeof (MonoDotNetHeader64);
873 /* copy the fields already swapped. the last field, pe_data_size, is missing */
874 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
875 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
876 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
878 SWAP64 (header64.nt.pe_image_base);
879 header->nt.pe_image_base = header64.nt.pe_image_base;
880 SWAP64 (header64.nt.pe_stack_reserve);
881 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
882 SWAP64 (header64.nt.pe_stack_commit);
883 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
884 SWAP64 (header64.nt.pe_heap_reserve);
885 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
886 SWAP64 (header64.nt.pe_heap_commit);
887 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
889 header->nt.pe_section_align = header64.nt.pe_section_align;
890 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
891 header->nt.pe_os_major = header64.nt.pe_os_major;
892 header->nt.pe_os_minor = header64.nt.pe_os_minor;
893 header->nt.pe_user_major = header64.nt.pe_user_major;
894 header->nt.pe_user_minor = header64.nt.pe_user_minor;
895 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
896 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
897 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
898 header->nt.pe_image_size = header64.nt.pe_image_size;
899 header->nt.pe_header_size = header64.nt.pe_header_size;
900 header->nt.pe_checksum = header64.nt.pe_checksum;
901 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
902 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
903 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
904 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
906 /* copy the datadir */
907 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
912 /* MonoPEHeaderNT: not used yet */
913 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
914 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
915 SWAP16 (header->nt.pe_os_major); /* must be 4 */
916 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
917 SWAP16 (header->nt.pe_user_major);
918 SWAP16 (header->nt.pe_user_minor);
919 SWAP16 (header->nt.pe_subsys_major);
920 SWAP16 (header->nt.pe_subsys_minor);
921 SWAP32 (header->nt.pe_reserved_1);
922 SWAP32 (header->nt.pe_image_size);
923 SWAP32 (header->nt.pe_header_size);
924 SWAP32 (header->nt.pe_checksum);
925 SWAP16 (header->nt.pe_subsys_required);
926 SWAP16 (header->nt.pe_dll_flags);
927 SWAP32 (header->nt.pe_loader_flags);
928 SWAP32 (header->nt.pe_data_dir_count);
930 /* MonoDotNetHeader: mostly unused */
931 SWAPPDE (header->datadir.pe_export_table);
932 SWAPPDE (header->datadir.pe_import_table);
933 SWAPPDE (header->datadir.pe_resource_table);
934 SWAPPDE (header->datadir.pe_exception_table);
935 SWAPPDE (header->datadir.pe_certificate_table);
936 SWAPPDE (header->datadir.pe_reloc_table);
937 SWAPPDE (header->datadir.pe_debug);
938 SWAPPDE (header->datadir.pe_copyright);
939 SWAPPDE (header->datadir.pe_global_ptr);
940 SWAPPDE (header->datadir.pe_tls_table);
941 SWAPPDE (header->datadir.pe_load_config_table);
942 SWAPPDE (header->datadir.pe_bound_import);
943 SWAPPDE (header->datadir.pe_iat);
944 SWAPPDE (header->datadir.pe_delay_import_desc);
945 SWAPPDE (header->datadir.pe_cli_header);
946 SWAPPDE (header->datadir.pe_reserved);
949 if (image->is_module_handle)
950 image->raw_data_len = header->nt.pe_image_size;
957 mono_image_load_pe_data (MonoImage *image)
959 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
963 pe_image_load_pe_data (MonoImage *image)
965 MonoCLIImageInfo *iinfo;
966 MonoDotNetHeader *header;
967 MonoMSDOSHeader msdos;
970 iinfo = (MonoCLIImageInfo *)image->image_info;
971 header = &iinfo->cli_header;
974 if (!image->is_module_handle)
976 if (offset + sizeof (msdos) > image->raw_data_len)
978 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
980 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
983 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
985 offset = msdos.pe_offset;
987 offset = do_load_header (image, header, offset);
992 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
994 if (header->coff.coff_machine != 0x14c)
1000 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1001 * which produces binaries with 7.0. From Sergey:
1003 * The reason is that MSVC7 uses traditional compile/link
1004 * sequence for CIL executables, and VS.NET (and Framework
1005 * SDK) includes linker version 7, that puts 7.0 in this
1006 * field. That's why it's currently not possible to load VC
1007 * binaries with Mono. This field is pretty much meaningless
1008 * anyway (what linker?).
1010 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1015 * FIXME: byte swap all addresses here for header.
1018 if (!load_section_tables (image, iinfo, offset))
1028 mono_image_load_cli_data (MonoImage *image)
1030 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1034 pe_image_load_cli_data (MonoImage *image)
1036 MonoCLIImageInfo *iinfo;
1037 MonoDotNetHeader *header;
1039 iinfo = (MonoCLIImageInfo *)image->image_info;
1040 header = &iinfo->cli_header;
1042 /* Load the CLI header */
1043 if (!mono_image_load_cli_header (image, iinfo))
1046 if (!mono_image_load_metadata (image, iinfo))
1053 mono_image_load_names (MonoImage *image)
1055 /* modules don't have an assembly table row */
1056 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1057 image->assembly_name = mono_metadata_string_heap (image,
1058 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1059 0, MONO_ASSEMBLY_NAME));
1062 /* Portable pdb images don't have a MODULE row */
1063 if (image->tables [MONO_TABLE_MODULE].rows) {
1064 image->module_name = mono_metadata_string_heap (image,
1065 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1066 0, MONO_MODULE_NAME));
1071 pe_image_load_tables (MonoImage *image)
1077 pe_image_match (MonoImage *image)
1079 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1084 static const MonoImageLoader pe_loader = {
1086 pe_image_load_pe_data,
1087 pe_image_load_cli_data,
1088 pe_image_load_tables,
1092 install_pe_loader (void)
1094 mono_install_image_loader (&pe_loader);
1100 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1101 Mono provides its own implementation of those assemblies so it's safe to do so.
1103 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1105 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1107 This is to be removed once a proper fix is shipped through nuget.
1112 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1113 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1114 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1115 SYS_NET_HTTP = 3, //System.Net.Http
1116 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1117 SYS_REF_DISP_PROXY = 5, //System.Reflection.DispatchProxy
1118 SYS_VALUE_TUPLE = 6, //System.ValueTuple
1119 } IgnoredAssemblyNames;
1124 const char guid [40];
1129 guint16 major, minor, build, revision;
1130 } IgnoredAssemblyVersion;
1132 const char *ignored_assemblies_file_names[] = {
1133 "System.Runtime.InteropServices.RuntimeInformation.dll",
1134 "System.Globalization.Extensions.dll",
1135 "System.IO.Compression.dll",
1136 "System.Net.Http.dll",
1137 "System.Text.Encoding.CodePages.dll",
1138 "System.Reflection.DispatchProxy.dll",
1139 "System.ValueTuple.dll"
1142 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1144 static const IgnoredAssembly ignored_assemblies [] = {
1145 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1146 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1147 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1148 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1149 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1150 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1151 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1152 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1153 IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1154 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1155 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1156 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1157 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1158 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1159 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1160 IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
1164 const char *ignored_assemblies_names[] = {
1165 "System.Runtime.InteropServices.RuntimeInformation",
1166 "System.Globalization.Extensions",
1167 "System.IO.Compression",
1169 "System.Text.Encoding.CodePages",
1170 "System.Reflection.DispatchProxy",
1174 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1176 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1177 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1178 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1179 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1180 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1181 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1182 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1183 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1184 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1185 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 0, 0),
1186 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 1, 0),
1187 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 2, 0),
1188 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1189 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1190 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1191 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1192 IGNORED_ASM_VER (SYS_VALUE_TUPLE, 4, 0, 1, 0),
1196 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1198 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1199 if (ignored_assembly_versions [i].major != major ||
1200 ignored_assembly_versions [i].minor != minor ||
1201 ignored_assembly_versions [i].build != build ||
1202 ignored_assembly_versions [i].revision != revision)
1204 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1212 static void Main () {
1215 for (int i = 0; i < str.Length; ++i)
1216 h = ((h << 5) + h) ^ str[i];
1218 Console.WriteLine ("{0:X}", h);
1222 hash_guid (const char *str)
1226 h = ((h << 5) + h) ^ *str;
1234 is_problematic_image (MonoImage *image)
1236 int h = hash_guid (image->guid);
1238 //TODO make this more cache effiecient.
1239 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1240 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1241 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1242 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1243 size_t needle_len = strlen (needle);
1244 size_t asm_len = strlen (image->name);
1245 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1253 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1254 gboolean care_about_cli, gboolean care_about_pecoff)
1256 MonoCLIImageInfo *iinfo;
1257 MonoDotNetHeader *header;
1258 GSList *errors = NULL;
1261 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1263 mono_image_init (image);
1265 iinfo = (MonoCLIImageInfo *)image->image_info;
1266 header = &iinfo->cli_header;
1268 if (!image->metadata_only) {
1269 for (l = image_loaders; l; l = l->next) {
1270 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1271 if (loader->match (image)) {
1272 image->loader = loader;
1276 if (!image->loader) {
1278 *status = MONO_IMAGE_IMAGE_INVALID;
1283 *status = MONO_IMAGE_IMAGE_INVALID;
1285 if (care_about_pecoff == FALSE)
1288 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1291 if (!mono_image_load_pe_data (image))
1294 image->loader = (MonoImageLoader*)&pe_loader;
1297 if (care_about_cli == FALSE) {
1301 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1304 if (!mono_image_load_cli_data (image))
1307 if (!image->ref_only && is_problematic_image (image)) {
1308 if (image->load_from_context) {
1309 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1311 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1312 *status = MONO_IMAGE_IMAGE_INVALID;
1317 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1320 mono_image_load_names (image);
1322 load_modules (image);
1325 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1327 *status = MONO_IMAGE_OK;
1333 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1334 g_warning ("Could not load image %s due to %s", image->name, info->message);
1335 mono_free_verify_list (errors);
1337 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1338 mono_image_close (image);
1343 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1344 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1346 MonoCLIImageInfo *iinfo;
1350 if ((filed = mono_file_map_open (fname)) == NULL){
1351 if (IS_PORTABILITY_SET) {
1352 gchar *ffname = mono_portability_find_file (fname, TRUE);
1354 filed = mono_file_map_open (ffname);
1359 if (filed == NULL) {
1361 *status = MONO_IMAGE_ERROR_ERRNO;
1366 image = g_new0 (MonoImage, 1);
1367 image->raw_buffer_used = TRUE;
1368 image->raw_data_len = mono_file_map_size (filed);
1369 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);
1370 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1371 if (!image->raw_data) {
1372 image->fileio_used = TRUE;
1373 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);
1376 if (!image->raw_data) {
1377 mono_file_map_close (filed);
1380 *status = MONO_IMAGE_IMAGE_INVALID;
1383 iinfo = g_new0 (MonoCLIImageInfo, 1);
1384 image->image_info = iinfo;
1385 image->name = mono_path_resolve_symlinks (fname);
1386 image->ref_only = refonly;
1387 image->metadata_only = metadata_only;
1388 image->load_from_context = load_from_context;
1389 image->ref_count = 1;
1390 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1391 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1393 mono_file_map_close (filed);
1394 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1398 * mono_image_loaded:
1399 * @name: path or assembly name of the image to load
1400 * @refonly: Check with respect to reflection-only loads?
1402 * This routine verifies that the given image is loaded.
1403 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1405 * Returns: the loaded MonoImage, or NULL on failure.
1408 mono_image_loaded_full (const char *name, gboolean refonly)
1412 mono_images_lock ();
1413 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1415 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1416 mono_images_unlock ();
1422 * mono_image_loaded:
1423 * @name: path or assembly name of the image to load
1425 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1427 * Returns: the loaded MonoImage, or NULL on failure.
1430 mono_image_loaded (const char *name)
1432 return mono_image_loaded_full (name, FALSE);
1441 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1443 GuidData *data = (GuidData *)user_data;
1448 image = (MonoImage *)val;
1449 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1454 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1457 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1461 mono_images_lock ();
1462 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1463 mono_images_unlock ();
1468 mono_image_loaded_by_guid (const char *guid)
1470 return mono_image_loaded_by_guid_full (guid, FALSE);
1474 register_image (MonoImage *image)
1477 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1479 mono_images_lock ();
1480 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1483 /* Somebody else beat us to it */
1484 mono_image_addref (image2);
1485 mono_images_unlock ();
1486 mono_image_close (image);
1490 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1491 g_hash_table_insert (loaded_images, image->name, image);
1492 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1493 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1494 mono_images_unlock ();
1500 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1502 MonoCLIImageInfo *iinfo;
1506 if (!data || !data_len) {
1508 *status = MONO_IMAGE_IMAGE_INVALID;
1513 datac = (char *)g_try_malloc (data_len);
1516 *status = MONO_IMAGE_ERROR_ERRNO;
1519 memcpy (datac, data, data_len);
1522 image = g_new0 (MonoImage, 1);
1523 image->raw_data = datac;
1524 image->raw_data_len = data_len;
1525 image->raw_data_allocated = need_copy;
1526 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1527 iinfo = g_new0 (MonoCLIImageInfo, 1);
1528 image->image_info = iinfo;
1529 image->ref_only = refonly;
1530 image->metadata_only = metadata_only;
1531 image->ref_count = 1;
1533 image = do_mono_image_load (image, status, TRUE, TRUE);
1537 return register_image (image);
1541 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1543 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1547 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1549 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1553 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1555 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1559 /* fname is not duplicated. */
1561 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1564 MonoCLIImageInfo* iinfo;
1566 image = g_new0 (MonoImage, 1);
1567 image->raw_data = (char*) module_handle;
1568 image->is_module_handle = TRUE;
1569 iinfo = g_new0 (MonoCLIImageInfo, 1);
1570 image->image_info = iinfo;
1571 image->name = fname;
1572 image->ref_count = has_entry_point ? 0 : 1;
1573 image->has_entry_point = has_entry_point;
1575 image = do_mono_image_load (image, status, TRUE, TRUE);
1579 return register_image (image);
1584 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1586 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1590 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1593 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1596 g_return_val_if_fail (fname != NULL, NULL);
1599 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1600 // then assemblies need to be loaded with LoadLibrary:
1601 if (!refonly && coree_module_handle) {
1602 HMODULE module_handle;
1603 guint16 *fname_utf16;
1606 absfname = mono_path_resolve_symlinks (fname);
1609 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1610 mono_images_lock ();
1611 image = g_hash_table_lookup (loaded_images, absfname);
1612 if (image) { // Image already loaded
1613 g_assert (image->is_module_handle);
1614 if (image->has_entry_point && image->ref_count == 0) {
1615 /* Increment reference count on images loaded outside of the runtime. */
1616 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1617 /* The image is already loaded because _CorDllMain removes images from the hash. */
1618 module_handle = LoadLibrary (fname_utf16);
1619 g_assert (module_handle == (HMODULE) image->raw_data);
1621 mono_image_addref (image);
1622 mono_images_unlock ();
1624 g_free (fname_utf16);
1629 // Image not loaded, load it now
1630 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1631 module_handle = MonoLoadImage (fname_utf16);
1632 if (status && module_handle == NULL)
1633 last_error = mono_w32error_get_last ();
1635 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1636 image = g_hash_table_lookup (loaded_images, absfname);
1638 mono_image_addref (image);
1639 mono_images_unlock ();
1641 g_free (fname_utf16);
1643 if (module_handle == NULL) {
1647 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1648 *status = MONO_IMAGE_IMAGE_INVALID;
1650 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1660 g_assert (image->is_module_handle);
1661 g_assert (image->has_entry_point);
1666 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1670 absfname = mono_path_canonicalize (fname);
1673 * The easiest solution would be to do all the loading inside the mutex,
1674 * but that would lead to scalability problems. So we let the loading
1675 * happen outside the mutex, and if multiple threads happen to load
1676 * the same image, we discard all but the first copy.
1678 mono_images_lock ();
1679 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1682 if (image) { // Image already loaded
1683 mono_image_addref (image);
1684 mono_images_unlock ();
1687 mono_images_unlock ();
1689 // Image not loaded, load it now
1690 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1694 return register_image (image);
1699 * @fname: filename that points to the module we want to open
1700 * @status: An error condition is returned in this field
1702 * Returns: An open image of type %MonoImage or NULL on error.
1703 * The caller holds a temporary reference to the returned image which should be cleared
1704 * when no longer needed by calling mono_image_close ().
1705 * if NULL, then check the value of @status for details on the error
1708 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1710 return mono_image_open_full (fname, status, FALSE);
1714 * mono_pe_file_open:
1715 * @fname: filename that points to the module we want to open
1716 * @status: An error condition is returned in this field
1718 * Returns: An open image of type %MonoImage or NULL on error. if
1719 * NULL, then check the value of @status for details on the error.
1720 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1721 * It's just a PE file loader, used for FileVersionInfo. It also does
1722 * not use the image cache.
1725 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1727 g_return_val_if_fail (fname != NULL, NULL);
1729 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1733 * mono_image_open_raw
1734 * @fname: filename that points to the module we want to open
1735 * @status: An error condition is returned in this field
1737 * Returns an image without loading neither pe or cli data.
1739 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1742 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1744 g_return_val_if_fail (fname != NULL, NULL);
1746 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1750 * mono_image_open_metadata_only:
1752 * Open an image which contains metadata only without a PE header.
1755 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1757 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1761 mono_image_fixup_vtable (MonoImage *image)
1764 MonoCLIImageInfo *iinfo;
1766 MonoVTableFixup *vtfixup;
1772 g_assert (image->is_module_handle);
1774 iinfo = image->image_info;
1775 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1776 if (!de->rva || !de->size)
1778 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1782 count = de->size / sizeof (MonoVTableFixup);
1784 if (!vtfixup->rva || !vtfixup->count)
1787 slot = mono_image_rva_map (image, vtfixup->rva);
1789 slot_type = vtfixup->type;
1790 slot_count = vtfixup->count;
1791 if (slot_type & VTFIXUP_TYPE_32BIT)
1792 while (slot_count--) {
1793 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1794 slot = ((guint32*) slot) + 1;
1796 else if (slot_type & VTFIXUP_TYPE_64BIT)
1797 while (slot_count--) {
1798 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1799 slot = ((guint32*) slot) + 1;
1802 g_assert_not_reached();
1807 g_assert_not_reached();
1812 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1814 g_hash_table_destroy ((GHashTable*)val);
1819 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1821 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1826 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1828 g_slist_free ((GSList*)val);
1832 * mono_image_addref:
1833 * @image: The image file we wish to add a reference to
1835 * Increases the reference count of an image.
1838 mono_image_addref (MonoImage *image)
1840 InterlockedIncrement (&image->ref_count);
1844 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1846 stream->alloc_size = stream->index = stream->offset = 0;
1847 g_free (stream->data);
1848 stream->data = NULL;
1850 g_hash_table_destroy (stream->hash);
1851 stream->hash = NULL;
1856 free_hash (GHashTable *hash)
1859 g_hash_table_destroy (hash);
1863 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1865 free_hash (cache->delegate_invoke_cache);
1866 free_hash (cache->delegate_begin_invoke_cache);
1867 free_hash (cache->delegate_end_invoke_cache);
1868 free_hash (cache->runtime_invoke_cache);
1869 free_hash (cache->runtime_invoke_vtype_cache);
1871 free_hash (cache->delegate_abstract_invoke_cache);
1873 free_hash (cache->runtime_invoke_direct_cache);
1874 free_hash (cache->managed_wrapper_cache);
1876 free_hash (cache->native_wrapper_cache);
1877 free_hash (cache->native_wrapper_aot_cache);
1878 free_hash (cache->native_wrapper_check_cache);
1879 free_hash (cache->native_wrapper_aot_check_cache);
1881 free_hash (cache->native_func_wrapper_aot_cache);
1882 free_hash (cache->remoting_invoke_cache);
1883 free_hash (cache->synchronized_cache);
1884 free_hash (cache->unbox_wrapper_cache);
1885 free_hash (cache->cominterop_invoke_cache);
1886 free_hash (cache->cominterop_wrapper_cache);
1887 free_hash (cache->thunk_invoke_cache);
1891 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1893 for (int i = 0; i < image_count; ++i) {
1895 if (!mono_image_close_except_pools (images [i]))
1902 * Returns whether mono_image_close_finish() must be called as well.
1903 * We must unload images in two steps because clearing the domain in
1904 * SGen requires the class metadata to be intact, but we need to free
1905 * the mono_g_hash_tables in case a collection occurs during domain
1906 * unloading and the roots would trip up the GC.
1909 mono_image_close_except_pools (MonoImage *image)
1912 GHashTable *loaded_images, *loaded_images_by_name;
1915 g_return_val_if_fail (image != NULL, FALSE);
1918 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1919 * register_image () can't grab an image which is being closed.
1921 mono_images_lock ();
1923 if (InterlockedDecrement (&image->ref_count) > 0) {
1924 mono_images_unlock ();
1928 loaded_images = get_loaded_images_hash (image->ref_only);
1929 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1930 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1931 if (image == image2) {
1932 /* This is not true if we are called from mono_image_open () */
1933 g_hash_table_remove (loaded_images, image->name);
1935 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1936 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1938 mono_images_unlock ();
1941 if (image->is_module_handle && image->has_entry_point) {
1942 mono_images_lock ();
1943 if (image->ref_count == 0) {
1944 /* Image will be closed by _CorDllMain. */
1945 FreeLibrary ((HMODULE) image->raw_data);
1946 mono_images_unlock ();
1949 mono_images_unlock ();
1953 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1955 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1957 mono_image_invoke_unload_hook (image);
1959 mono_metadata_clean_for_image (image);
1962 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1963 * assemblies, so we can't release these references in mono_assembly_close () since the
1964 * MonoImage might outlive its associated MonoAssembly.
1966 if (image->references && !image_is_dynamic (image)) {
1967 for (i = 0; i < image->nreferences; i++) {
1968 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1969 if (!mono_assembly_close_except_image_pools (image->references [i]))
1970 image->references [i] = NULL;
1974 if (image->references) {
1975 g_free (image->references);
1976 image->references = NULL;
1981 mono_images_lock ();
1982 if (image->is_module_handle && !image->has_entry_point)
1983 FreeLibrary ((HMODULE) image->raw_data);
1984 mono_images_unlock ();
1987 if (image->raw_buffer_used) {
1988 if (image->raw_data != NULL) {
1990 if (image->fileio_used)
1991 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1994 mono_file_unmap (image->raw_data, image->raw_data_handle);
1998 if (image->raw_data_allocated) {
1999 /* FIXME: do we need this? (image is disposed anyway) */
2000 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2001 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2003 if ((image->raw_metadata > image->raw_data) &&
2004 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2005 image->raw_metadata = NULL;
2007 for (i = 0; i < ii->cli_section_count; i++)
2008 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2009 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2010 ii->cli_sections [i] = NULL;
2012 g_free (image->raw_data);
2015 if (debug_assembly_unload) {
2016 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2018 g_free (image->name);
2019 g_free (image->guid);
2020 g_free (image->version);
2023 if (image->method_cache)
2024 g_hash_table_destroy (image->method_cache);
2025 if (image->methodref_cache)
2026 g_hash_table_destroy (image->methodref_cache);
2027 mono_internal_hash_table_destroy (&image->class_cache);
2028 mono_conc_hashtable_destroy (image->field_cache);
2029 if (image->array_cache) {
2030 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2031 g_hash_table_destroy (image->array_cache);
2033 if (image->szarray_cache)
2034 g_hash_table_destroy (image->szarray_cache);
2035 if (image->ptr_cache)
2036 g_hash_table_destroy (image->ptr_cache);
2037 if (image->name_cache) {
2038 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2039 g_hash_table_destroy (image->name_cache);
2042 free_hash (image->delegate_bound_static_invoke_cache);
2043 free_hash (image->runtime_invoke_vcall_cache);
2044 free_hash (image->ldfld_wrapper_cache);
2045 free_hash (image->ldflda_wrapper_cache);
2046 free_hash (image->stfld_wrapper_cache);
2047 free_hash (image->isinst_cache);
2048 free_hash (image->castclass_cache);
2049 free_hash (image->icall_wrapper_cache);
2050 free_hash (image->proxy_isinst_cache);
2051 free_hash (image->var_cache_slow);
2052 free_hash (image->mvar_cache_slow);
2053 free_hash (image->var_cache_constrained);
2054 free_hash (image->mvar_cache_constrained);
2055 free_hash (image->wrapper_param_names);
2056 free_hash (image->pinvoke_scopes);
2057 free_hash (image->pinvoke_scope_filenames);
2058 free_hash (image->native_func_wrapper_cache);
2059 free_hash (image->typespec_cache);
2061 mono_wrapper_caches_free (&image->wrapper_caches);
2063 for (i = 0; i < image->gshared_types_len; ++i)
2064 free_hash (image->gshared_types [i]);
2065 g_free (image->gshared_types);
2067 /* The ownership of signatures is not well defined */
2068 g_hash_table_destroy (image->memberref_signatures);
2069 g_hash_table_destroy (image->helper_signatures);
2070 g_hash_table_destroy (image->method_signatures);
2072 if (image->rgctx_template_hash)
2073 g_hash_table_destroy (image->rgctx_template_hash);
2075 if (image->property_hash)
2076 mono_property_hash_destroy (image->property_hash);
2079 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2080 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2082 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2083 image->reflection_info_unregister_classes = NULL;
2085 if (image->interface_bitset) {
2086 mono_unload_interface_ids (image->interface_bitset);
2087 mono_bitset_free (image->interface_bitset);
2089 if (image->image_info){
2090 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2092 if (ii->cli_section_tables)
2093 g_free (ii->cli_section_tables);
2094 if (ii->cli_sections)
2095 g_free (ii->cli_sections);
2096 g_free (image->image_info);
2099 mono_image_close_except_pools_all (image->files, image->file_count);
2100 mono_image_close_except_pools_all (image->modules, image->module_count);
2101 if (image->modules_loaded)
2102 g_free (image->modules_loaded);
2104 mono_os_mutex_destroy (&image->szarray_cache_lock);
2105 mono_os_mutex_destroy (&image->lock);
2107 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2108 if (image_is_dynamic (image)) {
2109 /* Dynamic images are GC_MALLOCed */
2110 g_free ((char*)image->module_name);
2111 mono_dynamic_image_free ((MonoDynamicImage*)image);
2114 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2120 mono_image_close_all (MonoImage**images, int image_count)
2122 for (int i = 0; i < image_count; ++i) {
2124 mono_image_close_finish (images [i]);
2131 mono_image_close_finish (MonoImage *image)
2135 if (image->references && !image_is_dynamic (image)) {
2136 for (i = 0; i < image->nreferences; i++) {
2137 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2138 mono_assembly_close_finish (image->references [i]);
2141 g_free (image->references);
2142 image->references = NULL;
2145 mono_image_close_all (image->files, image->file_count);
2146 mono_image_close_all (image->modules, image->module_count);
2148 #ifndef DISABLE_PERFCOUNTERS
2149 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2152 if (!image_is_dynamic (image)) {
2153 if (debug_assembly_unload)
2154 mono_mempool_invalidate (image->mempool);
2156 mono_mempool_destroy (image->mempool);
2160 if (debug_assembly_unload)
2161 mono_mempool_invalidate (image->mempool);
2163 mono_mempool_destroy (image->mempool);
2164 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2171 * @image: The image file we wish to close
2173 * Closes an image file, deallocates all memory consumed and
2174 * unmaps all possible sections of the file
2177 mono_image_close (MonoImage *image)
2179 if (mono_image_close_except_pools (image))
2180 mono_image_close_finish (image);
2184 * mono_image_strerror:
2185 * @status: an code indicating the result from a recent operation
2187 * Returns: a string describing the error
2190 mono_image_strerror (MonoImageOpenStatus status)
2195 case MONO_IMAGE_ERROR_ERRNO:
2196 return strerror (errno);
2197 case MONO_IMAGE_IMAGE_INVALID:
2198 return "File does not contain a valid CIL image";
2199 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2200 return "An assembly was referenced, but could not be found";
2202 return "Internal error";
2206 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2207 guint32 lang_id, gunichar2 *name,
2208 MonoPEResourceDirEntry *entry,
2209 MonoPEResourceDir *root, guint32 level)
2211 gboolean is_string, is_dir;
2212 guint32 name_offset, dir_offset;
2214 /* Level 0 holds a directory entry for each type of resource
2215 * (identified by ID or name).
2217 * Level 1 holds a directory entry for each named resource
2218 * item, and each "anonymous" item of a particular type of
2221 * Level 2 holds a directory entry for each language pointing to
2224 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2225 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2227 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2228 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2233 } else if (level==1) {
2234 if (res_id != name_offset)
2238 is_string==TRUE && name!=lookup (name_offset)) {
2242 } else if (level==2) {
2243 if (is_string || (lang_id != 0 && name_offset != lang_id))
2246 g_assert_not_reached ();
2250 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2251 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2254 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2256 for(i=0; i<entries; i++) {
2257 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2260 ret=mono_image_walk_resource_tree (info, res_id,
2271 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2272 MonoPEResourceDataEntry *res;
2274 res = g_new0 (MonoPEResourceDataEntry, 1);
2276 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2277 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2278 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2279 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2286 * mono_image_lookup_resource:
2287 * @image: the image to look up the resource in
2288 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2289 * @lang_id: The language id.
2290 * @name: the resource name to lookup.
2292 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2293 * of the given resource. The caller should free it using g_free () when no longer
2297 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2299 MonoCLIImageInfo *info;
2300 MonoDotNetHeader *header;
2301 MonoPEDatadir *datadir;
2302 MonoPEDirEntry *rsrc;
2303 MonoPEResourceDir *resource_dir;
2304 MonoPEResourceDirEntry *res_entries;
2311 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2313 info = (MonoCLIImageInfo *)image->image_info;
2318 header=&info->cli_header;
2323 datadir=&header->datadir;
2328 rsrc=&datadir->pe_resource_table;
2333 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2334 if(resource_dir==NULL) {
2338 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2339 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2341 for(i=0; i<entries; i++) {
2342 MonoPEResourceDirEntry *entry=&res_entries[i];
2345 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2346 name, entry, resource_dir,
2357 * mono_image_get_entry_point:
2358 * @image: the image where the entry point will be looked up.
2360 * Use this routine to determine the metadata token for method that
2361 * has been flagged as the entry point.
2363 * Returns: the token for the entry point method in the image
2366 mono_image_get_entry_point (MonoImage *image)
2368 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2372 * mono_image_get_resource:
2373 * @image: the image where the resource will be looked up.
2374 * @offset: The offset to add to the resource
2375 * @size: a pointer to an int where the size of the resource will be stored
2377 * This is a low-level routine that fetches a resource from the
2378 * metadata that starts at a given @offset. The @size parameter is
2379 * filled with the data field as encoded in the metadata.
2381 * Returns: the pointer to the resource whose offset is @offset.
2384 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2386 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2387 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2390 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2393 data = mono_image_rva_map (image, ch->ch_resources.rva);
2398 *size = read32 (data);
2403 // Returning NULL with no error set will be interpeted as "not found"
2405 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2407 char *base_dir, *name;
2409 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2415 if (fileidx < 1 || fileidx > t->rows)
2418 mono_image_lock (image);
2419 if (image->files && image->files [fileidx - 1]) {
2420 mono_image_unlock (image);
2421 return image->files [fileidx - 1];
2423 mono_image_unlock (image);
2425 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2426 fname = mono_metadata_string_heap (image, fname_id);
2427 base_dir = g_path_get_dirname (image->name);
2428 name = g_build_filename (base_dir, fname, NULL);
2429 res = mono_image_open (name, NULL);
2433 mono_image_lock (image);
2434 if (image->files && image->files [fileidx - 1]) {
2435 MonoImage *old = res;
2436 res = image->files [fileidx - 1];
2437 mono_image_unlock (image);
2438 mono_image_close (old);
2441 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2442 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2443 mono_image_unlock (image);
2444 mono_image_close (res);
2448 for (i = 0; i < res->module_count; ++i) {
2449 if (res->modules [i] && !res->modules [i]->assembly)
2450 res->modules [i]->assembly = image->assembly;
2453 if (!image->files) {
2454 image->files = g_new0 (MonoImage*, t->rows);
2455 image->file_count = t->rows;
2457 image->files [fileidx - 1] = res;
2458 mono_image_unlock (image);
2459 /* vtable fixup can't happen with the image lock held */
2461 if (res->is_module_handle)
2462 mono_image_fixup_vtable (res);
2473 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2476 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2477 mono_error_assert_ok (&error);
2482 * mono_image_get_strong_name:
2483 * @image: a MonoImage
2484 * @size: a guint32 pointer, or NULL.
2486 * If the image has a strong name, and @size is not NULL, the value
2487 * pointed to by size will have the size of the strong name.
2489 * Returns: NULL if the image does not have a strong name, or a
2490 * pointer to the public key.
2493 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2495 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2496 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2499 if (!de->size || !de->rva)
2501 data = mono_image_rva_map (image, de->rva);
2510 * mono_image_strong_name_position:
2511 * @image: a MonoImage
2512 * @size: a guint32 pointer, or NULL.
2514 * If the image has a strong name, and @size is not NULL, the value
2515 * pointed to by size will have the size of the strong name.
2517 * Returns: the position within the image file where the strong name
2521 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2523 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2524 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2529 if (!de->size || !de->rva)
2531 pos = mono_cli_rva_image_map (image, de->rva);
2532 return pos == INVALID_ADDRESS ? 0 : pos;
2536 * mono_image_get_public_key:
2537 * @image: a MonoImage
2538 * @size: a guint32 pointer, or NULL.
2540 * This is used to obtain the public key in the @image.
2542 * If the image has a public key, and @size is not NULL, the value
2543 * pointed to by size will have the size of the public key.
2545 * Returns: NULL if the image does not have a public key, or a pointer
2546 * to the public key.
2549 mono_image_get_public_key (MonoImage *image, guint32 *size)
2554 if (image_is_dynamic (image)) {
2556 *size = ((MonoDynamicImage*)image)->public_key_len;
2557 return (char*)((MonoDynamicImage*)image)->public_key;
2559 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2561 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2564 pubkey = mono_metadata_blob_heap (image, tok);
2565 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2572 * mono_image_get_name:
2573 * @name: a MonoImage
2575 * Returns: the name of the assembly.
2578 mono_image_get_name (MonoImage *image)
2580 return image->assembly_name;
2584 * mono_image_get_filename:
2585 * @image: a MonoImage
2587 * Used to get the filename that hold the actual MonoImage
2589 * Returns: the filename.
2592 mono_image_get_filename (MonoImage *image)
2598 mono_image_get_guid (MonoImage *image)
2603 const MonoTableInfo*
2604 mono_image_get_table_info (MonoImage *image, int table_id)
2606 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2608 return &image->tables [table_id];
2612 mono_image_get_table_rows (MonoImage *image, int table_id)
2614 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2616 return image->tables [table_id].rows;
2620 mono_table_info_get_rows (const MonoTableInfo *table)
2626 * mono_image_get_assembly:
2627 * @image: the MonoImage.
2629 * Use this routine to get the assembly that owns this image.
2631 * Returns: the assembly that holds this image.
2634 mono_image_get_assembly (MonoImage *image)
2636 return image->assembly;
2640 * mono_image_is_dynamic:
2641 * @image: the MonoImage
2643 * Determines if the given image was created dynamically through the
2644 * System.Reflection.Emit API
2646 * Returns: TRUE if the image was created dynamically, FALSE if not.
2649 mono_image_is_dynamic (MonoImage *image)
2651 return image_is_dynamic (image);
2655 * mono_image_has_authenticode_entry:
2656 * @image: the MonoImage
2658 * Use this routine to determine if the image has a Authenticode
2659 * Certificate Table.
2661 * Returns: TRUE if the image contains an authenticode entry in the PE
2665 mono_image_has_authenticode_entry (MonoImage *image)
2667 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2668 MonoDotNetHeader *header = &iinfo->cli_header;
2671 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2672 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2673 return ((de->rva != 0) && (de->size > 8));
2677 mono_image_alloc (MonoImage *image, guint size)
2681 #ifndef DISABLE_PERFCOUNTERS
2682 mono_perfcounters->loader_bytes += size;
2684 mono_image_lock (image);
2685 res = mono_mempool_alloc (image->mempool, size);
2686 mono_image_unlock (image);
2692 mono_image_alloc0 (MonoImage *image, guint size)
2696 #ifndef DISABLE_PERFCOUNTERS
2697 mono_perfcounters->loader_bytes += size;
2699 mono_image_lock (image);
2700 res = mono_mempool_alloc0 (image->mempool, size);
2701 mono_image_unlock (image);
2707 mono_image_strdup (MonoImage *image, const char *s)
2711 #ifndef DISABLE_PERFCOUNTERS
2712 mono_perfcounters->loader_bytes += strlen (s);
2714 mono_image_lock (image);
2715 res = mono_mempool_strdup (image->mempool, s);
2716 mono_image_unlock (image);
2722 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2725 mono_image_lock (image);
2726 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2727 mono_image_unlock (image);
2728 #ifndef DISABLE_PERFCOUNTERS
2729 mono_perfcounters->loader_bytes += strlen (buf);
2735 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2740 va_start (args, format);
2741 buf = mono_image_strdup_vprintf (image, format, args);
2747 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2751 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2752 new_list->data = data;
2753 new_list->prev = list ? list->prev : NULL;
2754 new_list->next = list;
2757 new_list->prev->next = new_list;
2759 list->prev = new_list;
2765 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2769 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2770 new_list->data = data;
2771 new_list->next = NULL;
2773 return g_slist_concat (list, new_list);
2777 mono_image_lock (MonoImage *image)
2779 mono_locks_os_acquire (&image->lock, ImageDataLock);
2783 mono_image_unlock (MonoImage *image)
2785 mono_locks_os_release (&image->lock, ImageDataLock);
2790 * mono_image_property_lookup:
2792 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2794 * LOCKING: Takes the image lock
2797 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2801 mono_image_lock (image);
2802 res = mono_property_hash_lookup (image->property_hash, subject, property);
2803 mono_image_unlock (image);
2809 * mono_image_property_insert:
2811 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2813 * LOCKING: Takes the image lock
2816 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2818 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2819 mono_image_lock (image);
2820 mono_property_hash_insert (image->property_hash, subject, property, value);
2821 mono_image_unlock (image);
2825 * mono_image_property_remove:
2827 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2829 * LOCKING: Takes the image lock
2832 mono_image_property_remove (MonoImage *image, gpointer subject)
2834 mono_image_lock (image);
2835 mono_property_hash_remove_object (image->property_hash, subject);
2836 mono_image_unlock (image);
2840 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2842 MonoImage *image = klass->image;
2843 g_assert (image_is_dynamic (image));
2844 mono_image_lock (image);
2845 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2846 mono_image_unlock (image);
2849 // 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.
2852 * mono_find_image_owner:
2854 * Find the image, if any, which a given pointer is located in the memory of.
2857 mono_find_image_owner (void *ptr)
2859 mono_images_lock ();
2861 MonoImage *owner = NULL;
2863 // Iterate over both by-path image hashes
2864 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2866 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2868 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2869 GHashTableIter iter;
2872 // Iterate over images within a hash
2873 g_hash_table_iter_init (&iter, target);
2874 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2876 mono_image_lock (image);
2877 if (mono_mempool_contains_addr (image->mempool, ptr))
2879 mono_image_unlock (image);
2883 mono_images_unlock ();