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_images_rva_map:
204 * @image: a MonoImage
205 * @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_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
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 * @image: The image we are operating on
295 * @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 (.text, .rsrc, .data).
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 * @image: The image we are operating on
330 * @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 (MonoImage *image, int idx)
766 MonoImage *result = mono_image_load_module_checked (image, idx, &error);
767 mono_error_assert_ok (&error);
772 class_key_extract (gpointer value)
774 MonoClass *klass = (MonoClass *)value;
776 return GUINT_TO_POINTER (klass->type_token);
780 class_next_value (gpointer value)
782 MonoClassDef *klass = (MonoClassDef *)value;
784 return (gpointer*)&klass->next_class_cache;
788 mono_image_init (MonoImage *image)
790 mono_os_mutex_init_recursive (&image->lock);
791 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
793 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
794 mono_internal_hash_table_init (&image->class_cache,
798 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
800 image->typespec_cache = g_hash_table_new (NULL, NULL);
801 image->memberref_signatures = g_hash_table_new (NULL, NULL);
802 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
803 image->method_signatures = g_hash_table_new (NULL, NULL);
805 image->property_hash = mono_property_hash_new ();
808 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
809 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
810 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
811 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
812 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
821 * Returns < 0 to indicate an error.
824 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
826 MonoDotNetHeader64 header64;
829 if (!image->is_module_handle)
831 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
834 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
836 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
839 /* endian swap the fields common between PE and PE+ */
840 SWAP32 (header->coff.coff_time);
841 SWAP32 (header->coff.coff_symptr);
842 SWAP32 (header->coff.coff_symcount);
843 SWAP16 (header->coff.coff_machine);
844 SWAP16 (header->coff.coff_sections);
845 SWAP16 (header->coff.coff_opt_header_size);
846 SWAP16 (header->coff.coff_attributes);
848 SWAP32 (header->pe.pe_code_size);
849 SWAP32 (header->pe.pe_uninit_data_size);
850 SWAP32 (header->pe.pe_rva_entry_point);
851 SWAP32 (header->pe.pe_rva_code_base);
852 SWAP32 (header->pe.pe_rva_data_base);
853 SWAP16 (header->pe.pe_magic);
855 /* now we are ready for the basic tests */
857 if (header->pe.pe_magic == 0x10B) {
858 offset += sizeof (MonoDotNetHeader);
859 SWAP32 (header->pe.pe_data_size);
860 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
863 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
864 SWAP32 (header->nt.pe_stack_reserve);
865 SWAP32 (header->nt.pe_stack_commit);
866 SWAP32 (header->nt.pe_heap_reserve);
867 SWAP32 (header->nt.pe_heap_commit);
868 } else if (header->pe.pe_magic == 0x20B) {
869 /* PE32+ file format */
870 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
872 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
873 offset += sizeof (MonoDotNetHeader64);
874 /* copy the fields already swapped. the last field, pe_data_size, is missing */
875 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
876 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
877 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
879 SWAP64 (header64.nt.pe_image_base);
880 header->nt.pe_image_base = header64.nt.pe_image_base;
881 SWAP64 (header64.nt.pe_stack_reserve);
882 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
883 SWAP64 (header64.nt.pe_stack_commit);
884 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
885 SWAP64 (header64.nt.pe_heap_reserve);
886 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
887 SWAP64 (header64.nt.pe_heap_commit);
888 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
890 header->nt.pe_section_align = header64.nt.pe_section_align;
891 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
892 header->nt.pe_os_major = header64.nt.pe_os_major;
893 header->nt.pe_os_minor = header64.nt.pe_os_minor;
894 header->nt.pe_user_major = header64.nt.pe_user_major;
895 header->nt.pe_user_minor = header64.nt.pe_user_minor;
896 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
897 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
898 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
899 header->nt.pe_image_size = header64.nt.pe_image_size;
900 header->nt.pe_header_size = header64.nt.pe_header_size;
901 header->nt.pe_checksum = header64.nt.pe_checksum;
902 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
903 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
904 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
905 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
907 /* copy the datadir */
908 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
913 /* MonoPEHeaderNT: not used yet */
914 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
915 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
916 SWAP16 (header->nt.pe_os_major); /* must be 4 */
917 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
918 SWAP16 (header->nt.pe_user_major);
919 SWAP16 (header->nt.pe_user_minor);
920 SWAP16 (header->nt.pe_subsys_major);
921 SWAP16 (header->nt.pe_subsys_minor);
922 SWAP32 (header->nt.pe_reserved_1);
923 SWAP32 (header->nt.pe_image_size);
924 SWAP32 (header->nt.pe_header_size);
925 SWAP32 (header->nt.pe_checksum);
926 SWAP16 (header->nt.pe_subsys_required);
927 SWAP16 (header->nt.pe_dll_flags);
928 SWAP32 (header->nt.pe_loader_flags);
929 SWAP32 (header->nt.pe_data_dir_count);
931 /* MonoDotNetHeader: mostly unused */
932 SWAPPDE (header->datadir.pe_export_table);
933 SWAPPDE (header->datadir.pe_import_table);
934 SWAPPDE (header->datadir.pe_resource_table);
935 SWAPPDE (header->datadir.pe_exception_table);
936 SWAPPDE (header->datadir.pe_certificate_table);
937 SWAPPDE (header->datadir.pe_reloc_table);
938 SWAPPDE (header->datadir.pe_debug);
939 SWAPPDE (header->datadir.pe_copyright);
940 SWAPPDE (header->datadir.pe_global_ptr);
941 SWAPPDE (header->datadir.pe_tls_table);
942 SWAPPDE (header->datadir.pe_load_config_table);
943 SWAPPDE (header->datadir.pe_bound_import);
944 SWAPPDE (header->datadir.pe_iat);
945 SWAPPDE (header->datadir.pe_delay_import_desc);
946 SWAPPDE (header->datadir.pe_cli_header);
947 SWAPPDE (header->datadir.pe_reserved);
950 if (image->is_module_handle)
951 image->raw_data_len = header->nt.pe_image_size;
958 mono_image_load_pe_data (MonoImage *image)
960 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
964 pe_image_load_pe_data (MonoImage *image)
966 MonoCLIImageInfo *iinfo;
967 MonoDotNetHeader *header;
968 MonoMSDOSHeader msdos;
971 iinfo = (MonoCLIImageInfo *)image->image_info;
972 header = &iinfo->cli_header;
975 if (!image->is_module_handle)
977 if (offset + sizeof (msdos) > image->raw_data_len)
979 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
981 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
984 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
986 offset = msdos.pe_offset;
988 offset = do_load_header (image, header, offset);
993 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
995 if (header->coff.coff_machine != 0x14c)
1001 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1002 * which produces binaries with 7.0. From Sergey:
1004 * The reason is that MSVC7 uses traditional compile/link
1005 * sequence for CIL executables, and VS.NET (and Framework
1006 * SDK) includes linker version 7, that puts 7.0 in this
1007 * field. That's why it's currently not possible to load VC
1008 * binaries with Mono. This field is pretty much meaningless
1009 * anyway (what linker?).
1011 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1016 * FIXME: byte swap all addresses here for header.
1019 if (!load_section_tables (image, iinfo, offset))
1029 mono_image_load_cli_data (MonoImage *image)
1031 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1035 pe_image_load_cli_data (MonoImage *image)
1037 MonoCLIImageInfo *iinfo;
1038 MonoDotNetHeader *header;
1040 iinfo = (MonoCLIImageInfo *)image->image_info;
1041 header = &iinfo->cli_header;
1043 /* Load the CLI header */
1044 if (!mono_image_load_cli_header (image, iinfo))
1047 if (!mono_image_load_metadata (image, iinfo))
1054 mono_image_load_names (MonoImage *image)
1056 /* modules don't have an assembly table row */
1057 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1058 image->assembly_name = mono_metadata_string_heap (image,
1059 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1060 0, MONO_ASSEMBLY_NAME));
1063 /* Portable pdb images don't have a MODULE row */
1064 if (image->tables [MONO_TABLE_MODULE].rows) {
1065 image->module_name = mono_metadata_string_heap (image,
1066 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1067 0, MONO_MODULE_NAME));
1072 pe_image_load_tables (MonoImage *image)
1078 pe_image_match (MonoImage *image)
1080 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1085 static const MonoImageLoader pe_loader = {
1087 pe_image_load_pe_data,
1088 pe_image_load_cli_data,
1089 pe_image_load_tables,
1093 install_pe_loader (void)
1095 mono_install_image_loader (&pe_loader);
1101 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1102 Mono provides its own implementation of those assemblies so it's safe to do so.
1104 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1106 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1108 This is to be removed once a proper fix is shipped through nuget.
1113 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1114 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1115 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1116 SYS_NET_HTTP = 3, //System.Net.Http
1117 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1118 SYS_REF_DISP_PROXY = 5, //System.Reflection.DispatchProxy
1119 SYS_VALUE_TUPLE = 6, //System.ValueTuple
1120 } IgnoredAssemblyNames;
1125 const char guid [40];
1130 guint16 major, minor, build, revision;
1131 } IgnoredAssemblyVersion;
1133 const char *ignored_assemblies_file_names[] = {
1134 "System.Runtime.InteropServices.RuntimeInformation.dll",
1135 "System.Globalization.Extensions.dll",
1136 "System.IO.Compression.dll",
1137 "System.Net.Http.dll",
1138 "System.Text.Encoding.CodePages.dll",
1139 "System.Reflection.DispatchProxy.dll",
1140 "System.ValueTuple.dll"
1143 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1145 static const IgnoredAssembly ignored_assemblies [] = {
1146 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1147 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1148 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1149 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1150 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1151 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1152 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1153 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1154 IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1155 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1156 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1157 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1158 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1159 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1160 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1161 IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
1165 const char *ignored_assemblies_names[] = {
1166 "System.Runtime.InteropServices.RuntimeInformation",
1167 "System.Globalization.Extensions",
1168 "System.IO.Compression",
1170 "System.Text.Encoding.CodePages",
1171 "System.Reflection.DispatchProxy",
1175 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1177 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1178 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1179 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1180 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1181 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1182 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1183 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1184 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1185 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1186 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 0, 0),
1187 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 1, 0),
1188 IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 2, 0),
1189 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1190 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1191 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1192 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1193 IGNORED_ASM_VER (SYS_VALUE_TUPLE, 4, 0, 1, 0),
1197 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1199 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1200 if (ignored_assembly_versions [i].major != major ||
1201 ignored_assembly_versions [i].minor != minor ||
1202 ignored_assembly_versions [i].build != build ||
1203 ignored_assembly_versions [i].revision != revision)
1205 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1213 static void Main () {
1216 for (int i = 0; i < str.Length; ++i)
1217 h = ((h << 5) + h) ^ str[i];
1219 Console.WriteLine ("{0:X}", h);
1223 hash_guid (const char *str)
1227 h = ((h << 5) + h) ^ *str;
1235 is_problematic_image (MonoImage *image)
1237 int h = hash_guid (image->guid);
1239 //TODO make this more cache effiecient.
1240 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1241 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1242 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1243 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1244 size_t needle_len = strlen (needle);
1245 size_t asm_len = strlen (image->name);
1246 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1254 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1255 gboolean care_about_cli, gboolean care_about_pecoff)
1257 MonoCLIImageInfo *iinfo;
1258 MonoDotNetHeader *header;
1259 GSList *errors = NULL;
1262 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1264 mono_image_init (image);
1266 iinfo = (MonoCLIImageInfo *)image->image_info;
1267 header = &iinfo->cli_header;
1269 if (!image->metadata_only) {
1270 for (l = image_loaders; l; l = l->next) {
1271 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1272 if (loader->match (image)) {
1273 image->loader = loader;
1277 if (!image->loader) {
1279 *status = MONO_IMAGE_IMAGE_INVALID;
1284 *status = MONO_IMAGE_IMAGE_INVALID;
1286 if (care_about_pecoff == FALSE)
1289 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1292 if (!mono_image_load_pe_data (image))
1295 image->loader = (MonoImageLoader*)&pe_loader;
1298 if (care_about_cli == FALSE) {
1302 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1305 if (!mono_image_load_cli_data (image))
1308 if (!image->ref_only && is_problematic_image (image)) {
1309 if (image->load_from_context) {
1310 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1312 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1313 *status = MONO_IMAGE_IMAGE_INVALID;
1318 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1321 mono_image_load_names (image);
1323 load_modules (image);
1326 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1328 *status = MONO_IMAGE_OK;
1334 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1335 g_warning ("Could not load image %s due to %s", image->name, info->message);
1336 mono_free_verify_list (errors);
1338 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1339 mono_image_close (image);
1344 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1345 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1347 MonoCLIImageInfo *iinfo;
1351 if ((filed = mono_file_map_open (fname)) == NULL){
1352 if (IS_PORTABILITY_SET) {
1353 gchar *ffname = mono_portability_find_file (fname, TRUE);
1355 filed = mono_file_map_open (ffname);
1360 if (filed == NULL) {
1362 *status = MONO_IMAGE_ERROR_ERRNO;
1367 image = g_new0 (MonoImage, 1);
1368 image->raw_buffer_used = TRUE;
1369 image->raw_data_len = mono_file_map_size (filed);
1370 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);
1371 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1372 if (!image->raw_data) {
1373 image->fileio_used = TRUE;
1374 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);
1377 if (!image->raw_data) {
1378 mono_file_map_close (filed);
1381 *status = MONO_IMAGE_IMAGE_INVALID;
1384 iinfo = g_new0 (MonoCLIImageInfo, 1);
1385 image->image_info = iinfo;
1386 image->name = mono_path_resolve_symlinks (fname);
1387 image->ref_only = refonly;
1388 image->metadata_only = metadata_only;
1389 image->load_from_context = load_from_context;
1390 image->ref_count = 1;
1391 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1392 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1394 mono_file_map_close (filed);
1395 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1399 * mono_image_loaded_full:
1400 * @name: path or assembly name of the image to load
1401 * @refonly: Check with respect to reflection-only loads?
1403 * This routine verifies that the given image is loaded.
1404 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1406 * Returns: the loaded MonoImage, or NULL on failure.
1409 mono_image_loaded_full (const char *name, gboolean refonly)
1413 mono_images_lock ();
1414 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1416 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1417 mono_images_unlock ();
1423 * mono_image_loaded:
1424 * @name: path or assembly name of the image to load
1426 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1428 * Returns: the loaded MonoImage, or NULL on failure.
1431 mono_image_loaded (const char *name)
1433 return mono_image_loaded_full (name, FALSE);
1442 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1444 GuidData *data = (GuidData *)user_data;
1449 image = (MonoImage *)val;
1450 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1455 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1458 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1462 mono_images_lock ();
1463 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1464 mono_images_unlock ();
1469 mono_image_loaded_by_guid (const char *guid)
1471 return mono_image_loaded_by_guid_full (guid, FALSE);
1475 register_image (MonoImage *image)
1478 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1480 mono_images_lock ();
1481 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1484 /* Somebody else beat us to it */
1485 mono_image_addref (image2);
1486 mono_images_unlock ();
1487 mono_image_close (image);
1491 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1492 g_hash_table_insert (loaded_images, image->name, image);
1493 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1494 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1495 mono_images_unlock ();
1501 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1503 MonoCLIImageInfo *iinfo;
1507 if (!data || !data_len) {
1509 *status = MONO_IMAGE_IMAGE_INVALID;
1514 datac = (char *)g_try_malloc (data_len);
1517 *status = MONO_IMAGE_ERROR_ERRNO;
1520 memcpy (datac, data, data_len);
1523 image = g_new0 (MonoImage, 1);
1524 image->raw_data = datac;
1525 image->raw_data_len = data_len;
1526 image->raw_data_allocated = need_copy;
1527 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1528 iinfo = g_new0 (MonoCLIImageInfo, 1);
1529 image->image_info = iinfo;
1530 image->ref_only = refonly;
1531 image->metadata_only = metadata_only;
1532 image->ref_count = 1;
1534 image = do_mono_image_load (image, status, TRUE, TRUE);
1538 return register_image (image);
1542 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1544 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1548 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1550 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1554 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1556 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1560 /* fname is not duplicated. */
1562 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1565 MonoCLIImageInfo* iinfo;
1567 image = g_new0 (MonoImage, 1);
1568 image->raw_data = (char*) module_handle;
1569 image->is_module_handle = TRUE;
1570 iinfo = g_new0 (MonoCLIImageInfo, 1);
1571 image->image_info = iinfo;
1572 image->name = fname;
1573 image->ref_count = has_entry_point ? 0 : 1;
1574 image->has_entry_point = has_entry_point;
1576 image = do_mono_image_load (image, status, TRUE, TRUE);
1580 return register_image (image);
1585 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1587 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1591 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1594 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1597 g_return_val_if_fail (fname != NULL, NULL);
1600 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1601 // then assemblies need to be loaded with LoadLibrary:
1602 if (!refonly && coree_module_handle) {
1603 HMODULE module_handle;
1604 guint16 *fname_utf16;
1607 absfname = mono_path_resolve_symlinks (fname);
1610 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1611 mono_images_lock ();
1612 image = g_hash_table_lookup (loaded_images, absfname);
1613 if (image) { // Image already loaded
1614 g_assert (image->is_module_handle);
1615 if (image->has_entry_point && image->ref_count == 0) {
1616 /* Increment reference count on images loaded outside of the runtime. */
1617 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1618 /* The image is already loaded because _CorDllMain removes images from the hash. */
1619 module_handle = LoadLibrary (fname_utf16);
1620 g_assert (module_handle == (HMODULE) image->raw_data);
1622 mono_image_addref (image);
1623 mono_images_unlock ();
1625 g_free (fname_utf16);
1630 // Image not loaded, load it now
1631 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1632 module_handle = MonoLoadImage (fname_utf16);
1633 if (status && module_handle == NULL)
1634 last_error = mono_w32error_get_last ();
1636 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1637 image = g_hash_table_lookup (loaded_images, absfname);
1639 mono_image_addref (image);
1640 mono_images_unlock ();
1642 g_free (fname_utf16);
1644 if (module_handle == NULL) {
1648 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1649 *status = MONO_IMAGE_IMAGE_INVALID;
1651 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1661 g_assert (image->is_module_handle);
1662 g_assert (image->has_entry_point);
1667 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1671 absfname = mono_path_canonicalize (fname);
1674 * The easiest solution would be to do all the loading inside the mutex,
1675 * but that would lead to scalability problems. So we let the loading
1676 * happen outside the mutex, and if multiple threads happen to load
1677 * the same image, we discard all but the first copy.
1679 mono_images_lock ();
1680 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1683 if (image) { // Image already loaded
1684 mono_image_addref (image);
1685 mono_images_unlock ();
1688 mono_images_unlock ();
1690 // Image not loaded, load it now
1691 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1695 return register_image (image);
1700 * @fname: filename that points to the module we want to open
1701 * @status: An error condition is returned in this field
1703 * Returns: An open image of type %MonoImage or NULL on error.
1704 * The caller holds a temporary reference to the returned image which should be cleared
1705 * when no longer needed by calling mono_image_close ().
1706 * if NULL, then check the value of @status for details on the error
1709 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1711 return mono_image_open_full (fname, status, FALSE);
1715 * mono_pe_file_open:
1716 * @fname: filename that points to the module we want to open
1717 * @status: An error condition is returned in this field
1719 * Returns: An open image of type %MonoImage or NULL on error. if
1720 * NULL, then check the value of @status for details on the error.
1721 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1722 * It's just a PE file loader, used for FileVersionInfo. It also does
1723 * not use the image cache.
1726 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1728 g_return_val_if_fail (fname != NULL, NULL);
1730 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1734 * mono_image_open_raw
1735 * @fname: filename that points to the module we want to open
1736 * @status: An error condition is returned in this field
1738 * Returns an image without loading neither pe or cli data.
1740 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1743 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1745 g_return_val_if_fail (fname != NULL, NULL);
1747 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1751 * mono_image_open_metadata_only:
1753 * Open an image which contains metadata only without a PE header.
1756 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1758 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1762 mono_image_fixup_vtable (MonoImage *image)
1765 MonoCLIImageInfo *iinfo;
1767 MonoVTableFixup *vtfixup;
1773 g_assert (image->is_module_handle);
1775 iinfo = image->image_info;
1776 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1777 if (!de->rva || !de->size)
1779 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1783 count = de->size / sizeof (MonoVTableFixup);
1785 if (!vtfixup->rva || !vtfixup->count)
1788 slot = mono_image_rva_map (image, vtfixup->rva);
1790 slot_type = vtfixup->type;
1791 slot_count = vtfixup->count;
1792 if (slot_type & VTFIXUP_TYPE_32BIT)
1793 while (slot_count--) {
1794 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1795 slot = ((guint32*) slot) + 1;
1797 else if (slot_type & VTFIXUP_TYPE_64BIT)
1798 while (slot_count--) {
1799 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1800 slot = ((guint32*) slot) + 1;
1803 g_assert_not_reached();
1808 g_assert_not_reached();
1813 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1815 g_hash_table_destroy ((GHashTable*)val);
1820 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1822 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1827 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1829 g_slist_free ((GSList*)val);
1833 * mono_image_addref:
1834 * @image: The image file we wish to add a reference to
1836 * Increases the reference count of an image.
1839 mono_image_addref (MonoImage *image)
1841 InterlockedIncrement (&image->ref_count);
1845 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1847 stream->alloc_size = stream->index = stream->offset = 0;
1848 g_free (stream->data);
1849 stream->data = NULL;
1851 g_hash_table_destroy (stream->hash);
1852 stream->hash = NULL;
1857 free_hash (GHashTable *hash)
1860 g_hash_table_destroy (hash);
1864 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1866 free_hash (cache->delegate_invoke_cache);
1867 free_hash (cache->delegate_begin_invoke_cache);
1868 free_hash (cache->delegate_end_invoke_cache);
1869 free_hash (cache->runtime_invoke_cache);
1870 free_hash (cache->runtime_invoke_vtype_cache);
1872 free_hash (cache->delegate_abstract_invoke_cache);
1874 free_hash (cache->runtime_invoke_direct_cache);
1875 free_hash (cache->managed_wrapper_cache);
1877 free_hash (cache->native_wrapper_cache);
1878 free_hash (cache->native_wrapper_aot_cache);
1879 free_hash (cache->native_wrapper_check_cache);
1880 free_hash (cache->native_wrapper_aot_check_cache);
1882 free_hash (cache->native_func_wrapper_aot_cache);
1883 free_hash (cache->remoting_invoke_cache);
1884 free_hash (cache->synchronized_cache);
1885 free_hash (cache->unbox_wrapper_cache);
1886 free_hash (cache->cominterop_invoke_cache);
1887 free_hash (cache->cominterop_wrapper_cache);
1888 free_hash (cache->thunk_invoke_cache);
1892 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1894 for (int i = 0; i < image_count; ++i) {
1896 if (!mono_image_close_except_pools (images [i]))
1903 * Returns whether mono_image_close_finish() must be called as well.
1904 * We must unload images in two steps because clearing the domain in
1905 * SGen requires the class metadata to be intact, but we need to free
1906 * the mono_g_hash_tables in case a collection occurs during domain
1907 * unloading and the roots would trip up the GC.
1910 mono_image_close_except_pools (MonoImage *image)
1913 GHashTable *loaded_images, *loaded_images_by_name;
1916 g_return_val_if_fail (image != NULL, FALSE);
1919 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1920 * register_image () can't grab an image which is being closed.
1922 mono_images_lock ();
1924 if (InterlockedDecrement (&image->ref_count) > 0) {
1925 mono_images_unlock ();
1929 loaded_images = get_loaded_images_hash (image->ref_only);
1930 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1931 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1932 if (image == image2) {
1933 /* This is not true if we are called from mono_image_open () */
1934 g_hash_table_remove (loaded_images, image->name);
1936 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1937 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1939 mono_images_unlock ();
1942 if (image->is_module_handle && image->has_entry_point) {
1943 mono_images_lock ();
1944 if (image->ref_count == 0) {
1945 /* Image will be closed by _CorDllMain. */
1946 FreeLibrary ((HMODULE) image->raw_data);
1947 mono_images_unlock ();
1950 mono_images_unlock ();
1954 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1956 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1958 mono_image_invoke_unload_hook (image);
1960 mono_metadata_clean_for_image (image);
1963 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1964 * assemblies, so we can't release these references in mono_assembly_close () since the
1965 * MonoImage might outlive its associated MonoAssembly.
1967 if (image->references && !image_is_dynamic (image)) {
1968 for (i = 0; i < image->nreferences; i++) {
1969 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1970 if (!mono_assembly_close_except_image_pools (image->references [i]))
1971 image->references [i] = NULL;
1975 if (image->references) {
1976 g_free (image->references);
1977 image->references = NULL;
1982 mono_images_lock ();
1983 if (image->is_module_handle && !image->has_entry_point)
1984 FreeLibrary ((HMODULE) image->raw_data);
1985 mono_images_unlock ();
1988 if (image->raw_buffer_used) {
1989 if (image->raw_data != NULL) {
1991 if (image->fileio_used)
1992 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1995 mono_file_unmap (image->raw_data, image->raw_data_handle);
1999 if (image->raw_data_allocated) {
2000 /* FIXME: do we need this? (image is disposed anyway) */
2001 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2002 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2004 if ((image->raw_metadata > image->raw_data) &&
2005 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2006 image->raw_metadata = NULL;
2008 for (i = 0; i < ii->cli_section_count; i++)
2009 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2010 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2011 ii->cli_sections [i] = NULL;
2013 g_free (image->raw_data);
2016 if (debug_assembly_unload) {
2017 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2019 g_free (image->name);
2020 g_free (image->guid);
2021 g_free (image->version);
2024 if (image->method_cache)
2025 g_hash_table_destroy (image->method_cache);
2026 if (image->methodref_cache)
2027 g_hash_table_destroy (image->methodref_cache);
2028 mono_internal_hash_table_destroy (&image->class_cache);
2029 mono_conc_hashtable_destroy (image->field_cache);
2030 if (image->array_cache) {
2031 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2032 g_hash_table_destroy (image->array_cache);
2034 if (image->szarray_cache)
2035 g_hash_table_destroy (image->szarray_cache);
2036 if (image->ptr_cache)
2037 g_hash_table_destroy (image->ptr_cache);
2038 if (image->name_cache) {
2039 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2040 g_hash_table_destroy (image->name_cache);
2043 free_hash (image->delegate_bound_static_invoke_cache);
2044 free_hash (image->runtime_invoke_vcall_cache);
2045 free_hash (image->ldfld_wrapper_cache);
2046 free_hash (image->ldflda_wrapper_cache);
2047 free_hash (image->stfld_wrapper_cache);
2048 free_hash (image->isinst_cache);
2049 free_hash (image->castclass_cache);
2050 free_hash (image->icall_wrapper_cache);
2051 free_hash (image->proxy_isinst_cache);
2052 free_hash (image->var_cache_slow);
2053 free_hash (image->mvar_cache_slow);
2054 free_hash (image->var_cache_constrained);
2055 free_hash (image->mvar_cache_constrained);
2056 free_hash (image->wrapper_param_names);
2057 free_hash (image->pinvoke_scopes);
2058 free_hash (image->pinvoke_scope_filenames);
2059 free_hash (image->native_func_wrapper_cache);
2060 free_hash (image->typespec_cache);
2062 mono_wrapper_caches_free (&image->wrapper_caches);
2064 for (i = 0; i < image->gshared_types_len; ++i)
2065 free_hash (image->gshared_types [i]);
2066 g_free (image->gshared_types);
2068 /* The ownership of signatures is not well defined */
2069 g_hash_table_destroy (image->memberref_signatures);
2070 g_hash_table_destroy (image->helper_signatures);
2071 g_hash_table_destroy (image->method_signatures);
2073 if (image->rgctx_template_hash)
2074 g_hash_table_destroy (image->rgctx_template_hash);
2076 if (image->property_hash)
2077 mono_property_hash_destroy (image->property_hash);
2080 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2081 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2083 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2084 image->reflection_info_unregister_classes = NULL;
2086 if (image->interface_bitset) {
2087 mono_unload_interface_ids (image->interface_bitset);
2088 mono_bitset_free (image->interface_bitset);
2090 if (image->image_info){
2091 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2093 if (ii->cli_section_tables)
2094 g_free (ii->cli_section_tables);
2095 if (ii->cli_sections)
2096 g_free (ii->cli_sections);
2097 g_free (image->image_info);
2100 mono_image_close_except_pools_all (image->files, image->file_count);
2101 mono_image_close_except_pools_all (image->modules, image->module_count);
2102 if (image->modules_loaded)
2103 g_free (image->modules_loaded);
2105 mono_os_mutex_destroy (&image->szarray_cache_lock);
2106 mono_os_mutex_destroy (&image->lock);
2108 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2109 if (image_is_dynamic (image)) {
2110 /* Dynamic images are GC_MALLOCed */
2111 g_free ((char*)image->module_name);
2112 mono_dynamic_image_free ((MonoDynamicImage*)image);
2115 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2121 mono_image_close_all (MonoImage**images, int image_count)
2123 for (int i = 0; i < image_count; ++i) {
2125 mono_image_close_finish (images [i]);
2132 mono_image_close_finish (MonoImage *image)
2136 if (image->references && !image_is_dynamic (image)) {
2137 for (i = 0; i < image->nreferences; i++) {
2138 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2139 mono_assembly_close_finish (image->references [i]);
2142 g_free (image->references);
2143 image->references = NULL;
2146 mono_image_close_all (image->files, image->file_count);
2147 mono_image_close_all (image->modules, image->module_count);
2149 #ifndef DISABLE_PERFCOUNTERS
2150 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2153 if (!image_is_dynamic (image)) {
2154 if (debug_assembly_unload)
2155 mono_mempool_invalidate (image->mempool);
2157 mono_mempool_destroy (image->mempool);
2161 if (debug_assembly_unload)
2162 mono_mempool_invalidate (image->mempool);
2164 mono_mempool_destroy (image->mempool);
2165 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2172 * @image: The image file we wish to close
2174 * Closes an image file, deallocates all memory consumed and
2175 * unmaps all possible sections of the file
2178 mono_image_close (MonoImage *image)
2180 if (mono_image_close_except_pools (image))
2181 mono_image_close_finish (image);
2185 * mono_image_strerror:
2186 * @status: an code indicating the result from a recent operation
2188 * Returns: a string describing the error
2191 mono_image_strerror (MonoImageOpenStatus status)
2196 case MONO_IMAGE_ERROR_ERRNO:
2197 return strerror (errno);
2198 case MONO_IMAGE_IMAGE_INVALID:
2199 return "File does not contain a valid CIL image";
2200 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2201 return "An assembly was referenced, but could not be found";
2203 return "Internal error";
2207 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2208 guint32 lang_id, gunichar2 *name,
2209 MonoPEResourceDirEntry *entry,
2210 MonoPEResourceDir *root, guint32 level)
2212 gboolean is_string, is_dir;
2213 guint32 name_offset, dir_offset;
2215 /* Level 0 holds a directory entry for each type of resource
2216 * (identified by ID or name).
2218 * Level 1 holds a directory entry for each named resource
2219 * item, and each "anonymous" item of a particular type of
2222 * Level 2 holds a directory entry for each language pointing to
2225 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2226 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2228 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2229 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2234 } else if (level==1) {
2235 if (res_id != name_offset)
2239 is_string==TRUE && name!=lookup (name_offset)) {
2243 } else if (level==2) {
2244 if (is_string || (lang_id != 0 && name_offset != lang_id))
2247 g_assert_not_reached ();
2251 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2252 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2255 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2257 for(i=0; i<entries; i++) {
2258 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2261 ret=mono_image_walk_resource_tree (info, res_id,
2272 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2273 MonoPEResourceDataEntry *res;
2275 res = g_new0 (MonoPEResourceDataEntry, 1);
2277 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2278 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2279 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2280 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2287 * mono_image_lookup_resource:
2288 * @image: the image to look up the resource in
2289 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2290 * @lang_id: The language id.
2291 * @name: the resource name to lookup.
2293 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2294 * of the given resource. The caller should free it using g_free () when no longer
2298 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2300 MonoCLIImageInfo *info;
2301 MonoDotNetHeader *header;
2302 MonoPEDatadir *datadir;
2303 MonoPEDirEntry *rsrc;
2304 MonoPEResourceDir *resource_dir;
2305 MonoPEResourceDirEntry *res_entries;
2312 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2314 info = (MonoCLIImageInfo *)image->image_info;
2319 header=&info->cli_header;
2324 datadir=&header->datadir;
2329 rsrc=&datadir->pe_resource_table;
2334 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2335 if(resource_dir==NULL) {
2339 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2340 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2342 for(i=0; i<entries; i++) {
2343 MonoPEResourceDirEntry *entry=&res_entries[i];
2346 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2347 name, entry, resource_dir,
2358 * mono_image_get_entry_point:
2359 * @image: the image where the entry point will be looked up.
2361 * Use this routine to determine the metadata token for method that
2362 * has been flagged as the entry point.
2364 * Returns: the token for the entry point method in the image
2367 mono_image_get_entry_point (MonoImage *image)
2369 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2373 * mono_image_get_resource:
2374 * @image: the image where the resource will be looked up.
2375 * @offset: The offset to add to the resource
2376 * @size: a pointer to an int where the size of the resource will be stored
2378 * This is a low-level routine that fetches a resource from the
2379 * metadata that starts at a given @offset. The @size parameter is
2380 * filled with the data field as encoded in the metadata.
2382 * Returns: the pointer to the resource whose offset is @offset.
2385 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2387 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2388 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2391 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2394 data = mono_image_rva_map (image, ch->ch_resources.rva);
2399 *size = read32 (data);
2404 // Returning NULL with no error set will be interpeted as "not found"
2406 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2408 char *base_dir, *name;
2410 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2416 if (fileidx < 1 || fileidx > t->rows)
2419 mono_image_lock (image);
2420 if (image->files && image->files [fileidx - 1]) {
2421 mono_image_unlock (image);
2422 return image->files [fileidx - 1];
2424 mono_image_unlock (image);
2426 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2427 fname = mono_metadata_string_heap (image, fname_id);
2428 base_dir = g_path_get_dirname (image->name);
2429 name = g_build_filename (base_dir, fname, NULL);
2430 res = mono_image_open (name, NULL);
2434 mono_image_lock (image);
2435 if (image->files && image->files [fileidx - 1]) {
2436 MonoImage *old = res;
2437 res = image->files [fileidx - 1];
2438 mono_image_unlock (image);
2439 mono_image_close (old);
2442 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2443 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2444 mono_image_unlock (image);
2445 mono_image_close (res);
2449 for (i = 0; i < res->module_count; ++i) {
2450 if (res->modules [i] && !res->modules [i]->assembly)
2451 res->modules [i]->assembly = image->assembly;
2454 if (!image->files) {
2455 image->files = g_new0 (MonoImage*, t->rows);
2456 image->file_count = t->rows;
2458 image->files [fileidx - 1] = res;
2459 mono_image_unlock (image);
2460 /* vtable fixup can't happen with the image lock held */
2462 if (res->is_module_handle)
2463 mono_image_fixup_vtable (res);
2474 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2477 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2478 mono_error_assert_ok (&error);
2483 * mono_image_get_strong_name:
2484 * @image: a MonoImage
2485 * @size: a guint32 pointer, or NULL.
2487 * If the image has a strong name, and @size is not NULL, the value
2488 * pointed to by size will have the size of the strong name.
2490 * Returns: NULL if the image does not have a strong name, or a
2491 * pointer to the public key.
2494 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2496 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2497 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2500 if (!de->size || !de->rva)
2502 data = mono_image_rva_map (image, de->rva);
2511 * mono_image_strong_name_position:
2512 * @image: a MonoImage
2513 * @size: a guint32 pointer, or NULL.
2515 * If the image has a strong name, and @size is not NULL, the value
2516 * pointed to by size will have the size of the strong name.
2518 * Returns: the position within the image file where the strong name
2522 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2524 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2525 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2530 if (!de->size || !de->rva)
2532 pos = mono_cli_rva_image_map (image, de->rva);
2533 return pos == INVALID_ADDRESS ? 0 : pos;
2537 * mono_image_get_public_key:
2538 * @image: a MonoImage
2539 * @size: a guint32 pointer, or NULL.
2541 * This is used to obtain the public key in the @image.
2543 * If the image has a public key, and @size is not NULL, the value
2544 * pointed to by size will have the size of the public key.
2546 * Returns: NULL if the image does not have a public key, or a pointer
2547 * to the public key.
2550 mono_image_get_public_key (MonoImage *image, guint32 *size)
2555 if (image_is_dynamic (image)) {
2557 *size = ((MonoDynamicImage*)image)->public_key_len;
2558 return (char*)((MonoDynamicImage*)image)->public_key;
2560 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2562 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2565 pubkey = mono_metadata_blob_heap (image, tok);
2566 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2573 * mono_image_get_name:
2574 * @name: a MonoImage
2576 * Returns: the name of the assembly.
2579 mono_image_get_name (MonoImage *image)
2581 return image->assembly_name;
2585 * mono_image_get_filename:
2586 * @image: a MonoImage
2588 * Used to get the filename that hold the actual MonoImage
2590 * Returns: the filename.
2593 mono_image_get_filename (MonoImage *image)
2599 mono_image_get_guid (MonoImage *image)
2604 const MonoTableInfo*
2605 mono_image_get_table_info (MonoImage *image, int table_id)
2607 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2609 return &image->tables [table_id];
2613 mono_image_get_table_rows (MonoImage *image, int table_id)
2615 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2617 return image->tables [table_id].rows;
2621 mono_table_info_get_rows (const MonoTableInfo *table)
2627 * mono_image_get_assembly:
2628 * @image: the MonoImage.
2630 * Use this routine to get the assembly that owns this image.
2632 * Returns: the assembly that holds this image.
2635 mono_image_get_assembly (MonoImage *image)
2637 return image->assembly;
2641 * mono_image_is_dynamic:
2642 * @image: the MonoImage
2644 * Determines if the given image was created dynamically through the
2645 * System.Reflection.Emit API
2647 * Returns: TRUE if the image was created dynamically, FALSE if not.
2650 mono_image_is_dynamic (MonoImage *image)
2652 return image_is_dynamic (image);
2656 * mono_image_has_authenticode_entry:
2657 * @image: the MonoImage
2659 * Use this routine to determine if the image has a Authenticode
2660 * Certificate Table.
2662 * Returns: TRUE if the image contains an authenticode entry in the PE
2666 mono_image_has_authenticode_entry (MonoImage *image)
2668 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2669 MonoDotNetHeader *header = &iinfo->cli_header;
2672 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2673 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2674 return ((de->rva != 0) && (de->size > 8));
2678 mono_image_alloc (MonoImage *image, guint size)
2682 #ifndef DISABLE_PERFCOUNTERS
2683 mono_perfcounters->loader_bytes += size;
2685 mono_image_lock (image);
2686 res = mono_mempool_alloc (image->mempool, size);
2687 mono_image_unlock (image);
2693 mono_image_alloc0 (MonoImage *image, guint size)
2697 #ifndef DISABLE_PERFCOUNTERS
2698 mono_perfcounters->loader_bytes += size;
2700 mono_image_lock (image);
2701 res = mono_mempool_alloc0 (image->mempool, size);
2702 mono_image_unlock (image);
2708 mono_image_strdup (MonoImage *image, const char *s)
2712 #ifndef DISABLE_PERFCOUNTERS
2713 mono_perfcounters->loader_bytes += strlen (s);
2715 mono_image_lock (image);
2716 res = mono_mempool_strdup (image->mempool, s);
2717 mono_image_unlock (image);
2723 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2726 mono_image_lock (image);
2727 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2728 mono_image_unlock (image);
2729 #ifndef DISABLE_PERFCOUNTERS
2730 mono_perfcounters->loader_bytes += strlen (buf);
2736 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2741 va_start (args, format);
2742 buf = mono_image_strdup_vprintf (image, format, args);
2748 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2752 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2753 new_list->data = data;
2754 new_list->prev = list ? list->prev : NULL;
2755 new_list->next = list;
2758 new_list->prev->next = new_list;
2760 list->prev = new_list;
2766 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2770 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2771 new_list->data = data;
2772 new_list->next = NULL;
2774 return g_slist_concat (list, new_list);
2778 mono_image_lock (MonoImage *image)
2780 mono_locks_os_acquire (&image->lock, ImageDataLock);
2784 mono_image_unlock (MonoImage *image)
2786 mono_locks_os_release (&image->lock, ImageDataLock);
2791 * mono_image_property_lookup:
2793 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2795 * LOCKING: Takes the image lock
2798 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2802 mono_image_lock (image);
2803 res = mono_property_hash_lookup (image->property_hash, subject, property);
2804 mono_image_unlock (image);
2810 * mono_image_property_insert:
2812 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2814 * LOCKING: Takes the image lock
2817 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2819 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2820 mono_image_lock (image);
2821 mono_property_hash_insert (image->property_hash, subject, property, value);
2822 mono_image_unlock (image);
2826 * mono_image_property_remove:
2828 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2830 * LOCKING: Takes the image lock
2833 mono_image_property_remove (MonoImage *image, gpointer subject)
2835 mono_image_lock (image);
2836 mono_property_hash_remove_object (image->property_hash, subject);
2837 mono_image_unlock (image);
2841 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2843 MonoImage *image = klass->image;
2844 g_assert (image_is_dynamic (image));
2845 mono_image_lock (image);
2846 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2847 mono_image_unlock (image);
2850 // 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.
2853 * mono_find_image_owner:
2855 * Find the image, if any, which a given pointer is located in the memory of.
2858 mono_find_image_owner (void *ptr)
2860 mono_images_lock ();
2862 MonoImage *owner = NULL;
2864 // Iterate over both by-path image hashes
2865 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2867 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2869 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2870 GHashTableIter iter;
2873 // Iterate over images within a hash
2874 g_hash_table_iter_init (&iter, target);
2875 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2877 mono_image_lock (image);
2878 if (mono_mempool_contains_addr (image->mempool, ptr))
2880 mono_image_unlock (image);
2884 mono_images_unlock ();