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;
694 mono_error_init (error);
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_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];
1127 const char *ignored_assemblies_names[] = {
1128 "System.Runtime.InteropServices.RuntimeInformation.dll",
1129 "System.Globalization.Extensions.dll",
1130 "System.IO.Compression.dll",
1131 "System.Net.Http.dll",
1132 "System.Text.Encoding.CodePages.dll",
1133 "System.Reflection.DispatchProxy.dll",
1134 "System.ValueTuple.dll"
1137 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1139 static const IgnoredAssembly ignored_assemblies [] = {
1140 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1141 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1142 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1143 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1144 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1145 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1146 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1147 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1148 IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1149 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1150 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1151 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1152 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1153 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1154 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1155 IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
1160 static void Main () {
1163 for (int i = 0; i < str.Length; ++i)
1164 h = ((h << 5) + h) ^ str[i];
1166 Console.WriteLine ("{0:X}", h);
1170 hash_guid (const char *str)
1174 h = ((h << 5) + h) ^ *str;
1182 is_problematic_image (MonoImage *image)
1184 int h = hash_guid (image->guid);
1186 //TODO make this more cache effiecient.
1187 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1188 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1189 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1190 const char *needle = ignored_assemblies_names [ignored_assemblies [i].assembly_name];
1191 size_t needle_len = strlen (needle);
1192 size_t asm_len = strlen (image->name);
1193 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1201 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1202 gboolean care_about_cli, gboolean care_about_pecoff)
1204 MonoCLIImageInfo *iinfo;
1205 MonoDotNetHeader *header;
1206 GSList *errors = NULL;
1209 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1211 mono_image_init (image);
1213 iinfo = (MonoCLIImageInfo *)image->image_info;
1214 header = &iinfo->cli_header;
1216 if (!image->metadata_only) {
1217 for (l = image_loaders; l; l = l->next) {
1218 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1219 if (loader->match (image)) {
1220 image->loader = loader;
1224 if (!image->loader) {
1226 *status = MONO_IMAGE_IMAGE_INVALID;
1231 *status = MONO_IMAGE_IMAGE_INVALID;
1233 if (care_about_pecoff == FALSE)
1236 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1239 if (!mono_image_load_pe_data (image))
1242 image->loader = (MonoImageLoader*)&pe_loader;
1245 if (care_about_cli == FALSE) {
1249 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1252 if (!mono_image_load_cli_data (image))
1255 if (!image->ref_only && is_problematic_image (image)) {
1256 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1257 *status = MONO_IMAGE_IMAGE_INVALID;
1261 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1264 mono_image_load_names (image);
1266 load_modules (image);
1269 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1271 *status = MONO_IMAGE_OK;
1277 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1278 g_warning ("Could not load image %s due to %s", image->name, info->message);
1279 mono_free_verify_list (errors);
1281 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1282 mono_image_close (image);
1287 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1288 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1290 MonoCLIImageInfo *iinfo;
1294 if ((filed = mono_file_map_open (fname)) == NULL){
1295 if (IS_PORTABILITY_SET) {
1296 gchar *ffname = mono_portability_find_file (fname, TRUE);
1298 filed = mono_file_map_open (ffname);
1303 if (filed == NULL) {
1305 *status = MONO_IMAGE_ERROR_ERRNO;
1310 image = g_new0 (MonoImage, 1);
1311 image->raw_buffer_used = TRUE;
1312 image->raw_data_len = mono_file_map_size (filed);
1313 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);
1314 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1315 if (!image->raw_data) {
1316 image->fileio_used = TRUE;
1317 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);
1320 if (!image->raw_data) {
1321 mono_file_map_close (filed);
1324 *status = MONO_IMAGE_IMAGE_INVALID;
1327 iinfo = g_new0 (MonoCLIImageInfo, 1);
1328 image->image_info = iinfo;
1329 image->name = mono_path_resolve_symlinks (fname);
1330 image->ref_only = refonly;
1331 image->metadata_only = metadata_only;
1332 image->ref_count = 1;
1333 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1334 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1336 mono_file_map_close (filed);
1337 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1341 * mono_image_loaded:
1342 * @name: path or assembly name of the image to load
1343 * @refonly: Check with respect to reflection-only loads?
1345 * This routine verifies that the given image is loaded.
1346 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1348 * Returns: the loaded MonoImage, or NULL on failure.
1351 mono_image_loaded_full (const char *name, gboolean refonly)
1355 mono_images_lock ();
1356 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1358 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1359 mono_images_unlock ();
1365 * mono_image_loaded:
1366 * @name: path or assembly name of the image to load
1368 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1370 * Returns: the loaded MonoImage, or NULL on failure.
1373 mono_image_loaded (const char *name)
1375 return mono_image_loaded_full (name, FALSE);
1384 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1386 GuidData *data = (GuidData *)user_data;
1391 image = (MonoImage *)val;
1392 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1397 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1400 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1404 mono_images_lock ();
1405 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1406 mono_images_unlock ();
1411 mono_image_loaded_by_guid (const char *guid)
1413 return mono_image_loaded_by_guid_full (guid, FALSE);
1417 register_image (MonoImage *image)
1420 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1422 mono_images_lock ();
1423 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1426 /* Somebody else beat us to it */
1427 mono_image_addref (image2);
1428 mono_images_unlock ();
1429 mono_image_close (image);
1433 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1434 g_hash_table_insert (loaded_images, image->name, image);
1435 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1436 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1437 mono_images_unlock ();
1443 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1445 MonoCLIImageInfo *iinfo;
1449 if (!data || !data_len) {
1451 *status = MONO_IMAGE_IMAGE_INVALID;
1456 datac = (char *)g_try_malloc (data_len);
1459 *status = MONO_IMAGE_ERROR_ERRNO;
1462 memcpy (datac, data, data_len);
1465 image = g_new0 (MonoImage, 1);
1466 image->raw_data = datac;
1467 image->raw_data_len = data_len;
1468 image->raw_data_allocated = need_copy;
1469 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1470 iinfo = g_new0 (MonoCLIImageInfo, 1);
1471 image->image_info = iinfo;
1472 image->ref_only = refonly;
1473 image->metadata_only = metadata_only;
1474 image->ref_count = 1;
1476 image = do_mono_image_load (image, status, TRUE, TRUE);
1480 return register_image (image);
1484 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1486 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1490 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1492 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1496 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1498 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1502 /* fname is not duplicated. */
1504 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1507 MonoCLIImageInfo* iinfo;
1509 image = g_new0 (MonoImage, 1);
1510 image->raw_data = (char*) module_handle;
1511 image->is_module_handle = TRUE;
1512 iinfo = g_new0 (MonoCLIImageInfo, 1);
1513 image->image_info = iinfo;
1514 image->name = fname;
1515 image->ref_count = has_entry_point ? 0 : 1;
1516 image->has_entry_point = has_entry_point;
1518 image = do_mono_image_load (image, status, TRUE, TRUE);
1522 return register_image (image);
1527 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1530 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1533 g_return_val_if_fail (fname != NULL, NULL);
1536 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1537 // then assemblies need to be loaded with LoadLibrary:
1538 if (!refonly && coree_module_handle) {
1539 HMODULE module_handle;
1540 guint16 *fname_utf16;
1543 absfname = mono_path_resolve_symlinks (fname);
1546 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1547 mono_images_lock ();
1548 image = g_hash_table_lookup (loaded_images, absfname);
1549 if (image) { // Image already loaded
1550 g_assert (image->is_module_handle);
1551 if (image->has_entry_point && image->ref_count == 0) {
1552 /* Increment reference count on images loaded outside of the runtime. */
1553 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1554 /* The image is already loaded because _CorDllMain removes images from the hash. */
1555 module_handle = LoadLibrary (fname_utf16);
1556 g_assert (module_handle == (HMODULE) image->raw_data);
1558 mono_image_addref (image);
1559 mono_images_unlock ();
1561 g_free (fname_utf16);
1566 // Image not loaded, load it now
1567 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1568 module_handle = MonoLoadImage (fname_utf16);
1569 if (status && module_handle == NULL)
1570 last_error = mono_w32error_get_last ();
1572 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1573 image = g_hash_table_lookup (loaded_images, absfname);
1575 mono_image_addref (image);
1576 mono_images_unlock ();
1578 g_free (fname_utf16);
1580 if (module_handle == NULL) {
1584 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1585 *status = MONO_IMAGE_IMAGE_INVALID;
1587 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1597 g_assert (image->is_module_handle);
1598 g_assert (image->has_entry_point);
1603 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1607 absfname = mono_path_canonicalize (fname);
1610 * The easiest solution would be to do all the loading inside the mutex,
1611 * but that would lead to scalability problems. So we let the loading
1612 * happen outside the mutex, and if multiple threads happen to load
1613 * the same image, we discard all but the first copy.
1615 mono_images_lock ();
1616 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1619 if (image) { // Image already loaded
1620 mono_image_addref (image);
1621 mono_images_unlock ();
1624 mono_images_unlock ();
1626 // Image not loaded, load it now
1627 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1631 return register_image (image);
1636 * @fname: filename that points to the module we want to open
1637 * @status: An error condition is returned in this field
1639 * Returns: An open image of type %MonoImage or NULL on error.
1640 * The caller holds a temporary reference to the returned image which should be cleared
1641 * when no longer needed by calling mono_image_close ().
1642 * if NULL, then check the value of @status for details on the error
1645 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1647 return mono_image_open_full (fname, status, FALSE);
1651 * mono_pe_file_open:
1652 * @fname: filename that points to the module we want to open
1653 * @status: An error condition is returned in this field
1655 * Returns: An open image of type %MonoImage or NULL on error. if
1656 * NULL, then check the value of @status for details on the error.
1657 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1658 * It's just a PE file loader, used for FileVersionInfo. It also does
1659 * not use the image cache.
1662 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1664 g_return_val_if_fail (fname != NULL, NULL);
1666 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1670 * mono_image_open_raw
1671 * @fname: filename that points to the module we want to open
1672 * @status: An error condition is returned in this field
1674 * Returns an image without loading neither pe or cli data.
1676 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1679 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1681 g_return_val_if_fail (fname != NULL, NULL);
1683 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1687 * mono_image_open_metadata_only:
1689 * Open an image which contains metadata only without a PE header.
1692 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1694 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1698 mono_image_fixup_vtable (MonoImage *image)
1701 MonoCLIImageInfo *iinfo;
1703 MonoVTableFixup *vtfixup;
1709 g_assert (image->is_module_handle);
1711 iinfo = image->image_info;
1712 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1713 if (!de->rva || !de->size)
1715 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1719 count = de->size / sizeof (MonoVTableFixup);
1721 if (!vtfixup->rva || !vtfixup->count)
1724 slot = mono_image_rva_map (image, vtfixup->rva);
1726 slot_type = vtfixup->type;
1727 slot_count = vtfixup->count;
1728 if (slot_type & VTFIXUP_TYPE_32BIT)
1729 while (slot_count--) {
1730 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1731 slot = ((guint32*) slot) + 1;
1733 else if (slot_type & VTFIXUP_TYPE_64BIT)
1734 while (slot_count--) {
1735 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1736 slot = ((guint32*) slot) + 1;
1739 g_assert_not_reached();
1744 g_assert_not_reached();
1749 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1751 g_hash_table_destroy ((GHashTable*)val);
1756 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1758 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1763 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1765 g_slist_free ((GSList*)val);
1769 * mono_image_addref:
1770 * @image: The image file we wish to add a reference to
1772 * Increases the reference count of an image.
1775 mono_image_addref (MonoImage *image)
1777 InterlockedIncrement (&image->ref_count);
1781 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1783 stream->alloc_size = stream->index = stream->offset = 0;
1784 g_free (stream->data);
1785 stream->data = NULL;
1787 g_hash_table_destroy (stream->hash);
1788 stream->hash = NULL;
1793 free_hash (GHashTable *hash)
1796 g_hash_table_destroy (hash);
1800 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1802 free_hash (cache->delegate_invoke_cache);
1803 free_hash (cache->delegate_begin_invoke_cache);
1804 free_hash (cache->delegate_end_invoke_cache);
1805 free_hash (cache->runtime_invoke_cache);
1806 free_hash (cache->runtime_invoke_vtype_cache);
1808 free_hash (cache->delegate_abstract_invoke_cache);
1810 free_hash (cache->runtime_invoke_direct_cache);
1811 free_hash (cache->managed_wrapper_cache);
1813 free_hash (cache->native_wrapper_cache);
1814 free_hash (cache->native_wrapper_aot_cache);
1815 free_hash (cache->native_wrapper_check_cache);
1816 free_hash (cache->native_wrapper_aot_check_cache);
1818 free_hash (cache->native_func_wrapper_aot_cache);
1819 free_hash (cache->remoting_invoke_cache);
1820 free_hash (cache->synchronized_cache);
1821 free_hash (cache->unbox_wrapper_cache);
1822 free_hash (cache->cominterop_invoke_cache);
1823 free_hash (cache->cominterop_wrapper_cache);
1824 free_hash (cache->thunk_invoke_cache);
1828 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1830 for (int i = 0; i < image_count; ++i) {
1832 if (!mono_image_close_except_pools (images [i]))
1839 * Returns whether mono_image_close_finish() must be called as well.
1840 * We must unload images in two steps because clearing the domain in
1841 * SGen requires the class metadata to be intact, but we need to free
1842 * the mono_g_hash_tables in case a collection occurs during domain
1843 * unloading and the roots would trip up the GC.
1846 mono_image_close_except_pools (MonoImage *image)
1849 GHashTable *loaded_images, *loaded_images_by_name;
1852 g_return_val_if_fail (image != NULL, FALSE);
1855 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1856 * register_image () can't grab an image which is being closed.
1858 mono_images_lock ();
1860 if (InterlockedDecrement (&image->ref_count) > 0) {
1861 mono_images_unlock ();
1865 loaded_images = get_loaded_images_hash (image->ref_only);
1866 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1867 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1868 if (image == image2) {
1869 /* This is not true if we are called from mono_image_open () */
1870 g_hash_table_remove (loaded_images, image->name);
1872 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1873 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1875 mono_images_unlock ();
1878 if (image->is_module_handle && image->has_entry_point) {
1879 mono_images_lock ();
1880 if (image->ref_count == 0) {
1881 /* Image will be closed by _CorDllMain. */
1882 FreeLibrary ((HMODULE) image->raw_data);
1883 mono_images_unlock ();
1886 mono_images_unlock ();
1890 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1892 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1894 mono_image_invoke_unload_hook (image);
1896 mono_metadata_clean_for_image (image);
1899 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1900 * assemblies, so we can't release these references in mono_assembly_close () since the
1901 * MonoImage might outlive its associated MonoAssembly.
1903 if (image->references && !image_is_dynamic (image)) {
1904 for (i = 0; i < image->nreferences; i++) {
1905 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1906 if (!mono_assembly_close_except_image_pools (image->references [i]))
1907 image->references [i] = NULL;
1911 if (image->references) {
1912 g_free (image->references);
1913 image->references = NULL;
1918 mono_images_lock ();
1919 if (image->is_module_handle && !image->has_entry_point)
1920 FreeLibrary ((HMODULE) image->raw_data);
1921 mono_images_unlock ();
1924 if (image->raw_buffer_used) {
1925 if (image->raw_data != NULL) {
1927 if (image->fileio_used)
1928 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1931 mono_file_unmap (image->raw_data, image->raw_data_handle);
1935 if (image->raw_data_allocated) {
1936 /* FIXME: do we need this? (image is disposed anyway) */
1937 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1938 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1940 if ((image->raw_metadata > image->raw_data) &&
1941 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1942 image->raw_metadata = NULL;
1944 for (i = 0; i < ii->cli_section_count; i++)
1945 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1946 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1947 ii->cli_sections [i] = NULL;
1949 g_free (image->raw_data);
1952 if (debug_assembly_unload) {
1953 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1955 g_free (image->name);
1956 g_free (image->guid);
1957 g_free (image->version);
1960 if (image->method_cache)
1961 g_hash_table_destroy (image->method_cache);
1962 if (image->methodref_cache)
1963 g_hash_table_destroy (image->methodref_cache);
1964 mono_internal_hash_table_destroy (&image->class_cache);
1965 mono_conc_hashtable_destroy (image->field_cache);
1966 if (image->array_cache) {
1967 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1968 g_hash_table_destroy (image->array_cache);
1970 if (image->szarray_cache)
1971 g_hash_table_destroy (image->szarray_cache);
1972 if (image->ptr_cache)
1973 g_hash_table_destroy (image->ptr_cache);
1974 if (image->name_cache) {
1975 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1976 g_hash_table_destroy (image->name_cache);
1979 free_hash (image->delegate_bound_static_invoke_cache);
1980 free_hash (image->runtime_invoke_vcall_cache);
1981 free_hash (image->ldfld_wrapper_cache);
1982 free_hash (image->ldflda_wrapper_cache);
1983 free_hash (image->stfld_wrapper_cache);
1984 free_hash (image->isinst_cache);
1985 free_hash (image->castclass_cache);
1986 free_hash (image->icall_wrapper_cache);
1987 free_hash (image->proxy_isinst_cache);
1988 free_hash (image->var_cache_slow);
1989 free_hash (image->mvar_cache_slow);
1990 free_hash (image->var_cache_constrained);
1991 free_hash (image->mvar_cache_constrained);
1992 free_hash (image->wrapper_param_names);
1993 free_hash (image->pinvoke_scopes);
1994 free_hash (image->pinvoke_scope_filenames);
1995 free_hash (image->native_func_wrapper_cache);
1996 free_hash (image->typespec_cache);
1998 mono_wrapper_caches_free (&image->wrapper_caches);
2000 for (i = 0; i < image->gshared_types_len; ++i)
2001 free_hash (image->gshared_types [i]);
2002 g_free (image->gshared_types);
2004 /* The ownership of signatures is not well defined */
2005 g_hash_table_destroy (image->memberref_signatures);
2006 g_hash_table_destroy (image->helper_signatures);
2007 g_hash_table_destroy (image->method_signatures);
2009 if (image->rgctx_template_hash)
2010 g_hash_table_destroy (image->rgctx_template_hash);
2012 if (image->property_hash)
2013 mono_property_hash_destroy (image->property_hash);
2016 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2017 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2019 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2020 image->reflection_info_unregister_classes = NULL;
2022 if (image->interface_bitset) {
2023 mono_unload_interface_ids (image->interface_bitset);
2024 mono_bitset_free (image->interface_bitset);
2026 if (image->image_info){
2027 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2029 if (ii->cli_section_tables)
2030 g_free (ii->cli_section_tables);
2031 if (ii->cli_sections)
2032 g_free (ii->cli_sections);
2033 g_free (image->image_info);
2036 mono_image_close_except_pools_all (image->files, image->file_count);
2037 mono_image_close_except_pools_all (image->modules, image->module_count);
2038 if (image->modules_loaded)
2039 g_free (image->modules_loaded);
2041 mono_os_mutex_destroy (&image->szarray_cache_lock);
2042 mono_os_mutex_destroy (&image->lock);
2044 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2045 if (image_is_dynamic (image)) {
2046 /* Dynamic images are GC_MALLOCed */
2047 g_free ((char*)image->module_name);
2048 mono_dynamic_image_free ((MonoDynamicImage*)image);
2051 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2057 mono_image_close_all (MonoImage**images, int image_count)
2059 for (int i = 0; i < image_count; ++i) {
2061 mono_image_close_finish (images [i]);
2068 mono_image_close_finish (MonoImage *image)
2072 if (image->references && !image_is_dynamic (image)) {
2073 for (i = 0; i < image->nreferences; i++) {
2074 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2075 mono_assembly_close_finish (image->references [i]);
2078 g_free (image->references);
2079 image->references = NULL;
2082 mono_image_close_all (image->files, image->file_count);
2083 mono_image_close_all (image->modules, image->module_count);
2085 #ifndef DISABLE_PERFCOUNTERS
2086 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2089 if (!image_is_dynamic (image)) {
2090 if (debug_assembly_unload)
2091 mono_mempool_invalidate (image->mempool);
2093 mono_mempool_destroy (image->mempool);
2097 if (debug_assembly_unload)
2098 mono_mempool_invalidate (image->mempool);
2100 mono_mempool_destroy (image->mempool);
2101 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2108 * @image: The image file we wish to close
2110 * Closes an image file, deallocates all memory consumed and
2111 * unmaps all possible sections of the file
2114 mono_image_close (MonoImage *image)
2116 if (mono_image_close_except_pools (image))
2117 mono_image_close_finish (image);
2121 * mono_image_strerror:
2122 * @status: an code indicating the result from a recent operation
2124 * Returns: a string describing the error
2127 mono_image_strerror (MonoImageOpenStatus status)
2132 case MONO_IMAGE_ERROR_ERRNO:
2133 return strerror (errno);
2134 case MONO_IMAGE_IMAGE_INVALID:
2135 return "File does not contain a valid CIL image";
2136 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2137 return "An assembly was referenced, but could not be found";
2139 return "Internal error";
2143 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2144 guint32 lang_id, gunichar2 *name,
2145 MonoPEResourceDirEntry *entry,
2146 MonoPEResourceDir *root, guint32 level)
2148 gboolean is_string, is_dir;
2149 guint32 name_offset, dir_offset;
2151 /* Level 0 holds a directory entry for each type of resource
2152 * (identified by ID or name).
2154 * Level 1 holds a directory entry for each named resource
2155 * item, and each "anonymous" item of a particular type of
2158 * Level 2 holds a directory entry for each language pointing to
2161 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2162 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2164 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2165 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2170 } else if (level==1) {
2171 if (res_id != name_offset)
2175 is_string==TRUE && name!=lookup (name_offset)) {
2179 } else if (level==2) {
2180 if (is_string || (lang_id != 0 && name_offset != lang_id))
2183 g_assert_not_reached ();
2187 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2188 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2191 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2193 for(i=0; i<entries; i++) {
2194 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2197 ret=mono_image_walk_resource_tree (info, res_id,
2208 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2209 MonoPEResourceDataEntry *res;
2211 res = g_new0 (MonoPEResourceDataEntry, 1);
2213 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2214 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2215 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2216 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2223 * mono_image_lookup_resource:
2224 * @image: the image to look up the resource in
2225 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2226 * @lang_id: The language id.
2227 * @name: the resource name to lookup.
2229 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2230 * of the given resource. The caller should free it using g_free () when no longer
2234 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2236 MonoCLIImageInfo *info;
2237 MonoDotNetHeader *header;
2238 MonoPEDatadir *datadir;
2239 MonoPEDirEntry *rsrc;
2240 MonoPEResourceDir *resource_dir;
2241 MonoPEResourceDirEntry *res_entries;
2248 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2250 info = (MonoCLIImageInfo *)image->image_info;
2255 header=&info->cli_header;
2260 datadir=&header->datadir;
2265 rsrc=&datadir->pe_resource_table;
2270 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2271 if(resource_dir==NULL) {
2275 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2276 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2278 for(i=0; i<entries; i++) {
2279 MonoPEResourceDirEntry *entry=&res_entries[i];
2282 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2283 name, entry, resource_dir,
2294 * mono_image_get_entry_point:
2295 * @image: the image where the entry point will be looked up.
2297 * Use this routine to determine the metadata token for method that
2298 * has been flagged as the entry point.
2300 * Returns: the token for the entry point method in the image
2303 mono_image_get_entry_point (MonoImage *image)
2305 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2309 * mono_image_get_resource:
2310 * @image: the image where the resource will be looked up.
2311 * @offset: The offset to add to the resource
2312 * @size: a pointer to an int where the size of the resource will be stored
2314 * This is a low-level routine that fetches a resource from the
2315 * metadata that starts at a given @offset. The @size parameter is
2316 * filled with the data field as encoded in the metadata.
2318 * Returns: the pointer to the resource whose offset is @offset.
2321 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2323 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2324 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2327 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2330 data = mono_image_rva_map (image, ch->ch_resources.rva);
2335 *size = read32 (data);
2340 // Returning NULL with no error set will be interpeted as "not found"
2342 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2344 char *base_dir, *name;
2346 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2350 mono_error_init (error);
2352 if (fileidx < 1 || fileidx > t->rows)
2355 mono_image_lock (image);
2356 if (image->files && image->files [fileidx - 1]) {
2357 mono_image_unlock (image);
2358 return image->files [fileidx - 1];
2360 mono_image_unlock (image);
2362 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2363 fname = mono_metadata_string_heap (image, fname_id);
2364 base_dir = g_path_get_dirname (image->name);
2365 name = g_build_filename (base_dir, fname, NULL);
2366 res = mono_image_open (name, NULL);
2370 mono_image_lock (image);
2371 if (image->files && image->files [fileidx - 1]) {
2372 MonoImage *old = res;
2373 res = image->files [fileidx - 1];
2374 mono_image_unlock (image);
2375 mono_image_close (old);
2378 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2379 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2380 mono_image_unlock (image);
2381 mono_image_close (res);
2385 for (i = 0; i < res->module_count; ++i) {
2386 if (res->modules [i] && !res->modules [i]->assembly)
2387 res->modules [i]->assembly = image->assembly;
2390 if (!image->files) {
2391 image->files = g_new0 (MonoImage*, t->rows);
2392 image->file_count = t->rows;
2394 image->files [fileidx - 1] = res;
2395 mono_image_unlock (image);
2396 /* vtable fixup can't happen with the image lock held */
2398 if (res->is_module_handle)
2399 mono_image_fixup_vtable (res);
2410 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2413 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2414 mono_error_assert_ok (&error);
2419 * mono_image_get_strong_name:
2420 * @image: a MonoImage
2421 * @size: a guint32 pointer, or NULL.
2423 * If the image has a strong name, and @size is not NULL, the value
2424 * pointed to by size will have the size of the strong name.
2426 * Returns: NULL if the image does not have a strong name, or a
2427 * pointer to the public key.
2430 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2432 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2433 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2436 if (!de->size || !de->rva)
2438 data = mono_image_rva_map (image, de->rva);
2447 * mono_image_strong_name_position:
2448 * @image: a MonoImage
2449 * @size: a guint32 pointer, or NULL.
2451 * If the image has a strong name, and @size is not NULL, the value
2452 * pointed to by size will have the size of the strong name.
2454 * Returns: the position within the image file where the strong name
2458 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2460 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2461 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2466 if (!de->size || !de->rva)
2468 pos = mono_cli_rva_image_map (image, de->rva);
2469 return pos == INVALID_ADDRESS ? 0 : pos;
2473 * mono_image_get_public_key:
2474 * @image: a MonoImage
2475 * @size: a guint32 pointer, or NULL.
2477 * This is used to obtain the public key in the @image.
2479 * If the image has a public key, and @size is not NULL, the value
2480 * pointed to by size will have the size of the public key.
2482 * Returns: NULL if the image does not have a public key, or a pointer
2483 * to the public key.
2486 mono_image_get_public_key (MonoImage *image, guint32 *size)
2491 if (image_is_dynamic (image)) {
2493 *size = ((MonoDynamicImage*)image)->public_key_len;
2494 return (char*)((MonoDynamicImage*)image)->public_key;
2496 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2498 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2501 pubkey = mono_metadata_blob_heap (image, tok);
2502 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2509 * mono_image_get_name:
2510 * @name: a MonoImage
2512 * Returns: the name of the assembly.
2515 mono_image_get_name (MonoImage *image)
2517 return image->assembly_name;
2521 * mono_image_get_filename:
2522 * @image: a MonoImage
2524 * Used to get the filename that hold the actual MonoImage
2526 * Returns: the filename.
2529 mono_image_get_filename (MonoImage *image)
2535 mono_image_get_guid (MonoImage *image)
2540 const MonoTableInfo*
2541 mono_image_get_table_info (MonoImage *image, int table_id)
2543 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2545 return &image->tables [table_id];
2549 mono_image_get_table_rows (MonoImage *image, int table_id)
2551 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2553 return image->tables [table_id].rows;
2557 mono_table_info_get_rows (const MonoTableInfo *table)
2563 * mono_image_get_assembly:
2564 * @image: the MonoImage.
2566 * Use this routine to get the assembly that owns this image.
2568 * Returns: the assembly that holds this image.
2571 mono_image_get_assembly (MonoImage *image)
2573 return image->assembly;
2577 * mono_image_is_dynamic:
2578 * @image: the MonoImage
2580 * Determines if the given image was created dynamically through the
2581 * System.Reflection.Emit API
2583 * Returns: TRUE if the image was created dynamically, FALSE if not.
2586 mono_image_is_dynamic (MonoImage *image)
2588 return image_is_dynamic (image);
2592 * mono_image_has_authenticode_entry:
2593 * @image: the MonoImage
2595 * Use this routine to determine if the image has a Authenticode
2596 * Certificate Table.
2598 * Returns: TRUE if the image contains an authenticode entry in the PE
2602 mono_image_has_authenticode_entry (MonoImage *image)
2604 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2605 MonoDotNetHeader *header = &iinfo->cli_header;
2608 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2609 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2610 return ((de->rva != 0) && (de->size > 8));
2614 mono_image_alloc (MonoImage *image, guint size)
2618 #ifndef DISABLE_PERFCOUNTERS
2619 mono_perfcounters->loader_bytes += size;
2621 mono_image_lock (image);
2622 res = mono_mempool_alloc (image->mempool, size);
2623 mono_image_unlock (image);
2629 mono_image_alloc0 (MonoImage *image, guint size)
2633 #ifndef DISABLE_PERFCOUNTERS
2634 mono_perfcounters->loader_bytes += size;
2636 mono_image_lock (image);
2637 res = mono_mempool_alloc0 (image->mempool, size);
2638 mono_image_unlock (image);
2644 mono_image_strdup (MonoImage *image, const char *s)
2648 #ifndef DISABLE_PERFCOUNTERS
2649 mono_perfcounters->loader_bytes += strlen (s);
2651 mono_image_lock (image);
2652 res = mono_mempool_strdup (image->mempool, s);
2653 mono_image_unlock (image);
2659 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2662 mono_image_lock (image);
2663 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2664 mono_image_unlock (image);
2665 #ifndef DISABLE_PERFCOUNTERS
2666 mono_perfcounters->loader_bytes += strlen (buf);
2672 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2677 va_start (args, format);
2678 buf = mono_image_strdup_vprintf (image, format, args);
2684 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2688 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2689 new_list->data = data;
2690 new_list->prev = list ? list->prev : NULL;
2691 new_list->next = list;
2694 new_list->prev->next = new_list;
2696 list->prev = new_list;
2702 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2706 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2707 new_list->data = data;
2708 new_list->next = NULL;
2710 return g_slist_concat (list, new_list);
2714 mono_image_lock (MonoImage *image)
2716 mono_locks_os_acquire (&image->lock, ImageDataLock);
2720 mono_image_unlock (MonoImage *image)
2722 mono_locks_os_release (&image->lock, ImageDataLock);
2727 * mono_image_property_lookup:
2729 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2731 * LOCKING: Takes the image lock
2734 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2738 mono_image_lock (image);
2739 res = mono_property_hash_lookup (image->property_hash, subject, property);
2740 mono_image_unlock (image);
2746 * mono_image_property_insert:
2748 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2750 * LOCKING: Takes the image lock
2753 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2755 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2756 mono_image_lock (image);
2757 mono_property_hash_insert (image->property_hash, subject, property, value);
2758 mono_image_unlock (image);
2762 * mono_image_property_remove:
2764 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2766 * LOCKING: Takes the image lock
2769 mono_image_property_remove (MonoImage *image, gpointer subject)
2771 mono_image_lock (image);
2772 mono_property_hash_remove_object (image->property_hash, subject);
2773 mono_image_unlock (image);
2777 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2779 MonoImage *image = klass->image;
2780 g_assert (image_is_dynamic (image));
2781 mono_image_lock (image);
2782 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2783 mono_image_unlock (image);
2786 // 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.
2789 * mono_find_image_owner:
2791 * Find the image, if any, which a given pointer is located in the memory of.
2794 mono_find_image_owner (void *ptr)
2796 mono_images_lock ();
2798 MonoImage *owner = NULL;
2800 // Iterate over both by-path image hashes
2801 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2803 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2805 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2806 GHashTableIter iter;
2809 // Iterate over images within a hash
2810 g_hash_table_iter_init (&iter, target);
2811 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2813 mono_image_lock (image);
2814 if (mono_mempool_contains_addr (image->mempool, ptr))
2816 mono_image_unlock (image);
2820 mono_images_unlock ();