[Loader] Change mono_trace level from info to debug (#19110)
[mono-project.git] / mono / metadata / image.c
blobc7b309d60b8428a0f032ff0a9bcc29c37fd8bda1
1 /**
2 * \file
3 * Routines for manipulating an image stored in an
4 * extended PE/COFF file.
5 *
6 * Authors:
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.
15 #include <config.h>
16 #include <stdio.h>
17 #include <glib.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <string.h>
21 #include "image.h"
22 #include "cil-coff.h"
23 #include "mono-endian.h"
24 #include "tabledefs.h"
25 #include "tokentype.h"
26 #include "metadata-internals.h"
27 #include "profiler-private.h"
28 #include "loader.h"
29 #include "marshal.h"
30 #include "coree.h"
31 #include <mono/metadata/exception-internals.h>
32 #include <mono/utils/checked-build.h>
33 #include <mono/utils/mono-logger-internals.h>
34 #include <mono/utils/mono-errno.h>
35 #include <mono/utils/mono-path.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-io-portability.h>
38 #include <mono/utils/atomic.h>
39 #include <mono/utils/mono-proclib.h>
40 #include <mono/metadata/class-internals.h>
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/object-internals.h>
43 #include <mono/metadata/security-core-clr.h>
44 #include <mono/metadata/verify-internals.h>
45 #include <mono/metadata/verify.h>
46 #include <mono/metadata/image-internals.h>
47 #include <mono/metadata/loaded-images-internals.h>
48 #include <mono/metadata/w32process-internals.h>
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54 #include <mono/metadata/w32error.h>
56 #define INVALID_ADDRESS 0xffffffff
58 // Amount initially reserved in each image's mempool.
59 // FIXME: This number is arbitrary, a more practical number should be found
60 #define INITIAL_IMAGE_SIZE 512
62 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
63 // Can be used on modules loaded through either the "file" or "module" mechanism
64 static gboolean
65 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
67 // Assembly to assign
68 MonoAssembly *assembly = assemblyImage->assembly;
70 while (1) {
71 // Assembly currently assigned
72 MonoAssembly *assemblyOld = image->assembly;
73 if (assemblyOld) {
74 if (assemblyOld == assembly)
75 return TRUE;
76 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);
77 return FALSE;
79 gpointer result = mono_atomic_xchg_ptr((gpointer *)&image->assembly, assembly);
80 if (result == assembly)
81 return TRUE;
85 static gboolean debug_assembly_unload = FALSE;
87 #define mono_images_storage_lock() do { if (mutex_inited) mono_os_mutex_lock (&images_storage_mutex); } while (0)
88 #define mono_images_storage_unlock() do { if (mutex_inited) mono_os_mutex_unlock (&images_storage_mutex); } while (0)
89 static gboolean mutex_inited;
90 static mono_mutex_t images_mutex;
91 static mono_mutex_t images_storage_mutex;
93 void
94 mono_images_lock (void)
96 if (mutex_inited)
97 mono_os_mutex_lock (&images_mutex);
100 void
101 mono_images_unlock(void)
103 if (mutex_inited)
104 mono_os_mutex_unlock (&images_mutex);
107 static MonoImage *
108 mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context, gboolean *problematic);
110 /* Maps string keys to MonoImageStorage values.
112 * The MonoImageStorage in the hash owns the key.
114 static GHashTable *images_storage_hash;
116 static void install_pe_loader (void);
118 typedef struct ImageUnloadHook ImageUnloadHook;
119 struct ImageUnloadHook {
120 MonoImageUnloadFunc func;
121 gpointer user_data;
124 static GSList *image_unload_hooks;
126 void
127 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
129 ImageUnloadHook *hook;
131 g_return_if_fail (func != NULL);
133 hook = g_new0 (ImageUnloadHook, 1);
134 hook->func = func;
135 hook->user_data = user_data;
136 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
139 void
140 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
142 GSList *l;
143 ImageUnloadHook *hook;
145 for (l = image_unload_hooks; l; l = l->next) {
146 hook = (ImageUnloadHook *)l->data;
148 if (hook->func == func && hook->user_data == user_data) {
149 g_free (hook);
150 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
151 break;
156 static void
157 mono_image_invoke_unload_hook (MonoImage *image)
159 GSList *l;
160 ImageUnloadHook *hook;
162 for (l = image_unload_hooks; l; l = l->next) {
163 hook = (ImageUnloadHook *)l->data;
165 hook->func (image, hook->user_data);
169 static GSList *image_loaders;
171 void
172 mono_install_image_loader (const MonoImageLoader *loader)
174 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
177 /* returns offset relative to image->raw_data */
178 guint32
179 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
181 MonoCLIImageInfo *iinfo = image->image_info;
182 const int top = iinfo->cli_section_count;
183 MonoSectionTable *tables = iinfo->cli_section_tables;
184 int i;
186 if (image->metadata_only)
187 return addr;
189 for (i = 0; i < top; i++){
190 if ((addr >= tables->st_virtual_address) &&
191 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
192 #ifdef HOST_WIN32
193 if (m_image_is_module_handle (image))
194 return addr;
195 #endif
196 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
198 tables++;
200 return INVALID_ADDRESS;
204 * mono_image_rva_map:
205 * \param image a \c MonoImage
206 * \param addr relative virtual address (RVA)
208 * This is a low-level routine used by the runtime to map relative
209 * virtual address (RVA) into their location in memory.
211 * \returns the address in memory for the given RVA, or NULL if the
212 * RVA is not valid for this image.
214 char *
215 mono_image_rva_map (MonoImage *image, guint32 addr)
217 MonoCLIImageInfo *iinfo = image->image_info;
218 const int top = iinfo->cli_section_count;
219 MonoSectionTable *tables = iinfo->cli_section_tables;
220 int i;
222 #ifdef HOST_WIN32
223 if (m_image_is_module_handle (image)) {
224 if (addr && addr < image->raw_data_len)
225 return image->raw_data + addr;
226 else
227 return NULL;
229 #endif
231 for (i = 0; i < top; i++){
232 if ((addr >= tables->st_virtual_address) &&
233 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
234 if (!iinfo->cli_sections [i]) {
235 if (!mono_image_ensure_section_idx (image, i))
236 return NULL;
238 return (char*)iinfo->cli_sections [i] +
239 (addr - tables->st_virtual_address);
241 tables++;
243 return NULL;
247 * mono_images_init:
249 * Initialize the global variables used by this module.
251 void
252 mono_images_init (void)
254 mono_os_mutex_init (&images_storage_mutex);
255 mono_os_mutex_init_recursive (&images_mutex);
257 images_storage_hash = g_hash_table_new (g_str_hash, g_str_equal);
259 #ifndef ENABLE_NETCORE
260 mono_loaded_images_init (mono_get_global_loaded_images (), NULL);
261 #endif
263 debug_assembly_unload = g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
265 install_pe_loader ();
267 mutex_inited = TRUE;
271 * mono_images_cleanup:
273 * Free all resources used by this module.
275 void
276 mono_images_cleanup (void)
278 mono_os_mutex_destroy (&images_mutex);
280 #ifndef ENABLE_NETCORE
281 mono_loaded_images_cleanup (mono_get_global_loaded_images (), TRUE);
282 #endif
284 g_hash_table_destroy (images_storage_hash);
286 mono_os_mutex_destroy (&images_storage_mutex);
288 mutex_inited = FALSE;
292 * mono_image_ensure_section_idx:
293 * \param image The image we are operating on
294 * \param 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 (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
299 * \returns TRUE on success
302 mono_image_ensure_section_idx (MonoImage *image, int section)
304 MonoCLIImageInfo *iinfo = 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)
310 return TRUE;
312 sect = &iinfo->cli_section_tables [section];
314 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
315 return FALSE;
316 #ifdef HOST_WIN32
317 if (m_image_is_module_handle (image))
318 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
319 else
320 #endif
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;
323 return TRUE;
327 * mono_image_ensure_section:
328 * \param image The image we are operating on
329 * \param 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 = image->image_info;
340 int i;
342 for (i = 0; i < ii->cli_section_count; i++){
343 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
344 continue;
346 return mono_image_ensure_section_idx (image, i);
348 return FALSE;
351 static int
352 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
354 const int top = iinfo->cli_header.coff.coff_sections;
355 int i;
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)
365 return FALSE;
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);
379 #endif
380 /* consistency checks here */
383 return TRUE;
386 gboolean
387 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
389 guint32 offset;
391 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
392 if (offset == INVALID_ADDRESS)
393 return FALSE;
395 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
396 return FALSE;
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);
423 #undef SWAP32
424 #undef SWAP16
425 #undef SWAPPDE
426 #endif
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"); */
447 return TRUE;
450 static gboolean
451 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
453 guint32 offset, size;
454 guint16 streams;
455 int i;
456 guint32 pad;
457 char *ptr;
459 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
460 if (offset == INVALID_ADDRESS)
461 return FALSE;
463 size = iinfo->cli_cli_header.ch_metadata.size;
465 if (offset + size > image->raw_data_len)
466 return FALSE;
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;
475 ptr += 4;
476 image->md_version_major = read16 (ptr);
477 ptr += 2;
478 image->md_version_minor = read16 (ptr);
479 ptr += 6;
481 version_string_len = read32 (ptr);
482 ptr += 4;
483 image->version = g_strndup (ptr, version_string_len);
484 ptr += version_string_len;
485 pad = ptr - image->raw_metadata;
486 if (pad % 4)
487 ptr += 4 - (pad % 4);
488 } else
489 return FALSE;
491 /* skip over flags */
492 ptr += 2;
494 streams = read16 (ptr);
495 ptr += 2;
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);
501 ptr += 8 + 3;
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);
505 ptr += 8 + 9;
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);
509 ptr += 8 + 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);
513 ptr += 8 + 6;
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);
517 ptr += 8 + 6;
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);
521 ptr += 8 + 3;
522 image->uncompressed_metadata = TRUE;
523 mono_trace (G_LOG_LEVEL_DEBUG, 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);
527 ptr += 8 + 5;
528 } else {
529 g_message ("Unknown heap type: %s\n", ptr + 8);
530 ptr += 8 + strlen (ptr + 8) + 1;
532 pad = ptr - image->raw_metadata;
533 if (pad % 4)
534 ptr += 4 - (pad % 4);
537 i = ((MonoImageLoader*)image->loader)->load_tables (image);
539 if (!image->metadata_only) {
540 g_assert (image->heap_guid.data);
541 g_assert (image->heap_guid.size >= 16);
543 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
544 } else {
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);
553 return i;
557 * Load representation of logical metadata tables, from the "#~" stream
559 static gboolean
560 load_tables (MonoImage *image)
562 const char *heap_tables = image->heap_tables.data;
563 const guint32 *rows;
564 guint64 valid_mask;
565 int valid = 0, table;
566 int heap_sizes;
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)
579 continue;
580 image->tables [table].rows = 0;
581 continue;
583 if (table > MONO_TABLE_LAST) {
584 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
585 } else {
586 image->tables [table].rows = read32 (rows);
588 rows++;
589 valid++;
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 */
602 int pos = 24;
603 image->referenced_tables = read64 (image->heap_pdb.data + pos);
604 pos += 8;
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);
609 pos += 4;
614 mono_metadata_compute_table_bases (image);
615 return TRUE;
618 gboolean
619 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
621 if (!load_metadata_ptrs (image, iinfo))
622 return FALSE;
624 return load_tables (image);
627 void
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)) {
634 /* FIXME: */
635 image->checked_module_cctor = TRUE;
636 return;
638 if (t->rows >= 1) {
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;
643 guint32 last_method;
644 if (t->rows > 1)
645 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
646 else
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;
654 return;
659 image->has_module_cctor = FALSE;
660 image->checked_module_cctor = TRUE;
663 #ifndef ENABLE_NETCORE
664 static void
665 load_modules (MonoImage *image)
667 MonoTableInfo *t;
669 if (image->modules)
670 return;
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;
677 #endif
680 * mono_image_load_module_checked:
682 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
683 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
685 MonoImage*
686 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
688 error_init (error);
690 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
691 return NULL;
692 if (image->modules_loaded [idx - 1])
693 return image->modules [idx - 1];
695 #ifdef ENABLE_NETCORE
696 /* SRE still uses image->modules, but they are not loaded from files, so the rest of this function is dead code for netcore */
697 g_assert_not_reached ();
698 #else
699 MonoTableInfo *t;
700 MonoTableInfo *file_table;
701 int i;
702 char *base_dir;
703 gboolean refonly = image->ref_only;
704 GList *list_iter, *valid_modules = NULL;
705 MonoImageOpenStatus status;
707 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Loading module %d of %s (%s)", idx, image->assembly ? image->assembly->aname.name : "some assembly", image->name);
709 file_table = &image->tables [MONO_TABLE_FILE];
710 for (i = 0; i < file_table->rows; i++) {
711 guint32 cols [MONO_FILE_SIZE];
712 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
713 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
714 continue;
715 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
718 t = &image->tables [MONO_TABLE_MODULEREF];
719 base_dir = g_path_get_dirname (image->name);
722 char *module_ref;
723 const char *name;
724 guint32 cols [MONO_MODULEREF_SIZE];
725 /* if there is no file table, we try to load the module... */
726 int valid = file_table->rows == 0;
728 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
729 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
730 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
731 /* be safe with string dups, but we could just compare string indexes */
732 if (strcmp ((const char*)list_iter->data, name) == 0) {
733 valid = TRUE;
734 break;
737 if (valid) {
738 MonoAssemblyLoadContext *alc = mono_image_get_alc (image);
739 MonoLoadedImages *li = mono_image_get_loaded_images_for_modules (image);
740 module_ref = g_build_filename (base_dir, name, (const char*)NULL);
741 MonoImage *moduleImage = mono_image_open_a_lot_parameterized (li, alc, module_ref, &status, refonly, FALSE, NULL);
742 if (moduleImage) {
743 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
744 mono_image_close (moduleImage);
745 g_free (module_ref);
746 g_free (base_dir);
747 g_list_free (valid_modules);
748 return NULL;
751 image->modules [idx - 1] = moduleImage;
753 #ifdef HOST_WIN32
754 if (m_image_is_module_handle (image->modules [idx - 1]))
755 mono_image_fixup_vtable (image->modules [idx - 1]);
756 #endif
757 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
759 g_free (module_ref);
763 image->modules_loaded [idx - 1] = TRUE;
765 g_free (base_dir);
766 g_list_free (valid_modules);
768 return image->modules [idx - 1];
769 #endif
773 * mono_image_load_module:
775 MonoImage*
776 mono_image_load_module (MonoImage *image, int idx)
778 ERROR_DECL (error);
779 MonoImage *result = mono_image_load_module_checked (image, idx, error);
780 mono_error_assert_ok (error);
781 return result;
784 static gpointer
785 class_key_extract (gpointer value)
787 MonoClass *klass = (MonoClass *)value;
789 return GUINT_TO_POINTER (m_class_get_type_token (klass));
792 static gpointer*
793 class_next_value (gpointer value)
795 MonoClassDef *klass = (MonoClassDef *)value;
797 return (gpointer*)m_classdef_get_next_class_cache (klass);
801 * mono_image_init:
803 void
804 mono_image_init (MonoImage *image)
806 mono_os_mutex_init_recursive (&image->lock);
807 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
809 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
810 mono_internal_hash_table_init (&image->class_cache,
811 g_direct_hash,
812 class_key_extract,
813 class_next_value);
814 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
816 image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
817 image->memberref_signatures = g_hash_table_new (NULL, NULL);
818 image->method_signatures = g_hash_table_new (NULL, NULL);
820 image->property_hash = mono_property_hash_new ();
823 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
824 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
825 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
826 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
827 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
828 #else
829 #define SWAP64(x)
830 #define SWAP32(x)
831 #define SWAP16(x)
832 #define SWAPPDE(x)
833 #endif
836 * Returns < 0 to indicate an error.
838 static int
839 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
841 MonoDotNetHeader64 header64;
843 #ifdef HOST_WIN32
844 if (!m_image_is_module_handle (image))
845 #endif
846 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
847 return -1;
849 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
851 if (header->pesig [0] != 'P' || header->pesig [1] != 'E' || header->pesig [2] || header->pesig [3])
852 return -1;
854 /* endian swap the fields common between PE and PE+ */
855 SWAP32 (header->coff.coff_time);
856 SWAP32 (header->coff.coff_symptr);
857 SWAP32 (header->coff.coff_symcount);
858 SWAP16 (header->coff.coff_machine);
859 SWAP16 (header->coff.coff_sections);
860 SWAP16 (header->coff.coff_opt_header_size);
861 SWAP16 (header->coff.coff_attributes);
862 /* MonoPEHeader */
863 SWAP32 (header->pe.pe_code_size);
864 SWAP32 (header->pe.pe_uninit_data_size);
865 SWAP32 (header->pe.pe_rva_entry_point);
866 SWAP32 (header->pe.pe_rva_code_base);
867 SWAP32 (header->pe.pe_rva_data_base);
868 SWAP16 (header->pe.pe_magic);
870 /* now we are ready for the basic tests */
872 if (header->pe.pe_magic == 0x10B) {
873 offset += sizeof (MonoDotNetHeader);
874 SWAP32 (header->pe.pe_data_size);
875 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
876 return -1;
878 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
879 SWAP32 (header->nt.pe_stack_reserve);
880 SWAP32 (header->nt.pe_stack_commit);
881 SWAP32 (header->nt.pe_heap_reserve);
882 SWAP32 (header->nt.pe_heap_commit);
883 } else if (header->pe.pe_magic == 0x20B) {
884 /* PE32+ file format */
885 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
886 return -1;
887 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
888 offset += sizeof (MonoDotNetHeader64);
889 /* copy the fields already swapped. the last field, pe_data_size, is missing */
890 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
891 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
892 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
894 SWAP64 (header64.nt.pe_image_base);
895 header->nt.pe_image_base = header64.nt.pe_image_base;
896 SWAP64 (header64.nt.pe_stack_reserve);
897 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
898 SWAP64 (header64.nt.pe_stack_commit);
899 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
900 SWAP64 (header64.nt.pe_heap_reserve);
901 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
902 SWAP64 (header64.nt.pe_heap_commit);
903 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
905 header->nt.pe_section_align = header64.nt.pe_section_align;
906 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
907 header->nt.pe_os_major = header64.nt.pe_os_major;
908 header->nt.pe_os_minor = header64.nt.pe_os_minor;
909 header->nt.pe_user_major = header64.nt.pe_user_major;
910 header->nt.pe_user_minor = header64.nt.pe_user_minor;
911 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
912 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
913 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
914 header->nt.pe_image_size = header64.nt.pe_image_size;
915 header->nt.pe_header_size = header64.nt.pe_header_size;
916 header->nt.pe_checksum = header64.nt.pe_checksum;
917 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
918 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
919 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
920 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
922 /* copy the datadir */
923 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
924 } else {
925 return -1;
928 /* MonoPEHeaderNT: not used yet */
929 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
930 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
931 SWAP16 (header->nt.pe_os_major); /* must be 4 */
932 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
933 SWAP16 (header->nt.pe_user_major);
934 SWAP16 (header->nt.pe_user_minor);
935 SWAP16 (header->nt.pe_subsys_major);
936 SWAP16 (header->nt.pe_subsys_minor);
937 SWAP32 (header->nt.pe_reserved_1);
938 SWAP32 (header->nt.pe_image_size);
939 SWAP32 (header->nt.pe_header_size);
940 SWAP32 (header->nt.pe_checksum);
941 SWAP16 (header->nt.pe_subsys_required);
942 SWAP16 (header->nt.pe_dll_flags);
943 SWAP32 (header->nt.pe_loader_flags);
944 SWAP32 (header->nt.pe_data_dir_count);
946 /* MonoDotNetHeader: mostly unused */
947 SWAPPDE (header->datadir.pe_export_table);
948 SWAPPDE (header->datadir.pe_import_table);
949 SWAPPDE (header->datadir.pe_resource_table);
950 SWAPPDE (header->datadir.pe_exception_table);
951 SWAPPDE (header->datadir.pe_certificate_table);
952 SWAPPDE (header->datadir.pe_reloc_table);
953 SWAPPDE (header->datadir.pe_debug);
954 SWAPPDE (header->datadir.pe_copyright);
955 SWAPPDE (header->datadir.pe_global_ptr);
956 SWAPPDE (header->datadir.pe_tls_table);
957 SWAPPDE (header->datadir.pe_load_config_table);
958 SWAPPDE (header->datadir.pe_bound_import);
959 SWAPPDE (header->datadir.pe_iat);
960 SWAPPDE (header->datadir.pe_delay_import_desc);
961 SWAPPDE (header->datadir.pe_cli_header);
962 SWAPPDE (header->datadir.pe_reserved);
964 #ifdef HOST_WIN32
965 if (m_image_is_module_handle (image))
966 image->storage->raw_data_len = header->nt.pe_image_size;
967 #endif
969 return offset;
972 gboolean
973 mono_image_load_pe_data (MonoImage *image)
975 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
978 static gboolean
979 pe_image_load_pe_data (MonoImage *image)
981 MonoCLIImageInfo *iinfo;
982 MonoDotNetHeader *header;
983 MonoMSDOSHeader msdos;
984 gint32 offset = 0;
986 iinfo = image->image_info;
987 header = &iinfo->cli_header;
989 #ifdef HOST_WIN32
990 if (!m_image_is_module_handle (image))
991 #endif
992 if (offset + sizeof (msdos) > image->raw_data_len)
993 goto invalid_image;
994 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
996 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
997 goto invalid_image;
999 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
1001 offset = msdos.pe_offset;
1003 offset = do_load_header (image, header, offset);
1004 if (offset < 0)
1005 goto invalid_image;
1008 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1009 * we skip this test.
1010 if (header->coff.coff_machine != 0x14c)
1011 goto invalid_image;
1014 #if 0
1016 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1017 * which produces binaries with 7.0. From Sergey:
1019 * The reason is that MSVC7 uses traditional compile/link
1020 * sequence for CIL executables, and VS.NET (and Framework
1021 * SDK) includes linker version 7, that puts 7.0 in this
1022 * field. That's why it's currently not possible to load VC
1023 * binaries with Mono. This field is pretty much meaningless
1024 * anyway (what linker?).
1026 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1027 goto invalid_image;
1028 #endif
1031 * FIXME: byte swap all addresses here for header.
1034 if (!load_section_tables (image, iinfo, offset))
1035 goto invalid_image;
1037 return TRUE;
1039 invalid_image:
1040 return FALSE;
1043 gboolean
1044 mono_image_load_cli_data (MonoImage *image)
1046 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1049 static gboolean
1050 pe_image_load_cli_data (MonoImage *image)
1052 MonoCLIImageInfo *iinfo;
1054 iinfo = image->image_info;
1056 /* Load the CLI header */
1057 if (!mono_image_load_cli_header (image, iinfo))
1058 return FALSE;
1060 if (!mono_image_load_metadata (image, iinfo))
1061 return FALSE;
1063 return TRUE;
1066 static void
1067 mono_image_load_time_date_stamp (MonoImage *image)
1069 image->time_date_stamp = 0;
1070 #ifndef HOST_WIN32
1071 if (!image->filename)
1072 return;
1074 gunichar2 *uni_name = g_utf8_to_utf16 (image->filename, -1, NULL, NULL, NULL);
1075 mono_pe_file_time_date_stamp (uni_name, &image->time_date_stamp);
1076 g_free (uni_name);
1077 #endif
1080 void
1081 mono_image_load_names (MonoImage *image)
1083 /* modules don't have an assembly table row */
1084 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1085 image->assembly_name = mono_metadata_string_heap (image,
1086 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1087 0, MONO_ASSEMBLY_NAME));
1090 /* Portable pdb images don't have a MODULE row */
1091 if (image->tables [MONO_TABLE_MODULE].rows) {
1092 image->module_name = mono_metadata_string_heap (image,
1093 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1094 0, MONO_MODULE_NAME));
1098 static gboolean
1099 pe_image_load_tables (MonoImage *image)
1101 return TRUE;
1104 static gboolean
1105 pe_image_match (MonoImage *image)
1107 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1108 return TRUE;
1109 return FALSE;
1112 static const MonoImageLoader pe_loader = {
1113 pe_image_match,
1114 pe_image_load_pe_data,
1115 pe_image_load_cli_data,
1116 pe_image_load_tables,
1119 static void
1120 install_pe_loader (void)
1122 mono_install_image_loader (&pe_loader);
1126 Ignored assemblies.
1128 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1129 Mono provides its own implementation of those assemblies so it's safe to do so.
1131 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1133 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1135 This is to be removed once a proper fix is shipped through nuget.
1137 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1138 If any assemblies are added/removed, then this should be regenerated with:
1140 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1144 typedef enum {
1145 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1146 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1147 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1148 SYS_NET_HTTP = 3, //System.Net.Http
1149 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1150 SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1151 } IgnoredAssemblyNames;
1153 typedef struct {
1154 int hash;
1155 int assembly_name;
1156 char guid [40];
1157 } IgnoredAssembly;
1159 typedef struct {
1160 int assembly_name;
1161 guint16 major, minor, build, revision;
1162 } IgnoredAssemblyVersion;
1164 static const char *ignored_assemblies_file_names[] = {
1165 "System.Runtime.InteropServices.RuntimeInformation.dll",
1166 "System.Globalization.Extensions.dll",
1167 "System.IO.Compression.dll",
1168 "System.Net.Http.dll",
1169 "System.Text.Encoding.CodePages.dll",
1170 "System.Threading.Overlapped.dll"
1173 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { (int)HASH, NAME, GUID }
1175 static const IgnoredAssembly ignored_assemblies [] = {
1176 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1177 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1178 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1179 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1180 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1181 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1182 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1183 IGNORED_ASSEMBLY (0x1FB3F8E8, SYS_GLOBALIZATION_EXT, "B9BA8638-25D2-4A3B-B91F-16B3D3799861", "2.1.100-preview-62617-01 net461"),
1184 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1185 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1186 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1187 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1188 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1189 IGNORED_ASSEMBLY (0x3E21E75A, SYS_TEXT_ENC_CODEPAGES, "67D3A14A-8F55-4C9F-9699-EDD0876369DA", "4.5.0 net461"),
1190 IGNORED_ASSEMBLY (0x420963C4, SYS_NET_HTTP, "084B071E-1637-4B3F-B7CD-6CEF28A6E4AE", "4.3.4 net46"),
1191 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1192 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1193 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1194 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1195 IGNORED_ASSEMBLY (0x4E906129, SYS_NET_HTTP, "27BBDD4C-EAF0-4A95-B172-EE502D76A725", "2.1.100-preview-62617-01 net461"),
1196 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1197 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1198 IGNORED_ASSEMBLY (0x66CEDA9, SYS_THREADING_OVERLAPPED, "A0439CB6-A5E6-4813-A76C-13F92ADDDED5", "2.1.100-preview-62617-01 net461"),
1199 IGNORED_ASSEMBLY (0x6AE7C015, SYS_IO_COMPRESSION, "35DD20B5-8766-476B-B5D2-0EA16EF0A946", "2.1.100-preview-62617-01 net461"),
1200 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46"),
1201 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1202 IGNORED_ASSEMBLY (0x765A8E04, SYS_RT_INTEROP_RUNTIME_INFO, "E46BA45E-6A63-47CD-AF70-2C3016AFF75A", "2.1.100-preview-62617-01 net461"),
1203 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1204 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1205 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1206 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1207 IGNORED_ASSEMBLY (0x8BFCB05D, SYS_THREADING_OVERLAPPED, "82D565AC-E41C-4E29-9939-C031C88EDBDD", "2.1.100-preview-62617-01 net471"),
1208 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1209 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1210 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1211 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1212 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1213 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1214 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1215 IGNORED_ASSEMBLY (0xA99E866F, SYS_NET_HTTP, "41ACE450-8F44-455A-97AC-0679E5462071", "2.1.100-preview-62617-01 net471"),
1216 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1217 IGNORED_ASSEMBLY (0xAF2093B8, SYS_TEXT_ENC_CODEPAGES, "D2B4F262-31A4-4E80-9CFB-26A2249A735E", "4.5.1 net461"),
1218 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1219 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1220 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1221 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1222 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1223 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1224 IGNORED_ASSEMBLY (0xD3ABE53A, SYS_RT_INTEROP_RUNTIME_INFO, "488CE209-4E5D-40E7-BE8C-F81F2B99F13A", "2.1.100-preview-62617-01 net462"),
1225 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1226 IGNORED_ASSEMBLY (0xE16ECCCD, SYS_GLOBALIZATION_EXT, "1A2B9B2A-02F5-4C78-AB0C-7C6D2795CE2B", "2.1.100-preview-62617-01 net471"),
1227 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1228 IGNORED_ASSEMBLY (0xE758DAD4, SYS_IO_COMPRESSION, "8DBD1669-97BC-4190-9BD8-738561193741", "2.1.100-preview-62617-01 net471"),
1229 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1230 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1231 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1232 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1233 IGNORED_ASSEMBLY (0xFC67D3A7, SYS_RT_INTEROP_RUNTIME_INFO, "FD6C8616-C1D8-43F9-AC17-A1C48A45FDA2", "2.1.100-preview-62617-01 net47")
1237 static const char *ignored_assemblies_names[] = {
1238 "System.Runtime.InteropServices.RuntimeInformation",
1239 "System.Globalization.Extensions",
1240 "System.IO.Compression",
1241 "System.Net.Http",
1242 "System.Text.Encoding.CodePages",
1243 "System.Threading.Overlapped"
1246 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { NAME, MAJOR, MINOR, BUILD, REVISION }
1248 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1249 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1250 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1251 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1252 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 1, 0, 0),
1253 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1254 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1255 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 2, 0, 0),
1256 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1257 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1258 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1259 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1260 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 2),
1261 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 3),
1262 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 2, 0, 0),
1263 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1264 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1265 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 2, 0),
1266 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1267 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1268 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1269 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 1, 0),
1270 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1271 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1272 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1273 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 1, 0, 0)
1276 gboolean
1277 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1279 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1280 if (ignored_assembly_versions [i].major != major ||
1281 ignored_assembly_versions [i].minor != minor ||
1282 ignored_assembly_versions [i].build != build ||
1283 ignored_assembly_versions [i].revision != revision)
1284 continue;
1285 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1286 return TRUE;
1288 return FALSE;
1292 Equivalent C# code:
1293 static void Main () {
1294 string str = "...";
1295 int h = 5381;
1296 for (int i = 0; i < str.Length; ++i)
1297 h = ((h << 5) + h) ^ str[i];
1299 Console.WriteLine ("{0:X}", h);
1302 static int
1303 hash_guid (const char *str)
1305 int h = 5381;
1306 while (*str) {
1307 h = ((h << 5) + h) ^ *str;
1308 ++str;
1311 return h;
1314 gboolean
1315 mono_is_problematic_image (MonoImage *image)
1317 int h = hash_guid (image->guid);
1319 //TODO make this more cache effiecient.
1320 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1321 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1322 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1323 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1324 size_t needle_len = strlen (needle);
1325 size_t asm_len = strlen (image->name);
1326 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1327 return TRUE;
1330 return FALSE;
1333 static MonoImage *
1334 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1335 gboolean care_about_cli, gboolean care_about_pecoff)
1337 ERROR_DECL (error);
1338 GSList *l;
1340 MONO_PROFILER_RAISE (image_loading, (image));
1342 mono_image_init (image);
1344 if (!image->metadata_only) {
1345 for (l = image_loaders; l; l = l->next) {
1346 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1347 if (loader->match (image)) {
1348 image->loader = loader;
1349 break;
1352 if (!image->loader) {
1353 if (status)
1354 *status = MONO_IMAGE_IMAGE_INVALID;
1355 goto invalid_image;
1358 if (status)
1359 *status = MONO_IMAGE_IMAGE_INVALID;
1361 if (care_about_pecoff == FALSE)
1362 goto done;
1364 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, error))
1365 goto invalid_image;
1367 if (!mono_image_load_pe_data (image))
1368 goto invalid_image;
1369 } else {
1370 image->loader = (MonoImageLoader*)&pe_loader;
1373 if (care_about_cli == FALSE) {
1374 goto done;
1377 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, error))
1378 goto invalid_image;
1380 if (!mono_image_load_cli_data (image))
1381 goto invalid_image;
1383 if (!image->ref_only && mono_is_problematic_image (image)) {
1384 if (image->load_from_context) {
1385 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1386 } else {
1387 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1388 if (status)
1389 *status = MONO_IMAGE_IMAGE_INVALID;
1390 goto invalid_image;
1394 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, error))
1395 goto invalid_image;
1397 mono_image_load_names (image);
1399 mono_image_load_time_date_stamp (image);
1401 #ifndef ENABLE_NETCORE
1402 load_modules (image);
1403 #endif
1405 done:
1406 MONO_PROFILER_RAISE (image_loaded, (image));
1407 if (status)
1408 *status = MONO_IMAGE_OK;
1410 return image;
1412 invalid_image:
1413 if (!is_ok (error)) {
1414 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Could not load image %s due to %s", image->name, mono_error_get_message (error));
1415 mono_error_cleanup (error);
1417 MONO_PROFILER_RAISE (image_failed, (image));
1418 mono_image_close (image);
1419 return NULL;
1422 static gboolean
1423 mono_image_storage_trypublish (MonoImageStorage *candidate, MonoImageStorage **out_storage)
1425 gboolean result;
1426 mono_images_storage_lock ();
1427 MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, candidate->key);
1428 if (val) {
1429 mono_refcount_inc (val);
1430 *out_storage = val;
1431 result = FALSE;
1432 } else {
1433 g_hash_table_insert (images_storage_hash, candidate->key, candidate);
1434 result = TRUE;
1436 mono_images_storage_unlock ();
1437 return result;
1440 static void
1441 mono_image_storage_unpublish (MonoImageStorage *storage)
1443 mono_images_storage_lock ();
1444 g_assert (storage->ref.ref == 0);
1446 MonoImageStorage *published = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, storage->key);
1447 if (published == storage) {
1448 g_hash_table_remove (images_storage_hash, storage->key);
1451 mono_images_storage_unlock ();
1454 static gboolean
1455 mono_image_storage_tryaddref (const char *key, MonoImageStorage **found)
1457 gboolean result = FALSE;
1458 mono_images_storage_lock ();
1459 MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, key);
1460 if (val) {
1461 mono_refcount_inc (val);
1462 *found = val;
1463 result = TRUE;
1465 mono_images_storage_unlock ();
1466 return result;
1469 static void
1470 mono_image_storage_dtor (gpointer self)
1472 MonoImageStorage *storage = (MonoImageStorage *)self;
1474 mono_image_storage_unpublish (storage);
1476 #ifdef HOST_WIN32
1477 if (storage->is_module_handle && !storage->has_entry_point) {
1478 mono_images_lock ();
1479 FreeLibrary ((HMODULE) storage->raw_data);
1480 mono_images_unlock ();
1482 #endif
1484 if (storage->raw_buffer_used) {
1485 if (storage->raw_data != NULL) {
1486 #ifndef HOST_WIN32
1487 if (storage->fileio_used)
1488 mono_file_unmap_fileio (storage->raw_data, storage->raw_data_handle);
1489 else
1490 #endif
1491 mono_file_unmap (storage->raw_data, storage->raw_data_handle);
1494 if (storage->raw_data_allocated) {
1495 g_free (storage->raw_data);
1498 g_free (storage->key);
1500 g_free (storage);
1503 static void
1504 mono_image_storage_close (MonoImageStorage *storage)
1506 mono_refcount_dec (storage);
1509 static gboolean
1510 mono_image_init_raw_data (MonoImage *image, const MonoImageStorage *storage)
1512 if (!storage)
1513 return FALSE;
1514 image->raw_data = storage->raw_data;
1515 image->raw_data_len = storage->raw_data_len;
1516 return TRUE;
1519 static MonoImageStorage *
1520 mono_image_storage_open (const char *fname)
1522 char *key = NULL;
1524 key = mono_path_resolve_symlinks (fname);
1525 MonoImageStorage *published_storage = NULL;
1526 if (mono_image_storage_tryaddref (key, &published_storage)) {
1527 g_free (key);
1528 return published_storage;
1531 MonoFileMap *filed;
1532 if ((filed = mono_file_map_open (fname)) == NULL){
1533 if (IS_PORTABILITY_SET) {
1534 gchar *ffname = mono_portability_find_file (fname, TRUE);
1535 if (ffname) {
1536 filed = mono_file_map_open (ffname);
1537 g_free (ffname);
1541 if (filed == NULL) {
1542 g_free (key);
1543 return NULL;
1547 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1548 mono_refcount_init (storage, mono_image_storage_dtor);
1549 storage->raw_buffer_used = TRUE;
1550 storage->raw_data_len = mono_file_map_size (filed);
1551 storage->raw_data = (char*)mono_file_map (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
1552 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1553 if (!storage->raw_data) {
1554 storage->fileio_used = TRUE;
1555 storage->raw_data = (char *)mono_file_map_fileio (storage->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &storage->raw_data_handle);
1557 #endif
1558 mono_file_map_close (filed);
1560 storage->key = key;
1562 MonoImageStorage *other_storage = NULL;
1563 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1564 mono_image_storage_close (storage);
1565 storage = other_storage;
1567 return storage;
1570 static MonoImageStorage *
1571 mono_image_storage_new_raw_data (char *datac, guint32 data_len, gboolean raw_data_allocated, const char *name)
1573 char *key = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup (name);
1574 MonoImageStorage *published_storage = NULL;
1575 if (mono_image_storage_tryaddref (key, &published_storage)) {
1576 g_free (key);
1577 return published_storage;
1580 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1581 mono_refcount_init (storage, mono_image_storage_dtor);
1583 storage->raw_data = datac;
1584 storage->raw_data_len = data_len;
1585 storage->raw_data_allocated = raw_data_allocated;
1587 storage->key = key;
1588 MonoImageStorage *other_storage = NULL;
1589 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1590 mono_image_storage_close (storage);
1591 storage = other_storage;
1593 return storage;
1596 static MonoImage *
1597 do_mono_image_open (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status,
1598 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1600 MonoCLIImageInfo *iinfo;
1601 MonoImage *image;
1603 MonoImageStorage *storage = mono_image_storage_open (fname);
1605 if (!storage) {
1606 if (status)
1607 *status = MONO_IMAGE_ERROR_ERRNO;
1608 return NULL;
1611 image = g_new0 (MonoImage, 1);
1612 image->storage = storage;
1613 mono_image_init_raw_data (image, storage);
1614 if (!image->raw_data) {
1615 mono_image_storage_close (image->storage);
1616 g_free (image);
1617 if (status)
1618 *status = MONO_IMAGE_IMAGE_INVALID;
1619 return NULL;
1621 iinfo = g_new0 (MonoCLIImageInfo, 1);
1622 image->image_info = iinfo;
1623 image->name = mono_path_resolve_symlinks (fname);
1624 image->filename = g_strdup (image->name);
1625 image->ref_only = refonly;
1626 image->metadata_only = metadata_only;
1627 image->load_from_context = load_from_context;
1628 image->ref_count = 1;
1629 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1630 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1631 #ifdef ENABLE_NETCORE
1632 image->alc = alc;
1633 #endif
1634 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1638 * mono_image_loaded_full:
1639 * \param name path or assembly name of the image to load
1640 * \param refonly Check with respect to reflection-only loads?
1642 * This routine verifies that the given image is loaded.
1643 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1645 * \returns the loaded \c MonoImage, or NULL on failure.
1647 MonoImage *
1648 mono_image_loaded_full (const char *name, gboolean refonly)
1650 MonoImage *result;
1651 MONO_ENTER_GC_UNSAFE;
1652 MonoDomain *domain = mono_domain_get ();
1653 result = mono_image_loaded_internal (mono_domain_default_alc (domain), name, refonly);
1654 MONO_EXIT_GC_UNSAFE;
1655 return result;
1659 * mono_image_loaded_internal:
1660 * \param alc The AssemblyLoadContext that should be checked
1661 * \param name path or assembly name of the image to load
1662 * \param refonly Check with respect to reflection-only loads?
1664 * This routine verifies that the given image is loaded.
1665 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1667 * \returns the loaded \c MonoImage, or NULL on failure.
1669 MonoImage *
1670 mono_image_loaded_internal (MonoAssemblyLoadContext *alc, const char *name, gboolean refonly)
1672 MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
1673 MonoImage *res;
1675 mono_images_lock ();
1676 res = (MonoImage *)g_hash_table_lookup (mono_loaded_images_get_hash (li, refonly), name);
1677 if (!res)
1678 res = (MonoImage *)g_hash_table_lookup (mono_loaded_images_get_by_name_hash (li, refonly), name);
1679 mono_images_unlock ();
1681 return res;
1685 * mono_image_loaded:
1686 * \param name path or assembly name of the image to load
1687 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1688 * \returns the loaded \c MonoImage, or NULL on failure.
1690 MonoImage *
1691 mono_image_loaded (const char *name)
1693 MonoImage *result;
1694 MONO_ENTER_GC_UNSAFE;
1695 MonoDomain *domain = mono_domain_get ();
1696 result = mono_image_loaded_internal (mono_domain_default_alc (domain), name, FALSE);
1697 MONO_EXIT_GC_UNSAFE;
1698 return result;
1701 typedef struct {
1702 MonoImage *res;
1703 const char* guid;
1704 } GuidData;
1706 static void
1707 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1709 GuidData *data = (GuidData *)user_data;
1710 MonoImage *image;
1712 if (data->res)
1713 return;
1714 image = (MonoImage *)val;
1715 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1716 data->res = image;
1719 static MonoImage *
1720 mono_image_loaded_by_guid_internal (const char *guid, gboolean refonly);
1723 * mono_image_loaded_by_guid_full:
1725 * Looks only in the global loaded images hash, will miss assemblies loaded
1726 * into an AssemblyLoadContext.
1728 MonoImage *
1729 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1731 return mono_image_loaded_by_guid_internal (guid, refonly);
1735 * mono_image_loaded_by_guid_internal:
1737 * Do not use. Looks only in the global loaded images hash, will miss Assembly
1738 * Load Contexts.
1740 static MonoImage *
1741 mono_image_loaded_by_guid_internal (const char *guid, gboolean refonly)
1743 #ifndef ENABLE_NETCORE
1744 GuidData data;
1745 GHashTable *loaded_images = mono_loaded_images_get_hash (mono_get_global_loaded_images (), refonly);
1746 data.res = NULL;
1747 data.guid = guid;
1749 mono_images_lock ();
1750 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1751 mono_images_unlock ();
1752 return data.res;
1753 #else
1754 /* TODO: Maybe implement this for netcore by searching only the default ALC of the current domain */
1755 return NULL;
1756 #endif
1760 * mono_image_loaded_by_guid:
1762 * Looks only in the global loaded images hash, will miss assemblies loaded
1763 * into an AssemblyLoadContext.
1765 MonoImage *
1766 mono_image_loaded_by_guid (const char *guid)
1768 return mono_image_loaded_by_guid_internal (guid, FALSE);
1771 static MonoImage *
1772 register_image (MonoLoadedImages *li, MonoImage *image, gboolean *problematic)
1774 MonoImage *image2;
1775 GHashTable *loaded_images = mono_loaded_images_get_hash (li, image->ref_only);
1777 mono_images_lock ();
1778 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1780 if (image2) {
1781 /* Somebody else beat us to it */
1782 mono_image_addref (image2);
1783 mono_images_unlock ();
1784 mono_image_close (image);
1785 return image2;
1788 GHashTable *loaded_images_by_name = mono_loaded_images_get_by_name_hash (li, image->ref_only);
1789 g_hash_table_insert (loaded_images, image->name, image);
1790 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1791 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1792 mono_images_unlock ();
1794 if (mono_is_problematic_image (image)) {
1795 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Registering %s, problematic image '%s'", image->ref_only ? "REFONLY" : "default", image->name);
1796 if (problematic)
1797 *problematic = TRUE;
1799 return image;
1802 MonoImage *
1803 mono_image_open_from_data_internal (MonoAssemblyLoadContext *alc, char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1805 MonoCLIImageInfo *iinfo;
1806 MonoImage *image;
1807 char *datac;
1809 if (!data || !data_len) {
1810 if (status)
1811 *status = MONO_IMAGE_IMAGE_INVALID;
1812 return NULL;
1814 datac = data;
1815 if (need_copy) {
1816 datac = (char *)g_try_malloc (data_len);
1817 if (!datac) {
1818 if (status)
1819 *status = MONO_IMAGE_ERROR_ERRNO;
1820 return NULL;
1822 memcpy (datac, data, data_len);
1825 MonoImageStorage *storage = mono_image_storage_new_raw_data (datac, data_len, need_copy, name);
1826 image = g_new0 (MonoImage, 1);
1827 image->storage = storage;
1828 mono_image_init_raw_data (image, storage);
1829 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1830 image->filename = name ? g_strdup (name) : NULL;
1831 iinfo = g_new0 (MonoCLIImageInfo, 1);
1832 image->image_info = iinfo;
1833 image->ref_only = refonly;
1834 image->metadata_only = metadata_only;
1835 image->ref_count = 1;
1836 #ifdef ENABLE_NETCORE
1837 image->alc = alc;
1838 #endif
1840 image = do_mono_image_load (image, status, TRUE, TRUE);
1841 if (image == NULL)
1842 return NULL;
1844 return register_image (mono_alc_get_loaded_images (alc), image, NULL);
1848 * mono_image_open_from_data_with_name:
1850 MonoImage *
1851 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1853 MonoImage *result;
1854 MONO_ENTER_GC_UNSAFE;
1855 MonoDomain *domain = mono_domain_get ();
1856 result = mono_image_open_from_data_internal (mono_domain_default_alc (domain), data, data_len, need_copy, status, refonly, FALSE, name);
1857 MONO_EXIT_GC_UNSAFE;
1858 return result;
1862 * mono_image_open_from_data_full:
1864 MonoImage *
1865 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1867 MonoImage *result;
1868 MONO_ENTER_GC_UNSAFE;
1869 MonoDomain *domain = mono_domain_get ();
1870 result = mono_image_open_from_data_internal (mono_domain_default_alc (domain), data, data_len, need_copy, status, refonly, FALSE, NULL);
1871 MONO_EXIT_GC_UNSAFE;
1872 return result;
1876 * mono_image_open_from_data:
1878 MonoImage *
1879 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1881 MonoImage *result;
1882 MONO_ENTER_GC_UNSAFE;
1883 MonoDomain *domain = mono_domain_get ();
1884 result = mono_image_open_from_data_internal (mono_domain_default_alc (domain), data, data_len, need_copy, status, FALSE, FALSE, NULL);
1885 MONO_EXIT_GC_UNSAFE;
1886 return result;
1889 #ifdef HOST_WIN32
1890 static MonoImageStorage *
1891 mono_image_storage_open_from_module_handle (HMODULE module_handle, const char *fname, gboolean has_entry_point)
1893 char *key = g_strdup (fname);
1894 MonoImageStorage *published_storage = NULL;
1895 if (mono_image_storage_tryaddref (key, &published_storage)) {
1896 g_free (key);
1897 return published_storage;
1900 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1901 mono_refcount_init (storage, mono_image_storage_dtor);
1902 storage->raw_data = (char*) module_handle;
1903 storage->is_module_handle = TRUE;
1904 storage->has_entry_point = has_entry_point;
1906 storage->key = key;
1908 MonoImageStorage *other_storage = NULL;
1909 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1910 mono_image_storage_close (storage);
1911 storage = other_storage;
1913 return storage;
1916 /* fname is not duplicated. */
1917 MonoImage*
1918 mono_image_open_from_module_handle (MonoAssemblyLoadContext *alc, HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1920 MonoImage* image;
1921 MonoCLIImageInfo* iinfo;
1923 MonoImageStorage *storage = mono_image_storage_open_from_module_handle (module_handle, fname, has_entry_point);
1924 image = g_new0 (MonoImage, 1);
1925 image->storage = storage;
1926 mono_image_init_raw_data (image, storage);
1927 iinfo = g_new0 (MonoCLIImageInfo, 1);
1928 image->image_info = iinfo;
1929 image->name = fname;
1930 image->filename = g_strdup (image->name);
1931 image->ref_count = has_entry_point ? 0 : 1;
1932 #ifdef ENABLE_NETCORE
1933 image->alc = alc;
1934 #endif
1936 image = do_mono_image_load (image, status, TRUE, TRUE);
1937 if (image == NULL)
1938 return NULL;
1940 return register_image (mono_alc_get_loaded_images (alc), image, NULL);
1942 #endif
1945 * mono_image_open_full:
1947 MonoImage *
1948 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1950 MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ());
1951 return mono_image_open_a_lot (alc, fname, status, refonly, FALSE);
1954 static MonoImage *
1955 mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context, gboolean *problematic)
1957 MonoImage *image;
1958 GHashTable *loaded_images = mono_loaded_images_get_hash (li, refonly);
1959 char *absfname;
1961 g_return_val_if_fail (fname != NULL, NULL);
1963 #ifdef HOST_WIN32
1964 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1965 // then assemblies need to be loaded with LoadLibrary:
1966 if (!refonly && coree_module_handle) {
1967 HMODULE module_handle;
1968 gunichar2 *fname_utf16;
1969 DWORD last_error;
1971 absfname = mono_path_resolve_symlinks (fname);
1972 fname_utf16 = NULL;
1974 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1975 mono_images_lock ();
1976 image = (MonoImage*)g_hash_table_lookup (loaded_images, absfname);
1977 if (image) { // Image already loaded
1978 if (!load_from_context && mono_is_problematic_image (image)) {
1979 // If we previously loaded a problematic image, don't
1980 // return it if we're not in LoadFrom context.
1982 // Note: this has an interaction with
1983 // mono_problematic_image_reprobe - at that point we
1984 // have a problematic image opened, but we don't want
1985 // to see it again when we go searching for an image
1986 // to load.
1987 mono_images_unlock ();
1989 if (problematic)
1990 *problematic = TRUE;
1992 return NULL;
1994 g_assert (m_image_is_module_handle (image));
1995 if (m_image_has_entry_point (image) && image->ref_count == 0) {
1996 /* Increment reference count on images loaded outside of the runtime. */
1997 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1998 /* The image is already loaded because _CorDllMain removes images from the hash. */
1999 module_handle = LoadLibrary (fname_utf16);
2000 g_assert (module_handle == (HMODULE) image->raw_data);
2002 mono_image_addref (image);
2003 mono_images_unlock ();
2004 if (fname_utf16)
2005 g_free (fname_utf16);
2006 g_free (absfname);
2007 return image;
2010 // Image not loaded, load it now
2011 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
2012 module_handle = MonoLoadImage (fname_utf16);
2013 if (status && module_handle == NULL)
2014 last_error = mono_w32error_get_last ();
2016 /* mono_image_open_from_module_handle is called by _CorDllMain. */
2017 image = (MonoImage*)g_hash_table_lookup (loaded_images, absfname);
2018 if (image)
2019 mono_image_addref (image);
2020 mono_images_unlock ();
2022 g_free (fname_utf16);
2024 if (module_handle == NULL) {
2025 g_assert (!image);
2026 g_free (absfname);
2027 if (status) {
2028 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT) {
2029 if (status)
2030 *status = MONO_IMAGE_IMAGE_INVALID;
2031 } else {
2032 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
2033 mono_set_errno (ENOENT);
2034 else
2035 mono_set_errno (0);
2038 return NULL;
2041 if (image) {
2042 g_assert (m_image_is_module_handle (image));
2043 g_assert (m_image_has_entry_point (image));
2044 g_free (absfname);
2045 return image;
2048 return mono_image_open_from_module_handle (alc, module_handle, absfname, FALSE, status);
2050 #endif
2052 absfname = mono_path_resolve_symlinks (fname);
2055 * The easiest solution would be to do all the loading inside the mutex,
2056 * but that would lead to scalability problems. So we let the loading
2057 * happen outside the mutex, and if multiple threads happen to load
2058 * the same image, we discard all but the first copy.
2060 mono_images_lock ();
2061 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
2062 g_free (absfname);
2064 if (image) { // Image already loaded
2065 if (!refonly && !load_from_context && mono_is_problematic_image (image)) {
2066 // If we previously loaded a problematic image, don't
2067 // return it if we're not in LoadFrom context.
2069 // Note: this has an interaction with
2070 // mono_problematic_image_reprobe - at that point we
2071 // have a problematic image opened, but we don't want
2072 // to see it again when we go searching for an image
2073 // to load.
2074 mono_images_unlock ();
2075 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Not returning problematic image '%s' refcount=%d", image->name, image->ref_count);
2076 if (problematic)
2077 *problematic = TRUE;
2078 return NULL;
2080 mono_image_addref (image);
2081 mono_images_unlock ();
2082 return image;
2084 mono_images_unlock ();
2086 // Image not loaded, load it now
2087 image = do_mono_image_open (alc, fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
2088 if (image == NULL)
2089 return NULL;
2091 return register_image (li, image, problematic);
2094 MonoImage *
2095 mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
2097 MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
2098 return mono_image_open_a_lot_parameterized (li, alc, fname, status, refonly, load_from_context, NULL);
2101 gboolean
2102 mono_is_problematic_file (const char *fname)
2104 MonoImageOpenStatus status;
2105 gboolean problematic = FALSE;
2107 MonoDomain *domain = mono_domain_get ();
2108 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
2109 MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
2110 MonoImage *opened = mono_image_open_a_lot_parameterized (li, alc, fname, &status, FALSE, FALSE, &problematic);
2111 if (opened)
2112 mono_image_close (opened);
2114 return problematic;
2119 * mono_image_open:
2120 * \param fname filename that points to the module we want to open
2121 * \param status An error condition is returned in this field
2122 * \returns An open image of type \c MonoImage or NULL on error.
2123 * The caller holds a temporary reference to the returned image which should be cleared
2124 * when no longer needed by calling \c mono_image_close.
2125 * if NULL, then check the value of \p status for details on the error
2127 MonoImage *
2128 mono_image_open (const char *fname, MonoImageOpenStatus *status)
2130 MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ());
2131 return mono_image_open_a_lot (alc, fname, status, FALSE, FALSE);
2135 * mono_pe_file_open:
2136 * \param fname filename that points to the module we want to open
2137 * \param status An error condition is returned in this field
2138 * \returns An open image of type \c MonoImage or NULL on error. if
2139 * NULL, then check the value of \p status for details on the error.
2140 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
2141 * It's just a PE file loader, used for \c FileVersionInfo. It also does
2142 * not use the image cache.
2144 MonoImage *
2145 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
2147 g_return_val_if_fail (fname != NULL, NULL);
2148 MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ());
2150 return do_mono_image_open (alc, fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
2154 * mono_image_open_raw
2155 * \param fname filename that points to the module we want to open
2156 * \param status An error condition is returned in this field
2157 * \returns an image without loading neither pe or cli data.
2158 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
2160 MonoImage *
2161 mono_image_open_raw (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
2163 g_return_val_if_fail (fname != NULL, NULL);
2165 return do_mono_image_open (alc, fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
2169 * mono_image_open_metadata_only:
2171 * Open an image which contains metadata only without a PE header.
2173 MonoImage *
2174 mono_image_open_metadata_only (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
2176 return do_mono_image_open (alc, fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
2180 * mono_image_fixup_vtable:
2182 void
2183 mono_image_fixup_vtable (MonoImage *image)
2185 #ifdef HOST_WIN32
2186 MonoCLIImageInfo *iinfo;
2187 MonoPEDirEntry *de;
2188 MonoVTableFixup *vtfixup;
2189 int count;
2190 gpointer slot;
2191 guint16 slot_type;
2192 int slot_count;
2194 g_assert (m_image_is_module_handle (image));
2196 iinfo = image->image_info;
2197 de = &iinfo->cli_cli_header.ch_vtable_fixups;
2198 if (!de->rva || !de->size)
2199 return;
2200 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
2201 if (!vtfixup)
2202 return;
2204 count = de->size / sizeof (MonoVTableFixup);
2205 while (count--) {
2206 if (!vtfixup->rva || !vtfixup->count)
2207 continue;
2209 slot = mono_image_rva_map (image, vtfixup->rva);
2210 g_assert (slot);
2211 slot_type = vtfixup->type;
2212 slot_count = vtfixup->count;
2213 if (slot_type & VTFIXUP_TYPE_32BIT)
2214 while (slot_count--) {
2215 *((guint32*) slot) = (guint32)(gsize)mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
2216 slot = ((guint32*) slot) + 1;
2218 else if (slot_type & VTFIXUP_TYPE_64BIT)
2219 while (slot_count--) {
2220 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
2221 slot = ((guint32*) slot) + 1;
2223 else
2224 g_assert_not_reached();
2226 vtfixup++;
2228 #else
2229 g_assert_not_reached();
2230 #endif
2233 static void
2234 free_hash_table (gpointer key, gpointer val, gpointer user_data)
2236 g_hash_table_destroy ((GHashTable*)val);
2240 static void
2241 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
2243 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
2247 static void
2248 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
2250 g_slist_free ((GSList*)val);
2254 * mono_image_addref:
2255 * \param image The image file we wish to add a reference to
2256 * Increases the reference count of an image.
2258 void
2259 mono_image_addref (MonoImage *image)
2261 mono_atomic_inc_i32 (&image->ref_count);
2264 void
2265 mono_dynamic_stream_reset (MonoDynamicStream* stream)
2267 stream->alloc_size = stream->index = stream->offset = 0;
2268 g_free (stream->data);
2269 stream->data = NULL;
2270 if (stream->hash) {
2271 g_hash_table_destroy (stream->hash);
2272 stream->hash = NULL;
2276 static void
2277 free_hash (GHashTable *hash)
2279 if (hash)
2280 g_hash_table_destroy (hash);
2283 void
2284 mono_wrapper_caches_free (MonoWrapperCaches *cache)
2286 free_hash (cache->delegate_invoke_cache);
2287 free_hash (cache->delegate_begin_invoke_cache);
2288 free_hash (cache->delegate_end_invoke_cache);
2289 free_hash (cache->runtime_invoke_signature_cache);
2291 free_hash (cache->delegate_abstract_invoke_cache);
2293 free_hash (cache->runtime_invoke_method_cache);
2294 free_hash (cache->managed_wrapper_cache);
2296 free_hash (cache->native_wrapper_cache);
2297 free_hash (cache->native_wrapper_aot_cache);
2298 free_hash (cache->native_wrapper_check_cache);
2299 free_hash (cache->native_wrapper_aot_check_cache);
2301 free_hash (cache->native_func_wrapper_aot_cache);
2302 free_hash (cache->remoting_invoke_cache);
2303 free_hash (cache->synchronized_cache);
2304 free_hash (cache->unbox_wrapper_cache);
2305 free_hash (cache->cominterop_invoke_cache);
2306 free_hash (cache->cominterop_wrapper_cache);
2307 free_hash (cache->thunk_invoke_cache);
2310 static void
2311 mono_image_close_except_pools_all (MonoImage**images, int image_count)
2313 for (int i = 0; i < image_count; ++i) {
2314 if (images [i]) {
2315 if (!mono_image_close_except_pools (images [i]))
2316 images [i] = NULL;
2322 * Returns whether mono_image_close_finish() must be called as well.
2323 * We must unload images in two steps because clearing the domain in
2324 * SGen requires the class metadata to be intact, but we need to free
2325 * the mono_g_hash_tables in case a collection occurs during domain
2326 * unloading and the roots would trip up the GC.
2328 gboolean
2329 mono_image_close_except_pools (MonoImage *image)
2331 int i;
2333 g_return_val_if_fail (image != NULL, FALSE);
2336 if (!mono_loaded_images_remove_image (image))
2337 return FALSE;
2339 #ifdef HOST_WIN32
2340 if (m_image_is_module_handle (image) && m_image_has_entry_point (image)) {
2341 mono_images_lock ();
2342 if (image->ref_count == 0) {
2343 /* Image will be closed by _CorDllMain. */
2344 FreeLibrary ((HMODULE) image->raw_data);
2345 mono_images_unlock ();
2346 return FALSE;
2348 mono_images_unlock ();
2350 #endif
2352 MONO_PROFILER_RAISE (image_unloading, (image));
2354 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
2356 mono_image_invoke_unload_hook (image);
2358 mono_metadata_clean_for_image (image);
2361 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2362 * assemblies, so we can't release these references in mono_assembly_close () since the
2363 * MonoImage might outlive its associated MonoAssembly.
2365 if (image->references && !image_is_dynamic (image)) {
2366 for (i = 0; i < image->nreferences; i++) {
2367 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2368 if (!mono_assembly_close_except_image_pools (image->references [i]))
2369 image->references [i] = NULL;
2372 } else {
2373 if (image->references) {
2374 g_free (image->references);
2375 image->references = NULL;
2379 /* a MonoDynamicImage doesn't have any storage */
2380 g_assert (image_is_dynamic (image) || image->storage != NULL);
2382 if (image->storage && m_image_is_raw_data_allocated (image)) {
2383 /* FIXME: do we need this? (image is disposed anyway) */
2384 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2385 MonoCLIImageInfo *ii = image->image_info;
2387 if ((image->raw_metadata > image->raw_data) &&
2388 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2389 image->raw_metadata = NULL;
2391 for (i = 0; i < ii->cli_section_count; i++)
2392 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2393 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2394 ii->cli_sections [i] = NULL;
2398 if (image->storage)
2399 mono_image_storage_close (image->storage);
2401 if (debug_assembly_unload) {
2402 char *old_name = image->name;
2403 image->name = g_strdup_printf ("%s - UNLOADED", old_name);
2404 g_free (old_name);
2405 } else {
2406 g_free (image->name);
2407 g_free (image->filename);
2408 g_free (image->guid);
2409 g_free (image->version);
2412 if (image->method_cache)
2413 g_hash_table_destroy (image->method_cache);
2414 if (image->methodref_cache)
2415 g_hash_table_destroy (image->methodref_cache);
2416 mono_internal_hash_table_destroy (&image->class_cache);
2417 mono_conc_hashtable_destroy (image->field_cache);
2418 if (image->array_cache) {
2419 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2420 g_hash_table_destroy (image->array_cache);
2422 if (image->szarray_cache)
2423 g_hash_table_destroy (image->szarray_cache);
2424 if (image->ptr_cache)
2425 g_hash_table_destroy (image->ptr_cache);
2426 if (image->name_cache) {
2427 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2428 g_hash_table_destroy (image->name_cache);
2431 free_hash (image->delegate_bound_static_invoke_cache);
2432 free_hash (image->ldfld_wrapper_cache);
2433 free_hash (image->ldflda_wrapper_cache);
2434 free_hash (image->stfld_wrapper_cache);
2435 free_hash (image->isinst_cache);
2436 free_hash (image->castclass_cache);
2437 free_hash (image->icall_wrapper_cache);
2438 free_hash (image->proxy_isinst_cache);
2439 if (image->var_gparam_cache)
2440 mono_conc_hashtable_destroy (image->var_gparam_cache);
2441 if (image->mvar_gparam_cache)
2442 mono_conc_hashtable_destroy (image->mvar_gparam_cache);
2443 free_hash (image->wrapper_param_names);
2444 #ifndef ENABLE_NETCORE
2445 free_hash (image->pinvoke_scopes);
2446 #endif
2447 free_hash (image->native_func_wrapper_cache);
2448 mono_conc_hashtable_destroy (image->typespec_cache);
2449 free_hash (image->weak_field_indexes);
2451 mono_wrapper_caches_free (&image->wrapper_caches);
2453 for (i = 0; i < image->gshared_types_len; ++i)
2454 free_hash (image->gshared_types [i]);
2455 g_free (image->gshared_types);
2457 /* The ownership of signatures is not well defined */
2458 g_hash_table_destroy (image->memberref_signatures);
2459 g_hash_table_destroy (image->method_signatures);
2461 if (image->rgctx_template_hash)
2462 g_hash_table_destroy (image->rgctx_template_hash);
2464 if (image->property_hash)
2465 mono_property_hash_destroy (image->property_hash);
2468 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2469 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2471 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2472 image->reflection_info_unregister_classes = NULL;
2474 if (image->interface_bitset) {
2475 mono_unload_interface_ids (image->interface_bitset);
2476 mono_bitset_free (image->interface_bitset);
2478 if (image->image_info){
2479 MonoCLIImageInfo *ii = image->image_info;
2481 g_free (ii->cli_section_tables);
2482 g_free (ii->cli_sections);
2483 g_free (image->image_info);
2486 mono_image_close_except_pools_all (image->files, image->file_count);
2487 mono_image_close_except_pools_all (image->modules, image->module_count);
2488 g_free (image->modules_loaded);
2490 mono_os_mutex_destroy (&image->szarray_cache_lock);
2491 mono_os_mutex_destroy (&image->lock);
2493 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2494 if (image_is_dynamic (image)) {
2495 /* Dynamic images are GC_MALLOCed */
2496 g_free ((char*)image->module_name);
2497 mono_dynamic_image_free ((MonoDynamicImage*)image);
2500 MONO_PROFILER_RAISE (image_unloaded, (image));
2502 return TRUE;
2505 static void
2506 mono_image_close_all (MonoImage**images, int image_count)
2508 for (int i = 0; i < image_count; ++i) {
2509 if (images [i])
2510 mono_image_close_finish (images [i]);
2512 if (images)
2513 g_free (images);
2516 void
2517 mono_image_close_finish (MonoImage *image)
2519 int i;
2521 if (image->references && !image_is_dynamic (image)) {
2522 for (i = 0; i < image->nreferences; i++) {
2523 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2524 mono_assembly_close_finish (image->references [i]);
2527 g_free (image->references);
2528 image->references = NULL;
2531 mono_image_close_all (image->files, image->file_count);
2532 mono_image_close_all (image->modules, image->module_count);
2534 #ifndef DISABLE_PERFCOUNTERS
2535 /* FIXME: use an explicit subtraction method as soon as it's available */
2536 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2537 #endif
2539 if (!image_is_dynamic (image)) {
2540 if (debug_assembly_unload)
2541 mono_mempool_invalidate (image->mempool);
2542 else {
2543 mono_mempool_destroy (image->mempool);
2544 g_free (image);
2546 } else {
2547 if (debug_assembly_unload)
2548 mono_mempool_invalidate (image->mempool);
2549 else {
2550 mono_mempool_destroy (image->mempool);
2551 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2557 * mono_image_close:
2558 * \param image The image file we wish to close
2559 * Closes an image file, deallocates all memory consumed and
2560 * unmaps all possible sections of the file
2562 void
2563 mono_image_close (MonoImage *image)
2565 if (mono_image_close_except_pools (image))
2566 mono_image_close_finish (image);
2569 /**
2570 * mono_image_strerror:
2571 * \param status an code indicating the result from a recent operation
2572 * \returns a string describing the error
2574 const char *
2575 mono_image_strerror (MonoImageOpenStatus status)
2577 switch (status){
2578 case MONO_IMAGE_OK:
2579 return "success";
2580 case MONO_IMAGE_ERROR_ERRNO:
2581 return strerror (errno);
2582 case MONO_IMAGE_IMAGE_INVALID:
2583 return "File does not contain a valid CIL image";
2584 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2585 return "An assembly was referenced, but could not be found";
2587 return "Internal error";
2590 static gpointer
2591 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2592 guint32 lang_id, gunichar2 *name,
2593 MonoPEResourceDirEntry *entry,
2594 MonoPEResourceDir *root, guint32 level)
2596 gboolean is_string, is_dir;
2597 guint32 name_offset, dir_offset;
2599 /* Level 0 holds a directory entry for each type of resource
2600 * (identified by ID or name).
2602 * Level 1 holds a directory entry for each named resource
2603 * item, and each "anonymous" item of a particular type of
2604 * resource.
2606 * Level 2 holds a directory entry for each language pointing to
2607 * the actual data.
2609 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2610 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2612 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2613 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2615 if(level==0) {
2616 if (is_string)
2617 return NULL;
2618 } else if (level==1) {
2619 if (res_id != name_offset)
2620 return NULL;
2621 #if 0
2622 if(name!=NULL &&
2623 is_string==TRUE && name!=lookup (name_offset)) {
2624 return(NULL);
2626 #endif
2627 } else if (level==2) {
2628 if (is_string || (lang_id != 0 && name_offset != lang_id))
2629 return NULL;
2630 } else {
2631 g_assert_not_reached ();
2634 if (is_dir) {
2635 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2636 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2637 guint32 entries, i;
2639 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2641 for(i=0; i<entries; i++) {
2642 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2643 gpointer ret;
2645 ret=mono_image_walk_resource_tree (info, res_id,
2646 lang_id, name,
2647 sub_entry, root,
2648 level+1);
2649 if(ret!=NULL) {
2650 return(ret);
2654 return(NULL);
2655 } else {
2656 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2657 MonoPEResourceDataEntry *res;
2659 res = g_new0 (MonoPEResourceDataEntry, 1);
2661 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2662 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2663 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2664 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2666 return (res);
2671 * mono_image_lookup_resource:
2672 * \param image the image to look up the resource in
2673 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2674 * \param lang_id The language id.
2675 * \param name the resource name to lookup.
2676 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2677 * of the given resource. The caller should free it using \c g_free when no longer
2678 * needed.
2680 gpointer
2681 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2683 MonoCLIImageInfo *info;
2684 MonoDotNetHeader *header;
2685 MonoPEDatadir *datadir;
2686 MonoPEDirEntry *rsrc;
2687 MonoPEResourceDir *resource_dir;
2688 MonoPEResourceDirEntry *res_entries;
2689 guint32 entries, i;
2691 if(image==NULL) {
2692 return(NULL);
2695 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2697 info = (MonoCLIImageInfo *)image->image_info;
2698 if(info==NULL) {
2699 return(NULL);
2702 header=&info->cli_header;
2703 if(header==NULL) {
2704 return(NULL);
2707 datadir=&header->datadir;
2708 if(datadir==NULL) {
2709 return(NULL);
2712 rsrc=&datadir->pe_resource_table;
2713 if(rsrc==NULL) {
2714 return(NULL);
2717 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2718 if(resource_dir==NULL) {
2719 return(NULL);
2722 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2723 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2725 for(i=0; i<entries; i++) {
2726 MonoPEResourceDirEntry *entry=&res_entries[i];
2727 gpointer ret;
2729 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2730 name, entry, resource_dir,
2732 if(ret!=NULL) {
2733 return(ret);
2737 return(NULL);
2740 /**
2741 * mono_image_get_entry_point:
2742 * \param image the image where the entry point will be looked up.
2743 * Use this routine to determine the metadata token for method that
2744 * has been flagged as the entry point.
2745 * \returns the token for the entry point method in the image
2747 guint32
2748 mono_image_get_entry_point (MonoImage *image)
2750 return image->image_info->cli_cli_header.ch_entry_point;
2754 * mono_image_get_resource:
2755 * \param image the image where the resource will be looked up.
2756 * \param offset The offset to add to the resource
2757 * \param size a pointer to an int where the size of the resource will be stored
2759 * This is a low-level routine that fetches a resource from the
2760 * metadata that starts at a given \p offset. The \p size parameter is
2761 * filled with the data field as encoded in the metadata.
2763 * \returns the pointer to the resource whose offset is \p offset.
2765 const char*
2766 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2768 MonoCLIImageInfo *iinfo = image->image_info;
2769 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2770 const char* data;
2772 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2773 return NULL;
2775 data = mono_image_rva_map (image, ch->ch_resources.rva);
2776 if (!data)
2777 return NULL;
2778 data += offset;
2779 if (size)
2780 *size = read32 (data);
2781 data += 4;
2782 return data;
2785 // Returning NULL with no error set will be interpeted as "not found"
2786 MonoImage*
2787 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2789 char *base_dir, *name;
2790 MonoImage *res;
2791 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2792 const char *fname;
2793 guint32 fname_id;
2795 error_init (error);
2797 if (fileidx < 1 || fileidx > t->rows)
2798 return NULL;
2800 mono_image_lock (image);
2801 if (image->files && image->files [fileidx - 1]) {
2802 mono_image_unlock (image);
2803 return image->files [fileidx - 1];
2805 mono_image_unlock (image);
2807 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2808 fname = mono_metadata_string_heap (image, fname_id);
2809 base_dir = g_path_get_dirname (image->name);
2810 name = g_build_filename (base_dir, fname, (const char*)NULL);
2811 res = mono_image_open (name, NULL);
2812 if (!res)
2813 goto done;
2815 mono_image_lock (image);
2816 if (image->files && image->files [fileidx - 1]) {
2817 MonoImage *old = res;
2818 res = image->files [fileidx - 1];
2819 mono_image_unlock (image);
2820 mono_image_close (old);
2821 } else {
2822 int i;
2823 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2824 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2825 mono_image_unlock (image);
2826 mono_image_close (res);
2827 return NULL;
2830 for (i = 0; i < res->module_count; ++i) {
2831 if (res->modules [i] && !res->modules [i]->assembly)
2832 res->modules [i]->assembly = image->assembly;
2835 if (!image->files) {
2836 image->files = g_new0 (MonoImage*, t->rows);
2837 image->file_count = t->rows;
2839 image->files [fileidx - 1] = res;
2840 mono_image_unlock (image);
2841 /* vtable fixup can't happen with the image lock held */
2842 #ifdef HOST_WIN32
2843 if (m_image_is_module_handle (res))
2844 mono_image_fixup_vtable (res);
2845 #endif
2848 done:
2849 g_free (name);
2850 g_free (base_dir);
2851 return res;
2855 * mono_image_load_file_for_image:
2857 MonoImage*
2858 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2860 ERROR_DECL (error);
2861 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, error);
2862 mono_error_assert_ok (error);
2863 return result;
2867 * mono_image_get_strong_name:
2868 * \param image a MonoImage
2869 * \param size a \c guint32 pointer, or NULL.
2871 * If the image has a strong name, and \p size is not NULL, the value
2872 * pointed to by size will have the size of the strong name.
2874 * \returns NULL if the image does not have a strong name, or a
2875 * pointer to the public key.
2877 const char*
2878 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2880 MonoCLIImageInfo *iinfo = image->image_info;
2881 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2882 const char* data;
2884 if (!de->size || !de->rva)
2885 return NULL;
2886 data = mono_image_rva_map (image, de->rva);
2887 if (!data)
2888 return NULL;
2889 if (size)
2890 *size = de->size;
2891 return data;
2895 * mono_image_strong_name_position:
2896 * \param image a \c MonoImage
2897 * \param size a \c guint32 pointer, or NULL.
2899 * If the image has a strong name, and \p size is not NULL, the value
2900 * pointed to by size will have the size of the strong name.
2902 * \returns the position within the image file where the strong name
2903 * is stored.
2905 guint32
2906 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2908 MonoCLIImageInfo *iinfo = image->image_info;
2909 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2910 guint32 pos;
2912 if (size)
2913 *size = de->size;
2914 if (!de->size || !de->rva)
2915 return 0;
2916 pos = mono_cli_rva_image_map (image, de->rva);
2917 return pos == INVALID_ADDRESS ? 0 : pos;
2921 * mono_image_get_public_key:
2922 * \param image a \c MonoImage
2923 * \param size a \c guint32 pointer, or NULL.
2925 * This is used to obtain the public key in the \p image.
2927 * If the image has a public key, and \p size is not NULL, the value
2928 * pointed to by size will have the size of the public key.
2930 * \returns NULL if the image does not have a public key, or a pointer
2931 * to the public key.
2933 const char*
2934 mono_image_get_public_key (MonoImage *image, guint32 *size)
2936 const char *pubkey;
2937 guint32 len, tok;
2939 if (image_is_dynamic (image)) {
2940 if (size)
2941 *size = ((MonoDynamicImage*)image)->public_key_len;
2942 return (char*)((MonoDynamicImage*)image)->public_key;
2944 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2945 return NULL;
2946 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2947 if (!tok)
2948 return NULL;
2949 pubkey = mono_metadata_blob_heap (image, tok);
2950 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2951 if (size)
2952 *size = len;
2953 return pubkey;
2957 * mono_image_get_name:
2958 * \param name a \c MonoImage
2959 * \returns the name of the assembly.
2961 const char*
2962 mono_image_get_name (MonoImage *image)
2964 return image->assembly_name;
2968 * mono_image_get_filename:
2969 * \param image a \c MonoImage
2970 * Used to get the filename that hold the actual \c MonoImage
2971 * \returns the filename.
2973 const char*
2974 mono_image_get_filename (MonoImage *image)
2976 return image->name;
2980 * mono_image_get_guid:
2982 const char*
2983 mono_image_get_guid (MonoImage *image)
2985 return image->guid;
2989 * mono_image_get_table_info:
2991 const MonoTableInfo*
2992 mono_image_get_table_info (MonoImage *image, int table_id)
2994 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2995 return NULL;
2996 return &image->tables [table_id];
3000 * mono_image_get_table_rows:
3003 mono_image_get_table_rows (MonoImage *image, int table_id)
3005 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
3006 return 0;
3007 return image->tables [table_id].rows;
3011 * mono_table_info_get_rows:
3014 mono_table_info_get_rows (const MonoTableInfo *table)
3016 return table->rows;
3020 * mono_image_get_assembly:
3021 * \param image the \c MonoImage .
3022 * Use this routine to get the assembly that owns this image.
3023 * \returns the assembly that holds this image.
3025 MonoAssembly*
3026 mono_image_get_assembly (MonoImage *image)
3028 return image->assembly;
3032 * mono_image_is_dynamic:
3033 * \param image the \c MonoImage
3035 * Determines if the given image was created dynamically through the
3036 * \c System.Reflection.Emit API
3037 * \returns TRUE if the image was created dynamically, FALSE if not.
3039 gboolean
3040 mono_image_is_dynamic (MonoImage *image)
3042 return image_is_dynamic (image);
3046 * mono_image_has_authenticode_entry:
3047 * \param image the \c MonoImage
3048 * Use this routine to determine if the image has a Authenticode
3049 * Certificate Table.
3050 * \returns TRUE if the image contains an authenticode entry in the PE
3051 * directory.
3053 gboolean
3054 mono_image_has_authenticode_entry (MonoImage *image)
3056 MonoCLIImageInfo *iinfo = image->image_info;
3057 MonoDotNetHeader *header = &iinfo->cli_header;
3058 if (!header)
3059 return FALSE;
3060 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
3061 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
3062 return ((de->rva != 0) && (de->size > 8));
3065 gpointer
3066 mono_image_alloc (MonoImage *image, guint size)
3068 gpointer res;
3070 #ifndef DISABLE_PERFCOUNTERS
3071 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
3072 #endif
3073 mono_image_lock (image);
3074 res = mono_mempool_alloc (image->mempool, size);
3075 mono_image_unlock (image);
3077 return res;
3080 gpointer
3081 mono_image_alloc0 (MonoImage *image, guint size)
3083 gpointer res;
3085 #ifndef DISABLE_PERFCOUNTERS
3086 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
3087 #endif
3088 mono_image_lock (image);
3089 res = mono_mempool_alloc0 (image->mempool, size);
3090 mono_image_unlock (image);
3092 return res;
3095 char*
3096 mono_image_strdup (MonoImage *image, const char *s)
3098 char *res;
3100 #ifndef DISABLE_PERFCOUNTERS
3101 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (s));
3102 #endif
3103 mono_image_lock (image);
3104 res = mono_mempool_strdup (image->mempool, s);
3105 mono_image_unlock (image);
3107 return res;
3110 char*
3111 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
3113 char *buf;
3114 mono_image_lock (image);
3115 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
3116 mono_image_unlock (image);
3117 #ifndef DISABLE_PERFCOUNTERS
3118 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (buf));
3119 #endif
3120 return buf;
3123 char*
3124 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
3126 char *buf;
3127 va_list args;
3129 va_start (args, format);
3130 buf = mono_image_strdup_vprintf (image, format, args);
3131 va_end (args);
3132 return buf;
3135 GList*
3136 mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
3138 GList *new_list;
3140 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
3141 new_list->data = data;
3142 new_list->prev = list ? list->prev : NULL;
3143 new_list->next = list;
3145 if (new_list->prev)
3146 new_list->prev->next = new_list;
3147 if (list)
3148 list->prev = new_list;
3150 return new_list;
3153 GSList*
3154 mono_g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
3156 GSList *new_list;
3158 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
3159 new_list->data = data;
3160 new_list->next = NULL;
3162 return g_slist_concat (list, new_list);
3165 void
3166 mono_image_lock (MonoImage *image)
3168 mono_locks_os_acquire (&image->lock, ImageDataLock);
3171 void
3172 mono_image_unlock (MonoImage *image)
3174 mono_locks_os_release (&image->lock, ImageDataLock);
3179 * mono_image_property_lookup:
3180 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
3182 * LOCKING: Takes the image lock
3184 gpointer
3185 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
3187 gpointer res;
3189 mono_image_lock (image);
3190 res = mono_property_hash_lookup (image->property_hash, subject, property);
3191 mono_image_unlock (image);
3193 return res;
3197 * mono_image_property_insert:
3198 * Insert a new property \p property with value \p value on \p subject in \p
3199 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
3201 * LOCKING: Takes the image lock
3203 void
3204 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
3206 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
3207 mono_image_lock (image);
3208 mono_property_hash_insert (image->property_hash, subject, property, value);
3209 mono_image_unlock (image);
3213 * mono_image_property_remove:
3214 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
3216 * LOCKING: Takes the image lock
3218 void
3219 mono_image_property_remove (MonoImage *image, gpointer subject)
3221 mono_image_lock (image);
3222 mono_property_hash_remove_object (image->property_hash, subject);
3223 mono_image_unlock (image);
3226 void
3227 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
3229 MonoImage *image = m_class_get_image (klass);
3230 g_assert (image_is_dynamic (image));
3231 mono_image_lock (image);
3232 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
3233 mono_image_unlock (image);