Implemeneted imprecise.
[mono-project.git] / mono / metadata / image.c
blob0d653265cd827db39268116e28a4c3e56b8c8eb3
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_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name);
524 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
525 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
526 image->heap_pdb.size = read32 (ptr + 4);
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 MonoTableInfo *t;
689 MonoTableInfo *file_table;
690 int i;
691 char *base_dir;
692 gboolean refonly = image->ref_only;
693 GList *list_iter, *valid_modules = NULL;
694 MonoImageOpenStatus status;
696 error_init (error);
698 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
699 return NULL;
700 if (image->modules_loaded [idx - 1])
701 return image->modules [idx - 1];
703 #ifdef ENABLE_NETCORE
704 /* SRE still uses image->modules, but they are not loaded from files, so the rest of this function is dead code for netcore */
705 g_assert_not_reached ();
706 #else
708 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);
710 file_table = &image->tables [MONO_TABLE_FILE];
711 for (i = 0; i < file_table->rows; i++) {
712 guint32 cols [MONO_FILE_SIZE];
713 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
714 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
715 continue;
716 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
719 t = &image->tables [MONO_TABLE_MODULEREF];
720 base_dir = g_path_get_dirname (image->name);
723 char *module_ref;
724 const char *name;
725 guint32 cols [MONO_MODULEREF_SIZE];
726 /* if there is no file table, we try to load the module... */
727 int valid = file_table->rows == 0;
729 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
730 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
731 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
732 /* be safe with string dups, but we could just compare string indexes */
733 if (strcmp ((const char*)list_iter->data, name) == 0) {
734 valid = TRUE;
735 break;
738 if (valid) {
739 MonoAssemblyLoadContext *alc = mono_image_get_alc (image);
740 MonoLoadedImages *li = mono_image_get_loaded_images_for_modules (image);
741 module_ref = g_build_filename (base_dir, name, NULL);
742 MonoImage *moduleImage = mono_image_open_a_lot_parameterized (li, alc, module_ref, &status, refonly, FALSE, NULL);
743 if (moduleImage) {
744 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
745 mono_image_close (moduleImage);
746 g_free (module_ref);
747 g_free (base_dir);
748 g_list_free (valid_modules);
749 return NULL;
752 image->modules [idx - 1] = moduleImage;
754 #ifdef HOST_WIN32
755 if (m_image_is_module_handle (image->modules [idx - 1]))
756 mono_image_fixup_vtable (image->modules [idx - 1]);
757 #endif
758 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
760 g_free (module_ref);
764 image->modules_loaded [idx - 1] = TRUE;
766 g_free (base_dir);
767 g_list_free (valid_modules);
769 return image->modules [idx - 1];
770 #endif
774 * mono_image_load_module:
776 MonoImage*
777 mono_image_load_module (MonoImage *image, int idx)
779 ERROR_DECL (error);
780 MonoImage *result = mono_image_load_module_checked (image, idx, error);
781 mono_error_assert_ok (error);
782 return result;
785 static gpointer
786 class_key_extract (gpointer value)
788 MonoClass *klass = (MonoClass *)value;
790 return GUINT_TO_POINTER (m_class_get_type_token (klass));
793 static gpointer*
794 class_next_value (gpointer value)
796 MonoClassDef *klass = (MonoClassDef *)value;
798 return (gpointer*)m_classdef_get_next_class_cache (klass);
802 * mono_image_init:
804 void
805 mono_image_init (MonoImage *image)
807 mono_os_mutex_init_recursive (&image->lock);
808 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
810 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
811 mono_internal_hash_table_init (&image->class_cache,
812 g_direct_hash,
813 class_key_extract,
814 class_next_value);
815 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
817 image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
818 image->memberref_signatures = g_hash_table_new (NULL, NULL);
819 image->method_signatures = g_hash_table_new (NULL, NULL);
821 image->property_hash = mono_property_hash_new ();
824 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
825 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
826 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
827 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
828 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
829 #else
830 #define SWAP64(x)
831 #define SWAP32(x)
832 #define SWAP16(x)
833 #define SWAPPDE(x)
834 #endif
837 * Returns < 0 to indicate an error.
839 static int
840 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
842 MonoDotNetHeader64 header64;
844 #ifdef HOST_WIN32
845 if (!m_image_is_module_handle (image))
846 #endif
847 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
848 return -1;
850 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
852 if (header->pesig [0] != 'P' || header->pesig [1] != 'E' || header->pesig [2] || header->pesig [3])
853 return -1;
855 /* endian swap the fields common between PE and PE+ */
856 SWAP32 (header->coff.coff_time);
857 SWAP32 (header->coff.coff_symptr);
858 SWAP32 (header->coff.coff_symcount);
859 SWAP16 (header->coff.coff_machine);
860 SWAP16 (header->coff.coff_sections);
861 SWAP16 (header->coff.coff_opt_header_size);
862 SWAP16 (header->coff.coff_attributes);
863 /* MonoPEHeader */
864 SWAP32 (header->pe.pe_code_size);
865 SWAP32 (header->pe.pe_uninit_data_size);
866 SWAP32 (header->pe.pe_rva_entry_point);
867 SWAP32 (header->pe.pe_rva_code_base);
868 SWAP32 (header->pe.pe_rva_data_base);
869 SWAP16 (header->pe.pe_magic);
871 /* now we are ready for the basic tests */
873 if (header->pe.pe_magic == 0x10B) {
874 offset += sizeof (MonoDotNetHeader);
875 SWAP32 (header->pe.pe_data_size);
876 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
877 return -1;
879 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
880 SWAP32 (header->nt.pe_stack_reserve);
881 SWAP32 (header->nt.pe_stack_commit);
882 SWAP32 (header->nt.pe_heap_reserve);
883 SWAP32 (header->nt.pe_heap_commit);
884 } else if (header->pe.pe_magic == 0x20B) {
885 /* PE32+ file format */
886 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
887 return -1;
888 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
889 offset += sizeof (MonoDotNetHeader64);
890 /* copy the fields already swapped. the last field, pe_data_size, is missing */
891 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
892 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
893 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
895 SWAP64 (header64.nt.pe_image_base);
896 header->nt.pe_image_base = header64.nt.pe_image_base;
897 SWAP64 (header64.nt.pe_stack_reserve);
898 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
899 SWAP64 (header64.nt.pe_stack_commit);
900 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
901 SWAP64 (header64.nt.pe_heap_reserve);
902 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
903 SWAP64 (header64.nt.pe_heap_commit);
904 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
906 header->nt.pe_section_align = header64.nt.pe_section_align;
907 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
908 header->nt.pe_os_major = header64.nt.pe_os_major;
909 header->nt.pe_os_minor = header64.nt.pe_os_minor;
910 header->nt.pe_user_major = header64.nt.pe_user_major;
911 header->nt.pe_user_minor = header64.nt.pe_user_minor;
912 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
913 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
914 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
915 header->nt.pe_image_size = header64.nt.pe_image_size;
916 header->nt.pe_header_size = header64.nt.pe_header_size;
917 header->nt.pe_checksum = header64.nt.pe_checksum;
918 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
919 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
920 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
921 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
923 /* copy the datadir */
924 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
925 } else {
926 return -1;
929 /* MonoPEHeaderNT: not used yet */
930 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
931 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
932 SWAP16 (header->nt.pe_os_major); /* must be 4 */
933 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
934 SWAP16 (header->nt.pe_user_major);
935 SWAP16 (header->nt.pe_user_minor);
936 SWAP16 (header->nt.pe_subsys_major);
937 SWAP16 (header->nt.pe_subsys_minor);
938 SWAP32 (header->nt.pe_reserved_1);
939 SWAP32 (header->nt.pe_image_size);
940 SWAP32 (header->nt.pe_header_size);
941 SWAP32 (header->nt.pe_checksum);
942 SWAP16 (header->nt.pe_subsys_required);
943 SWAP16 (header->nt.pe_dll_flags);
944 SWAP32 (header->nt.pe_loader_flags);
945 SWAP32 (header->nt.pe_data_dir_count);
947 /* MonoDotNetHeader: mostly unused */
948 SWAPPDE (header->datadir.pe_export_table);
949 SWAPPDE (header->datadir.pe_import_table);
950 SWAPPDE (header->datadir.pe_resource_table);
951 SWAPPDE (header->datadir.pe_exception_table);
952 SWAPPDE (header->datadir.pe_certificate_table);
953 SWAPPDE (header->datadir.pe_reloc_table);
954 SWAPPDE (header->datadir.pe_debug);
955 SWAPPDE (header->datadir.pe_copyright);
956 SWAPPDE (header->datadir.pe_global_ptr);
957 SWAPPDE (header->datadir.pe_tls_table);
958 SWAPPDE (header->datadir.pe_load_config_table);
959 SWAPPDE (header->datadir.pe_bound_import);
960 SWAPPDE (header->datadir.pe_iat);
961 SWAPPDE (header->datadir.pe_delay_import_desc);
962 SWAPPDE (header->datadir.pe_cli_header);
963 SWAPPDE (header->datadir.pe_reserved);
965 #ifdef HOST_WIN32
966 if (m_image_is_module_handle (image))
967 image->storage->raw_data_len = header->nt.pe_image_size;
968 #endif
970 return offset;
973 gboolean
974 mono_image_load_pe_data (MonoImage *image)
976 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
979 static gboolean
980 pe_image_load_pe_data (MonoImage *image)
982 MonoCLIImageInfo *iinfo;
983 MonoDotNetHeader *header;
984 MonoMSDOSHeader msdos;
985 gint32 offset = 0;
987 iinfo = image->image_info;
988 header = &iinfo->cli_header;
990 #ifdef HOST_WIN32
991 if (!m_image_is_module_handle (image))
992 #endif
993 if (offset + sizeof (msdos) > image->raw_data_len)
994 goto invalid_image;
995 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
997 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
998 goto invalid_image;
1000 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
1002 offset = msdos.pe_offset;
1004 offset = do_load_header (image, header, offset);
1005 if (offset < 0)
1006 goto invalid_image;
1009 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1010 * we skip this test.
1011 if (header->coff.coff_machine != 0x14c)
1012 goto invalid_image;
1015 #if 0
1017 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1018 * which produces binaries with 7.0. From Sergey:
1020 * The reason is that MSVC7 uses traditional compile/link
1021 * sequence for CIL executables, and VS.NET (and Framework
1022 * SDK) includes linker version 7, that puts 7.0 in this
1023 * field. That's why it's currently not possible to load VC
1024 * binaries with Mono. This field is pretty much meaningless
1025 * anyway (what linker?).
1027 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1028 goto invalid_image;
1029 #endif
1032 * FIXME: byte swap all addresses here for header.
1035 if (!load_section_tables (image, iinfo, offset))
1036 goto invalid_image;
1038 return TRUE;
1040 invalid_image:
1041 return FALSE;
1044 gboolean
1045 mono_image_load_cli_data (MonoImage *image)
1047 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1050 static gboolean
1051 pe_image_load_cli_data (MonoImage *image)
1053 MonoCLIImageInfo *iinfo;
1055 iinfo = image->image_info;
1057 /* Load the CLI header */
1058 if (!mono_image_load_cli_header (image, iinfo))
1059 return FALSE;
1061 if (!mono_image_load_metadata (image, iinfo))
1062 return FALSE;
1064 return TRUE;
1067 static void
1068 mono_image_load_time_date_stamp (MonoImage *image)
1070 image->time_date_stamp = 0;
1071 #ifndef HOST_WIN32
1072 if (!image->filename)
1073 return;
1075 gunichar2 *uni_name = g_utf8_to_utf16 (image->filename, -1, NULL, NULL, NULL);
1076 mono_pe_file_time_date_stamp (uni_name, &image->time_date_stamp);
1077 g_free (uni_name);
1078 #endif
1081 void
1082 mono_image_load_names (MonoImage *image)
1084 /* modules don't have an assembly table row */
1085 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1086 image->assembly_name = mono_metadata_string_heap (image,
1087 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1088 0, MONO_ASSEMBLY_NAME));
1091 /* Portable pdb images don't have a MODULE row */
1092 if (image->tables [MONO_TABLE_MODULE].rows) {
1093 image->module_name = mono_metadata_string_heap (image,
1094 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1095 0, MONO_MODULE_NAME));
1099 static gboolean
1100 pe_image_load_tables (MonoImage *image)
1102 return TRUE;
1105 static gboolean
1106 pe_image_match (MonoImage *image)
1108 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1109 return TRUE;
1110 return FALSE;
1113 static const MonoImageLoader pe_loader = {
1114 pe_image_match,
1115 pe_image_load_pe_data,
1116 pe_image_load_cli_data,
1117 pe_image_load_tables,
1120 static void
1121 install_pe_loader (void)
1123 mono_install_image_loader (&pe_loader);
1127 Ignored assemblies.
1129 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1130 Mono provides its own implementation of those assemblies so it's safe to do so.
1132 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1134 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1136 This is to be removed once a proper fix is shipped through nuget.
1138 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1139 If any assemblies are added/removed, then this should be regenerated with:
1141 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1145 typedef enum {
1146 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1147 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1148 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1149 SYS_NET_HTTP = 3, //System.Net.Http
1150 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1151 SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1152 } IgnoredAssemblyNames;
1154 typedef struct {
1155 int hash;
1156 int assembly_name;
1157 const char guid [40];
1158 } IgnoredAssembly;
1160 typedef struct {
1161 int assembly_name;
1162 guint16 major, minor, build, revision;
1163 } IgnoredAssemblyVersion;
1165 static const char *ignored_assemblies_file_names[] = {
1166 "System.Runtime.InteropServices.RuntimeInformation.dll",
1167 "System.Globalization.Extensions.dll",
1168 "System.IO.Compression.dll",
1169 "System.Net.Http.dll",
1170 "System.Text.Encoding.CodePages.dll",
1171 "System.Threading.Overlapped.dll"
1174 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { (int)HASH, NAME, GUID }
1176 static const IgnoredAssembly ignored_assemblies [] = {
1177 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1178 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1179 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1180 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1181 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1182 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1183 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1184 IGNORED_ASSEMBLY (0x1FB3F8E8, SYS_GLOBALIZATION_EXT, "B9BA8638-25D2-4A3B-B91F-16B3D3799861", "2.1.100-preview-62617-01 net461"),
1185 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1186 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1187 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1188 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1189 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1190 IGNORED_ASSEMBLY (0x3E21E75A, SYS_TEXT_ENC_CODEPAGES, "67D3A14A-8F55-4C9F-9699-EDD0876369DA", "4.5.0 net461"),
1191 IGNORED_ASSEMBLY (0x420963C4, SYS_NET_HTTP, "084B071E-1637-4B3F-B7CD-6CEF28A6E4AE", "4.3.4 net46"),
1192 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1193 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1194 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1195 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1196 IGNORED_ASSEMBLY (0x4E906129, SYS_NET_HTTP, "27BBDD4C-EAF0-4A95-B172-EE502D76A725", "2.1.100-preview-62617-01 net461"),
1197 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1198 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1199 IGNORED_ASSEMBLY (0x66CEDA9, SYS_THREADING_OVERLAPPED, "A0439CB6-A5E6-4813-A76C-13F92ADDDED5", "2.1.100-preview-62617-01 net461"),
1200 IGNORED_ASSEMBLY (0x6AE7C015, SYS_IO_COMPRESSION, "35DD20B5-8766-476B-B5D2-0EA16EF0A946", "2.1.100-preview-62617-01 net461"),
1201 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46"),
1202 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1203 IGNORED_ASSEMBLY (0x765A8E04, SYS_RT_INTEROP_RUNTIME_INFO, "E46BA45E-6A63-47CD-AF70-2C3016AFF75A", "2.1.100-preview-62617-01 net461"),
1204 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1205 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1206 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1207 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1208 IGNORED_ASSEMBLY (0x8BFCB05D, SYS_THREADING_OVERLAPPED, "82D565AC-E41C-4E29-9939-C031C88EDBDD", "2.1.100-preview-62617-01 net471"),
1209 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1210 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1211 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1212 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1213 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1214 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1215 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1216 IGNORED_ASSEMBLY (0xA99E866F, SYS_NET_HTTP, "41ACE450-8F44-455A-97AC-0679E5462071", "2.1.100-preview-62617-01 net471"),
1217 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1218 IGNORED_ASSEMBLY (0xAF2093B8, SYS_TEXT_ENC_CODEPAGES, "D2B4F262-31A4-4E80-9CFB-26A2249A735E", "4.5.1 net461"),
1219 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1220 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1221 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1222 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1223 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1224 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1225 IGNORED_ASSEMBLY (0xD3ABE53A, SYS_RT_INTEROP_RUNTIME_INFO, "488CE209-4E5D-40E7-BE8C-F81F2B99F13A", "2.1.100-preview-62617-01 net462"),
1226 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1227 IGNORED_ASSEMBLY (0xE16ECCCD, SYS_GLOBALIZATION_EXT, "1A2B9B2A-02F5-4C78-AB0C-7C6D2795CE2B", "2.1.100-preview-62617-01 net471"),
1228 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1229 IGNORED_ASSEMBLY (0xE758DAD4, SYS_IO_COMPRESSION, "8DBD1669-97BC-4190-9BD8-738561193741", "2.1.100-preview-62617-01 net471"),
1230 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1231 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1232 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1233 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1234 IGNORED_ASSEMBLY (0xFC67D3A7, SYS_RT_INTEROP_RUNTIME_INFO, "FD6C8616-C1D8-43F9-AC17-A1C48A45FDA2", "2.1.100-preview-62617-01 net47")
1238 static const char *ignored_assemblies_names[] = {
1239 "System.Runtime.InteropServices.RuntimeInformation",
1240 "System.Globalization.Extensions",
1241 "System.IO.Compression",
1242 "System.Net.Http",
1243 "System.Text.Encoding.CodePages",
1244 "System.Threading.Overlapped"
1247 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { NAME, MAJOR, MINOR, BUILD, REVISION }
1249 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1250 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1251 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1252 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1253 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 1, 0, 0),
1254 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1255 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1256 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 2, 0, 0),
1257 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1258 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1259 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1260 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1261 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 2),
1262 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 3),
1263 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 2, 0, 0),
1264 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1265 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1266 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 2, 0),
1267 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1268 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1269 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1270 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 1, 0),
1271 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1272 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1273 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1274 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 1, 0, 0)
1277 gboolean
1278 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1280 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1281 if (ignored_assembly_versions [i].major != major ||
1282 ignored_assembly_versions [i].minor != minor ||
1283 ignored_assembly_versions [i].build != build ||
1284 ignored_assembly_versions [i].revision != revision)
1285 continue;
1286 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1287 return TRUE;
1289 return FALSE;
1293 Equivalent C# code:
1294 static void Main () {
1295 string str = "...";
1296 int h = 5381;
1297 for (int i = 0; i < str.Length; ++i)
1298 h = ((h << 5) + h) ^ str[i];
1300 Console.WriteLine ("{0:X}", h);
1303 static int
1304 hash_guid (const char *str)
1306 int h = 5381;
1307 while (*str) {
1308 h = ((h << 5) + h) ^ *str;
1309 ++str;
1312 return h;
1315 gboolean
1316 mono_is_problematic_image (MonoImage *image)
1318 int h = hash_guid (image->guid);
1320 //TODO make this more cache effiecient.
1321 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1322 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1323 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1324 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1325 size_t needle_len = strlen (needle);
1326 size_t asm_len = strlen (image->name);
1327 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1328 return TRUE;
1331 return FALSE;
1334 static MonoImage *
1335 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1336 gboolean care_about_cli, gboolean care_about_pecoff)
1338 ERROR_DECL (error);
1339 MonoCLIImageInfo *iinfo;
1340 GSList *l;
1342 MONO_PROFILER_RAISE (image_loading, (image));
1344 mono_image_init (image);
1346 iinfo = image->image_info;
1348 if (!image->metadata_only) {
1349 for (l = image_loaders; l; l = l->next) {
1350 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1351 if (loader->match (image)) {
1352 image->loader = loader;
1353 break;
1356 if (!image->loader) {
1357 if (status)
1358 *status = MONO_IMAGE_IMAGE_INVALID;
1359 goto invalid_image;
1362 if (status)
1363 *status = MONO_IMAGE_IMAGE_INVALID;
1365 if (care_about_pecoff == FALSE)
1366 goto done;
1368 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, error))
1369 goto invalid_image;
1371 if (!mono_image_load_pe_data (image))
1372 goto invalid_image;
1373 } else {
1374 image->loader = (MonoImageLoader*)&pe_loader;
1377 if (care_about_cli == FALSE) {
1378 goto done;
1381 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, error))
1382 goto invalid_image;
1384 if (!mono_image_load_cli_data (image))
1385 goto invalid_image;
1387 if (!image->ref_only && mono_is_problematic_image (image)) {
1388 if (image->load_from_context) {
1389 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1390 } else {
1391 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1392 if (status)
1393 *status = MONO_IMAGE_IMAGE_INVALID;
1394 goto invalid_image;
1398 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, error))
1399 goto invalid_image;
1401 mono_image_load_names (image);
1403 mono_image_load_time_date_stamp (image);
1405 #ifndef ENABLE_NETCORE
1406 load_modules (image);
1407 #endif
1409 done:
1410 MONO_PROFILER_RAISE (image_loaded, (image));
1411 if (status)
1412 *status = MONO_IMAGE_OK;
1414 return image;
1416 invalid_image:
1417 if (!is_ok (error)) {
1418 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Could not load image %s due to %s", image->name, mono_error_get_message (error));
1419 mono_error_cleanup (error);
1421 MONO_PROFILER_RAISE (image_failed, (image));
1422 mono_image_close (image);
1423 return NULL;
1426 static gboolean
1427 mono_image_storage_trypublish (MonoImageStorage *candidate, MonoImageStorage **out_storage)
1429 gboolean result;
1430 mono_images_storage_lock ();
1431 MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, candidate->key);
1432 if (val) {
1433 mono_refcount_inc (val);
1434 *out_storage = val;
1435 result = FALSE;
1436 } else {
1437 g_hash_table_insert (images_storage_hash, candidate->key, candidate);
1438 result = TRUE;
1440 mono_images_storage_unlock ();
1441 return result;
1444 static void
1445 mono_image_storage_unpublish (MonoImageStorage *storage)
1447 mono_images_storage_lock ();
1448 g_assert (storage->ref.ref == 0);
1450 MonoImageStorage *published = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, storage->key);
1451 if (published == storage) {
1452 g_hash_table_remove (images_storage_hash, storage->key);
1455 mono_images_storage_unlock ();
1458 static gboolean
1459 mono_image_storage_tryaddref (const char *key, MonoImageStorage **found)
1461 gboolean result = FALSE;
1462 mono_images_storage_lock ();
1463 MonoImageStorage *val = (MonoImageStorage *)g_hash_table_lookup (images_storage_hash, key);
1464 if (val) {
1465 mono_refcount_inc (val);
1466 *found = val;
1467 result = TRUE;
1469 mono_images_storage_unlock ();
1470 return result;
1473 static void
1474 mono_image_storage_dtor (gpointer self)
1476 MonoImageStorage *storage = (MonoImageStorage *)self;
1478 mono_image_storage_unpublish (storage);
1480 #ifdef HOST_WIN32
1481 if (storage->is_module_handle && !storage->has_entry_point) {
1482 mono_images_lock ();
1483 FreeLibrary ((HMODULE) storage->raw_data);
1484 mono_images_unlock ();
1486 #endif
1488 if (storage->raw_buffer_used) {
1489 if (storage->raw_data != NULL) {
1490 #ifndef HOST_WIN32
1491 if (storage->fileio_used)
1492 mono_file_unmap_fileio (storage->raw_data, storage->raw_data_handle);
1493 else
1494 #endif
1495 mono_file_unmap (storage->raw_data, storage->raw_data_handle);
1498 if (storage->raw_data_allocated) {
1499 g_free (storage->raw_data);
1502 g_free (storage->key);
1504 g_free (storage);
1507 static void
1508 mono_image_storage_close (MonoImageStorage *storage)
1510 mono_refcount_dec (storage);
1513 static gboolean
1514 mono_image_init_raw_data (MonoImage *image, const MonoImageStorage *storage)
1516 if (!storage)
1517 return FALSE;
1518 image->raw_data = storage->raw_data;
1519 image->raw_data_len = storage->raw_data_len;
1520 return TRUE;
1523 static MonoImageStorage *
1524 mono_image_storage_open (const char *fname)
1526 char *key = NULL;
1528 key = mono_path_resolve_symlinks (fname);
1529 MonoImageStorage *published_storage = NULL;
1530 if (mono_image_storage_tryaddref (key, &published_storage)) {
1531 g_free (key);
1532 return published_storage;
1535 MonoFileMap *filed;
1536 if ((filed = mono_file_map_open (fname)) == NULL){
1537 if (IS_PORTABILITY_SET) {
1538 gchar *ffname = mono_portability_find_file (fname, TRUE);
1539 if (ffname) {
1540 filed = mono_file_map_open (ffname);
1541 g_free (ffname);
1545 if (filed == NULL) {
1546 g_free (key);
1547 return NULL;
1551 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1552 mono_refcount_init (storage, mono_image_storage_dtor);
1553 storage->raw_buffer_used = TRUE;
1554 storage->raw_data_len = mono_file_map_size (filed);
1555 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);
1556 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1557 if (!storage->raw_data) {
1558 storage->fileio_used = TRUE;
1559 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);
1561 #endif
1562 mono_file_map_close (filed);
1564 storage->key = key;
1566 MonoImageStorage *other_storage = NULL;
1567 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1568 mono_image_storage_close (storage);
1569 storage = other_storage;
1571 return storage;
1574 static MonoImageStorage *
1575 mono_image_storage_new_raw_data (char *datac, guint32 data_len, gboolean raw_data_allocated, const char *name)
1577 char *key = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup (name);
1578 MonoImageStorage *published_storage = NULL;
1579 if (mono_image_storage_tryaddref (key, &published_storage)) {
1580 g_free (key);
1581 return published_storage;
1584 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1585 mono_refcount_init (storage, mono_image_storage_dtor);
1587 storage->raw_data = datac;
1588 storage->raw_data_len = data_len;
1589 storage->raw_data_allocated = raw_data_allocated;
1591 storage->key = key;
1592 MonoImageStorage *other_storage = NULL;
1593 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1594 mono_image_storage_close (storage);
1595 storage = other_storage;
1597 return storage;
1600 static MonoImage *
1601 do_mono_image_open (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status,
1602 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1604 MonoCLIImageInfo *iinfo;
1605 MonoImage *image;
1607 MonoImageStorage *storage = mono_image_storage_open (fname);
1609 if (!storage) {
1610 if (status)
1611 *status = MONO_IMAGE_ERROR_ERRNO;
1612 return NULL;
1615 image = g_new0 (MonoImage, 1);
1616 image->storage = storage;
1617 mono_image_init_raw_data (image, storage);
1618 if (!image->raw_data) {
1619 mono_image_storage_close (image->storage);
1620 g_free (image);
1621 if (status)
1622 *status = MONO_IMAGE_IMAGE_INVALID;
1623 return NULL;
1625 iinfo = g_new0 (MonoCLIImageInfo, 1);
1626 image->image_info = iinfo;
1627 image->name = mono_path_resolve_symlinks (fname);
1628 image->filename = g_strdup (image->name);
1629 image->ref_only = refonly;
1630 image->metadata_only = metadata_only;
1631 image->load_from_context = load_from_context;
1632 image->ref_count = 1;
1633 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1634 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1635 #ifdef ENABLE_NETCORE
1636 image->alc = alc;
1637 #endif
1638 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1642 * mono_image_loaded_full:
1643 * \param name path or assembly name of the image to load
1644 * \param refonly Check with respect to reflection-only loads?
1646 * This routine verifies that the given image is loaded.
1647 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1649 * \returns the loaded \c MonoImage, or NULL on failure.
1651 MonoImage *
1652 mono_image_loaded_full (const char *name, gboolean refonly)
1654 MonoImage *result;
1655 MONO_ENTER_GC_UNSAFE;
1656 MonoDomain *domain = mono_domain_get ();
1657 result = mono_image_loaded_internal (mono_domain_default_alc (domain), name, refonly);
1658 MONO_EXIT_GC_UNSAFE;
1659 return result;
1663 * mono_image_loaded_internal:
1664 * \param alc The AssemblyLoadContext that should be checked
1665 * \param name path or assembly name of the image to load
1666 * \param refonly Check with respect to reflection-only loads?
1668 * This routine verifies that the given image is loaded.
1669 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1671 * \returns the loaded \c MonoImage, or NULL on failure.
1673 MonoImage *
1674 mono_image_loaded_internal (MonoAssemblyLoadContext *alc, const char *name, gboolean refonly)
1676 MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
1677 MonoImage *res;
1679 mono_images_lock ();
1680 res = (MonoImage *)g_hash_table_lookup (mono_loaded_images_get_hash (li, refonly), name);
1681 if (!res)
1682 res = (MonoImage *)g_hash_table_lookup (mono_loaded_images_get_by_name_hash (li, refonly), name);
1683 mono_images_unlock ();
1685 return res;
1689 * mono_image_loaded:
1690 * \param name path or assembly name of the image to load
1691 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1692 * \returns the loaded \c MonoImage, or NULL on failure.
1694 MonoImage *
1695 mono_image_loaded (const char *name)
1697 MonoImage *result;
1698 MONO_ENTER_GC_UNSAFE;
1699 MonoDomain *domain = mono_domain_get ();
1700 result = mono_image_loaded_internal (mono_domain_default_alc (domain), name, FALSE);
1701 MONO_EXIT_GC_UNSAFE;
1702 return result;
1705 typedef struct {
1706 MonoImage *res;
1707 const char* guid;
1708 } GuidData;
1710 static void
1711 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1713 GuidData *data = (GuidData *)user_data;
1714 MonoImage *image;
1716 if (data->res)
1717 return;
1718 image = (MonoImage *)val;
1719 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1720 data->res = image;
1723 static MonoImage *
1724 mono_image_loaded_by_guid_internal (const char *guid, gboolean refonly);
1727 * mono_image_loaded_by_guid_full:
1729 * Looks only in the global loaded images hash, will miss assemblies loaded
1730 * into an AssemblyLoadContext.
1732 MonoImage *
1733 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1735 return mono_image_loaded_by_guid_internal (guid, refonly);
1739 * mono_image_loaded_by_guid_internal:
1741 * Do not use. Looks only in the global loaded images hash, will miss Assembly
1742 * Load Contexts.
1744 static MonoImage *
1745 mono_image_loaded_by_guid_internal (const char *guid, gboolean refonly)
1747 #ifndef ENABLE_NETCORE
1748 GuidData data;
1749 GHashTable *loaded_images = mono_loaded_images_get_hash (mono_get_global_loaded_images (), refonly);
1750 data.res = NULL;
1751 data.guid = guid;
1753 mono_images_lock ();
1754 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1755 mono_images_unlock ();
1756 return data.res;
1757 #else
1758 /* TODO: Maybe implement this for netcore by searching only the default ALC of the current domain */
1759 return NULL;
1760 #endif
1764 * mono_image_loaded_by_guid:
1766 * Looks only in the global loaded images hash, will miss assemblies loaded
1767 * into an AssemblyLoadContext.
1769 MonoImage *
1770 mono_image_loaded_by_guid (const char *guid)
1772 return mono_image_loaded_by_guid_internal (guid, FALSE);
1775 static MonoImage *
1776 register_image (MonoLoadedImages *li, MonoImage *image, gboolean *problematic)
1778 MonoImage *image2;
1779 GHashTable *loaded_images = mono_loaded_images_get_hash (li, image->ref_only);
1781 mono_images_lock ();
1782 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1784 if (image2) {
1785 /* Somebody else beat us to it */
1786 mono_image_addref (image2);
1787 mono_images_unlock ();
1788 mono_image_close (image);
1789 return image2;
1792 GHashTable *loaded_images_by_name = mono_loaded_images_get_by_name_hash (li, image->ref_only);
1793 g_hash_table_insert (loaded_images, image->name, image);
1794 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1795 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1796 mono_images_unlock ();
1798 if (mono_is_problematic_image (image)) {
1799 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Registering %s, problematic image '%s'", image->ref_only ? "REFONLY" : "default", image->name);
1800 if (problematic)
1801 *problematic = TRUE;
1803 return image;
1806 MonoImage *
1807 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)
1809 MonoCLIImageInfo *iinfo;
1810 MonoImage *image;
1811 char *datac;
1813 if (!data || !data_len) {
1814 if (status)
1815 *status = MONO_IMAGE_IMAGE_INVALID;
1816 return NULL;
1818 datac = data;
1819 if (need_copy) {
1820 datac = (char *)g_try_malloc (data_len);
1821 if (!datac) {
1822 if (status)
1823 *status = MONO_IMAGE_ERROR_ERRNO;
1824 return NULL;
1826 memcpy (datac, data, data_len);
1829 MonoImageStorage *storage = mono_image_storage_new_raw_data (datac, data_len, need_copy, name);
1830 image = g_new0 (MonoImage, 1);
1831 image->storage = storage;
1832 mono_image_init_raw_data (image, storage);
1833 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1834 iinfo = g_new0 (MonoCLIImageInfo, 1);
1835 image->image_info = iinfo;
1836 image->ref_only = refonly;
1837 image->metadata_only = metadata_only;
1838 image->ref_count = 1;
1839 #ifdef ENABLE_NETCORE
1840 image->alc = alc;
1841 #endif
1843 image = do_mono_image_load (image, status, TRUE, TRUE);
1844 if (image == NULL)
1845 return NULL;
1847 return register_image (mono_alc_get_loaded_images (alc), image, NULL);
1851 * mono_image_open_from_data_with_name:
1853 MonoImage *
1854 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1856 MonoImage *result;
1857 MONO_ENTER_GC_UNSAFE;
1858 MonoDomain *domain = mono_domain_get ();
1859 result = mono_image_open_from_data_internal (mono_domain_default_alc (domain), data, data_len, need_copy, status, refonly, FALSE, name);
1860 MONO_EXIT_GC_UNSAFE;
1861 return result;
1865 * mono_image_open_from_data_full:
1867 MonoImage *
1868 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1870 MonoImage *result;
1871 MONO_ENTER_GC_UNSAFE;
1872 MonoDomain *domain = mono_domain_get ();
1873 result = mono_image_open_from_data_internal (mono_domain_default_alc (domain), data, data_len, need_copy, status, refonly, FALSE, NULL);
1874 MONO_EXIT_GC_UNSAFE;
1875 return result;
1879 * mono_image_open_from_data:
1881 MonoImage *
1882 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1884 MonoImage *result;
1885 MONO_ENTER_GC_UNSAFE;
1886 MonoDomain *domain = mono_domain_get ();
1887 result = mono_image_open_from_data_internal (mono_domain_default_alc (domain), data, data_len, need_copy, status, FALSE, FALSE, NULL);
1888 MONO_EXIT_GC_UNSAFE;
1889 return result;
1892 #ifdef HOST_WIN32
1893 static MonoImageStorage *
1894 mono_image_storage_open_from_module_handle (HMODULE module_handle, const char *fname, gboolean has_entry_point)
1896 char *key = g_strdup (fname);
1897 MonoImageStorage *published_storage = NULL;
1898 if (mono_image_storage_tryaddref (key, &published_storage)) {
1899 g_free (key);
1900 return published_storage;
1903 MonoImageStorage *storage = g_new0 (MonoImageStorage, 1);
1904 mono_refcount_init (storage, mono_image_storage_dtor);
1905 storage->raw_data = (char*) module_handle;
1906 storage->is_module_handle = TRUE;
1907 storage->has_entry_point = has_entry_point;
1909 storage->key = key;
1911 MonoImageStorage *other_storage = NULL;
1912 if (!mono_image_storage_trypublish (storage, &other_storage)) {
1913 mono_image_storage_close (storage);
1914 storage = other_storage;
1916 return storage;
1919 /* fname is not duplicated. */
1920 MonoImage*
1921 mono_image_open_from_module_handle (MonoAssemblyLoadContext *alc, HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1923 MonoImage* image;
1924 MonoCLIImageInfo* iinfo;
1926 MonoImageStorage *storage = mono_image_storage_open_from_module_handle (module_handle, fname, has_entry_point);
1927 image = g_new0 (MonoImage, 1);
1928 image->storage = storage;
1929 mono_image_init_raw_data (image, storage);
1930 iinfo = g_new0 (MonoCLIImageInfo, 1);
1931 image->image_info = iinfo;
1932 image->name = fname;
1933 image->ref_count = has_entry_point ? 0 : 1;
1934 #ifdef ENABLE_NETCORE
1935 image->alc = alc;
1936 #endif
1938 image = do_mono_image_load (image, status, TRUE, TRUE);
1939 if (image == NULL)
1940 return NULL;
1942 return register_image (mono_alc_get_loaded_images (alc), image, NULL);
1944 #endif
1947 * mono_image_open_full:
1949 MonoImage *
1950 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1952 MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ());
1953 return mono_image_open_a_lot (alc, fname, status, refonly, FALSE);
1956 static MonoImage *
1957 mono_image_open_a_lot_parameterized (MonoLoadedImages *li, MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context, gboolean *problematic)
1959 MonoImage *image;
1960 GHashTable *loaded_images = mono_loaded_images_get_hash (li, refonly);
1961 char *absfname;
1963 g_return_val_if_fail (fname != NULL, NULL);
1965 #ifdef HOST_WIN32
1966 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1967 // then assemblies need to be loaded with LoadLibrary:
1968 if (!refonly && coree_module_handle) {
1969 HMODULE module_handle;
1970 gunichar2 *fname_utf16;
1971 DWORD last_error;
1973 absfname = mono_path_resolve_symlinks (fname);
1974 fname_utf16 = NULL;
1976 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1977 mono_images_lock ();
1978 image = (MonoImage*)g_hash_table_lookup (loaded_images, absfname);
1979 if (image) { // Image already loaded
1980 if (!load_from_context && mono_is_problematic_image (image)) {
1981 // If we previously loaded a problematic image, don't
1982 // return it if we're not in LoadFrom context.
1984 // Note: this has an interaction with
1985 // mono_problematic_image_reprobe - at that point we
1986 // have a problematic image opened, but we don't want
1987 // to see it again when we go searching for an image
1988 // to load.
1989 mono_images_unlock ();
1991 if (problematic)
1992 *problematic = TRUE;
1994 return NULL;
1996 g_assert (m_image_is_module_handle (image));
1997 if (m_image_has_entry_point (image) && image->ref_count == 0) {
1998 /* Increment reference count on images loaded outside of the runtime. */
1999 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
2000 /* The image is already loaded because _CorDllMain removes images from the hash. */
2001 module_handle = LoadLibrary (fname_utf16);
2002 g_assert (module_handle == (HMODULE) image->raw_data);
2004 mono_image_addref (image);
2005 mono_images_unlock ();
2006 if (fname_utf16)
2007 g_free (fname_utf16);
2008 g_free (absfname);
2009 return image;
2012 // Image not loaded, load it now
2013 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
2014 module_handle = MonoLoadImage (fname_utf16);
2015 if (status && module_handle == NULL)
2016 last_error = mono_w32error_get_last ();
2018 /* mono_image_open_from_module_handle is called by _CorDllMain. */
2019 image = (MonoImage*)g_hash_table_lookup (loaded_images, absfname);
2020 if (image)
2021 mono_image_addref (image);
2022 mono_images_unlock ();
2024 g_free (fname_utf16);
2026 if (module_handle == NULL) {
2027 g_assert (!image);
2028 g_free (absfname);
2029 if (status) {
2030 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT) {
2031 if (status)
2032 *status = MONO_IMAGE_IMAGE_INVALID;
2033 } else {
2034 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
2035 mono_set_errno (ENOENT);
2036 else
2037 mono_set_errno (0);
2040 return NULL;
2043 if (image) {
2044 g_assert (m_image_is_module_handle (image));
2045 g_assert (m_image_has_entry_point (image));
2046 g_free (absfname);
2047 return image;
2050 return mono_image_open_from_module_handle (alc, module_handle, absfname, FALSE, status);
2052 #endif
2054 absfname = mono_path_resolve_symlinks (fname);
2057 * The easiest solution would be to do all the loading inside the mutex,
2058 * but that would lead to scalability problems. So we let the loading
2059 * happen outside the mutex, and if multiple threads happen to load
2060 * the same image, we discard all but the first copy.
2062 mono_images_lock ();
2063 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
2064 g_free (absfname);
2066 if (image) { // Image already loaded
2067 if (!refonly && !load_from_context && mono_is_problematic_image (image)) {
2068 // If we previously loaded a problematic image, don't
2069 // return it if we're not in LoadFrom context.
2071 // Note: this has an interaction with
2072 // mono_problematic_image_reprobe - at that point we
2073 // have a problematic image opened, but we don't want
2074 // to see it again when we go searching for an image
2075 // to load.
2076 mono_images_unlock ();
2077 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_ASSEMBLY, "Not returning problematic image '%s' refcount=%d", image->name, image->ref_count);
2078 if (problematic)
2079 *problematic = TRUE;
2080 return NULL;
2082 mono_image_addref (image);
2083 mono_images_unlock ();
2084 return image;
2086 mono_images_unlock ();
2088 // Image not loaded, load it now
2089 image = do_mono_image_open (alc, fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
2090 if (image == NULL)
2091 return NULL;
2093 return register_image (li, image, problematic);
2096 MonoImage *
2097 mono_image_open_a_lot (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
2099 MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
2100 return mono_image_open_a_lot_parameterized (li, alc, fname, status, refonly, load_from_context, NULL);
2103 gboolean
2104 mono_is_problematic_file (const char *fname)
2106 MonoImageOpenStatus status;
2107 gboolean problematic = FALSE;
2109 MonoDomain *domain = mono_domain_get ();
2110 MonoAssemblyLoadContext *alc = mono_domain_default_alc (domain);
2111 MonoLoadedImages *li = mono_alc_get_loaded_images (alc);
2112 MonoImage *opened = mono_image_open_a_lot_parameterized (li, alc, fname, &status, FALSE, FALSE, &problematic);
2113 if (opened)
2114 mono_image_close (opened);
2116 return problematic;
2121 * mono_image_open:
2122 * \param fname filename that points to the module we want to open
2123 * \param status An error condition is returned in this field
2124 * \returns An open image of type \c MonoImage or NULL on error.
2125 * The caller holds a temporary reference to the returned image which should be cleared
2126 * when no longer needed by calling \c mono_image_close.
2127 * if NULL, then check the value of \p status for details on the error
2129 MonoImage *
2130 mono_image_open (const char *fname, MonoImageOpenStatus *status)
2132 MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ());
2133 return mono_image_open_a_lot (alc, fname, status, FALSE, FALSE);
2137 * mono_pe_file_open:
2138 * \param fname filename that points to the module we want to open
2139 * \param status An error condition is returned in this field
2140 * \returns An open image of type \c MonoImage or NULL on error. if
2141 * NULL, then check the value of \p status for details on the error.
2142 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
2143 * It's just a PE file loader, used for \c FileVersionInfo. It also does
2144 * not use the image cache.
2146 MonoImage *
2147 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
2149 g_return_val_if_fail (fname != NULL, NULL);
2150 MonoAssemblyLoadContext *alc = mono_domain_default_alc (mono_domain_get ());
2152 return do_mono_image_open (alc, fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
2156 * mono_image_open_raw
2157 * \param fname filename that points to the module we want to open
2158 * \param status An error condition is returned in this field
2159 * \returns an image without loading neither pe or cli data.
2160 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
2162 MonoImage *
2163 mono_image_open_raw (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
2165 g_return_val_if_fail (fname != NULL, NULL);
2167 return do_mono_image_open (alc, fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
2171 * mono_image_open_metadata_only:
2173 * Open an image which contains metadata only without a PE header.
2175 MonoImage *
2176 mono_image_open_metadata_only (MonoAssemblyLoadContext *alc, const char *fname, MonoImageOpenStatus *status)
2178 return do_mono_image_open (alc, fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
2182 * mono_image_fixup_vtable:
2184 void
2185 mono_image_fixup_vtable (MonoImage *image)
2187 #ifdef HOST_WIN32
2188 MonoCLIImageInfo *iinfo;
2189 MonoPEDirEntry *de;
2190 MonoVTableFixup *vtfixup;
2191 int count;
2192 gpointer slot;
2193 guint16 slot_type;
2194 int slot_count;
2196 g_assert (m_image_is_module_handle (image));
2198 iinfo = image->image_info;
2199 de = &iinfo->cli_cli_header.ch_vtable_fixups;
2200 if (!de->rva || !de->size)
2201 return;
2202 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
2203 if (!vtfixup)
2204 return;
2206 count = de->size / sizeof (MonoVTableFixup);
2207 while (count--) {
2208 if (!vtfixup->rva || !vtfixup->count)
2209 continue;
2211 slot = mono_image_rva_map (image, vtfixup->rva);
2212 g_assert (slot);
2213 slot_type = vtfixup->type;
2214 slot_count = vtfixup->count;
2215 if (slot_type & VTFIXUP_TYPE_32BIT)
2216 while (slot_count--) {
2217 *((guint32*) slot) = (guint32)(gsize)mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
2218 slot = ((guint32*) slot) + 1;
2220 else if (slot_type & VTFIXUP_TYPE_64BIT)
2221 while (slot_count--) {
2222 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
2223 slot = ((guint32*) slot) + 1;
2225 else
2226 g_assert_not_reached();
2228 vtfixup++;
2230 #else
2231 g_assert_not_reached();
2232 #endif
2235 static void
2236 free_hash_table (gpointer key, gpointer val, gpointer user_data)
2238 g_hash_table_destroy ((GHashTable*)val);
2242 static void
2243 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
2245 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
2249 static void
2250 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
2252 g_slist_free ((GSList*)val);
2256 * mono_image_addref:
2257 * \param image The image file we wish to add a reference to
2258 * Increases the reference count of an image.
2260 void
2261 mono_image_addref (MonoImage *image)
2263 mono_atomic_inc_i32 (&image->ref_count);
2266 void
2267 mono_dynamic_stream_reset (MonoDynamicStream* stream)
2269 stream->alloc_size = stream->index = stream->offset = 0;
2270 g_free (stream->data);
2271 stream->data = NULL;
2272 if (stream->hash) {
2273 g_hash_table_destroy (stream->hash);
2274 stream->hash = NULL;
2278 static inline void
2279 free_hash (GHashTable *hash)
2281 if (hash)
2282 g_hash_table_destroy (hash);
2285 void
2286 mono_wrapper_caches_free (MonoWrapperCaches *cache)
2288 free_hash (cache->delegate_invoke_cache);
2289 free_hash (cache->delegate_begin_invoke_cache);
2290 free_hash (cache->delegate_end_invoke_cache);
2291 free_hash (cache->runtime_invoke_signature_cache);
2293 free_hash (cache->delegate_abstract_invoke_cache);
2295 free_hash (cache->runtime_invoke_method_cache);
2296 free_hash (cache->managed_wrapper_cache);
2298 free_hash (cache->native_wrapper_cache);
2299 free_hash (cache->native_wrapper_aot_cache);
2300 free_hash (cache->native_wrapper_check_cache);
2301 free_hash (cache->native_wrapper_aot_check_cache);
2303 free_hash (cache->native_func_wrapper_aot_cache);
2304 free_hash (cache->remoting_invoke_cache);
2305 free_hash (cache->synchronized_cache);
2306 free_hash (cache->unbox_wrapper_cache);
2307 free_hash (cache->cominterop_invoke_cache);
2308 free_hash (cache->cominterop_wrapper_cache);
2309 free_hash (cache->thunk_invoke_cache);
2312 static void
2313 mono_image_close_except_pools_all (MonoImage**images, int image_count)
2315 for (int i = 0; i < image_count; ++i) {
2316 if (images [i]) {
2317 if (!mono_image_close_except_pools (images [i]))
2318 images [i] = NULL;
2324 * Returns whether mono_image_close_finish() must be called as well.
2325 * We must unload images in two steps because clearing the domain in
2326 * SGen requires the class metadata to be intact, but we need to free
2327 * the mono_g_hash_tables in case a collection occurs during domain
2328 * unloading and the roots would trip up the GC.
2330 gboolean
2331 mono_image_close_except_pools (MonoImage *image)
2333 int i;
2335 g_return_val_if_fail (image != NULL, FALSE);
2338 if (!mono_loaded_images_remove_image (image))
2339 return FALSE;
2341 #ifdef HOST_WIN32
2342 if (m_image_is_module_handle (image) && m_image_has_entry_point (image)) {
2343 mono_images_lock ();
2344 if (image->ref_count == 0) {
2345 /* Image will be closed by _CorDllMain. */
2346 FreeLibrary ((HMODULE) image->raw_data);
2347 mono_images_unlock ();
2348 return FALSE;
2350 mono_images_unlock ();
2352 #endif
2354 MONO_PROFILER_RAISE (image_unloading, (image));
2356 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
2358 mono_image_invoke_unload_hook (image);
2360 mono_metadata_clean_for_image (image);
2363 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2364 * assemblies, so we can't release these references in mono_assembly_close () since the
2365 * MonoImage might outlive its associated MonoAssembly.
2367 if (image->references && !image_is_dynamic (image)) {
2368 for (i = 0; i < image->nreferences; i++) {
2369 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2370 if (!mono_assembly_close_except_image_pools (image->references [i]))
2371 image->references [i] = NULL;
2374 } else {
2375 if (image->references) {
2376 g_free (image->references);
2377 image->references = NULL;
2381 /* a MonoDynamicImage doesn't have any storage */
2382 g_assert (image_is_dynamic (image) || image->storage != NULL);
2384 if (image->storage && m_image_is_raw_data_allocated (image)) {
2385 /* FIXME: do we need this? (image is disposed anyway) */
2386 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2387 MonoCLIImageInfo *ii = image->image_info;
2389 if ((image->raw_metadata > image->raw_data) &&
2390 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2391 image->raw_metadata = NULL;
2393 for (i = 0; i < ii->cli_section_count; i++)
2394 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2395 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2396 ii->cli_sections [i] = NULL;
2400 if (image->storage)
2401 mono_image_storage_close (image->storage);
2403 if (debug_assembly_unload) {
2404 char *old_name = image->name;
2405 image->name = g_strdup_printf ("%s - UNLOADED", old_name);
2406 g_free (old_name);
2407 } else {
2408 g_free (image->name);
2409 g_free (image->filename);
2410 g_free (image->guid);
2411 g_free (image->version);
2414 if (image->method_cache)
2415 g_hash_table_destroy (image->method_cache);
2416 if (image->methodref_cache)
2417 g_hash_table_destroy (image->methodref_cache);
2418 mono_internal_hash_table_destroy (&image->class_cache);
2419 mono_conc_hashtable_destroy (image->field_cache);
2420 if (image->array_cache) {
2421 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2422 g_hash_table_destroy (image->array_cache);
2424 if (image->szarray_cache)
2425 g_hash_table_destroy (image->szarray_cache);
2426 if (image->ptr_cache)
2427 g_hash_table_destroy (image->ptr_cache);
2428 if (image->name_cache) {
2429 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2430 g_hash_table_destroy (image->name_cache);
2433 free_hash (image->delegate_bound_static_invoke_cache);
2434 free_hash (image->ldfld_wrapper_cache);
2435 free_hash (image->ldflda_wrapper_cache);
2436 free_hash (image->stfld_wrapper_cache);
2437 free_hash (image->isinst_cache);
2438 free_hash (image->castclass_cache);
2439 free_hash (image->icall_wrapper_cache);
2440 free_hash (image->proxy_isinst_cache);
2441 if (image->var_gparam_cache)
2442 mono_conc_hashtable_destroy (image->var_gparam_cache);
2443 if (image->mvar_gparam_cache)
2444 mono_conc_hashtable_destroy (image->mvar_gparam_cache);
2445 free_hash (image->wrapper_param_names);
2446 free_hash (image->pinvoke_scopes);
2447 free_hash (image->pinvoke_scope_filenames);
2448 free_hash (image->native_func_wrapper_cache);
2449 mono_conc_hashtable_destroy (image->typespec_cache);
2450 free_hash (image->weak_field_indexes);
2452 mono_wrapper_caches_free (&image->wrapper_caches);
2454 for (i = 0; i < image->gshared_types_len; ++i)
2455 free_hash (image->gshared_types [i]);
2456 g_free (image->gshared_types);
2458 /* The ownership of signatures is not well defined */
2459 g_hash_table_destroy (image->memberref_signatures);
2460 g_hash_table_destroy (image->method_signatures);
2462 if (image->rgctx_template_hash)
2463 g_hash_table_destroy (image->rgctx_template_hash);
2465 if (image->property_hash)
2466 mono_property_hash_destroy (image->property_hash);
2469 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2470 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2472 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2473 image->reflection_info_unregister_classes = NULL;
2475 if (image->interface_bitset) {
2476 mono_unload_interface_ids (image->interface_bitset);
2477 mono_bitset_free (image->interface_bitset);
2479 if (image->image_info){
2480 MonoCLIImageInfo *ii = image->image_info;
2482 g_free (ii->cli_section_tables);
2483 g_free (ii->cli_sections);
2484 g_free (image->image_info);
2487 mono_image_close_except_pools_all (image->files, image->file_count);
2488 mono_image_close_except_pools_all (image->modules, image->module_count);
2489 g_free (image->modules_loaded);
2491 mono_os_mutex_destroy (&image->szarray_cache_lock);
2492 mono_os_mutex_destroy (&image->lock);
2494 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2495 if (image_is_dynamic (image)) {
2496 /* Dynamic images are GC_MALLOCed */
2497 g_free ((char*)image->module_name);
2498 mono_dynamic_image_free ((MonoDynamicImage*)image);
2501 MONO_PROFILER_RAISE (image_unloaded, (image));
2503 return TRUE;
2506 static void
2507 mono_image_close_all (MonoImage**images, int image_count)
2509 for (int i = 0; i < image_count; ++i) {
2510 if (images [i])
2511 mono_image_close_finish (images [i]);
2513 if (images)
2514 g_free (images);
2517 void
2518 mono_image_close_finish (MonoImage *image)
2520 int i;
2522 if (image->references && !image_is_dynamic (image)) {
2523 for (i = 0; i < image->nreferences; i++) {
2524 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2525 mono_assembly_close_finish (image->references [i]);
2528 g_free (image->references);
2529 image->references = NULL;
2532 mono_image_close_all (image->files, image->file_count);
2533 mono_image_close_all (image->modules, image->module_count);
2535 #ifndef DISABLE_PERFCOUNTERS
2536 /* FIXME: use an explicit subtraction method as soon as it's available */
2537 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2538 #endif
2540 if (!image_is_dynamic (image)) {
2541 if (debug_assembly_unload)
2542 mono_mempool_invalidate (image->mempool);
2543 else {
2544 mono_mempool_destroy (image->mempool);
2545 g_free (image);
2547 } else {
2548 if (debug_assembly_unload)
2549 mono_mempool_invalidate (image->mempool);
2550 else {
2551 mono_mempool_destroy (image->mempool);
2552 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2558 * mono_image_close:
2559 * \param image The image file we wish to close
2560 * Closes an image file, deallocates all memory consumed and
2561 * unmaps all possible sections of the file
2563 void
2564 mono_image_close (MonoImage *image)
2566 if (mono_image_close_except_pools (image))
2567 mono_image_close_finish (image);
2570 /**
2571 * mono_image_strerror:
2572 * \param status an code indicating the result from a recent operation
2573 * \returns a string describing the error
2575 const char *
2576 mono_image_strerror (MonoImageOpenStatus status)
2578 switch (status){
2579 case MONO_IMAGE_OK:
2580 return "success";
2581 case MONO_IMAGE_ERROR_ERRNO:
2582 return strerror (errno);
2583 case MONO_IMAGE_IMAGE_INVALID:
2584 return "File does not contain a valid CIL image";
2585 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2586 return "An assembly was referenced, but could not be found";
2588 return "Internal error";
2591 static gpointer
2592 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2593 guint32 lang_id, gunichar2 *name,
2594 MonoPEResourceDirEntry *entry,
2595 MonoPEResourceDir *root, guint32 level)
2597 gboolean is_string, is_dir;
2598 guint32 name_offset, dir_offset;
2600 /* Level 0 holds a directory entry for each type of resource
2601 * (identified by ID or name).
2603 * Level 1 holds a directory entry for each named resource
2604 * item, and each "anonymous" item of a particular type of
2605 * resource.
2607 * Level 2 holds a directory entry for each language pointing to
2608 * the actual data.
2610 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2611 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2613 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2614 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2616 if(level==0) {
2617 if (is_string)
2618 return NULL;
2619 } else if (level==1) {
2620 if (res_id != name_offset)
2621 return NULL;
2622 #if 0
2623 if(name!=NULL &&
2624 is_string==TRUE && name!=lookup (name_offset)) {
2625 return(NULL);
2627 #endif
2628 } else if (level==2) {
2629 if (is_string || (lang_id != 0 && name_offset != lang_id))
2630 return NULL;
2631 } else {
2632 g_assert_not_reached ();
2635 if (is_dir) {
2636 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2637 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2638 guint32 entries, i;
2640 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2642 for(i=0; i<entries; i++) {
2643 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2644 gpointer ret;
2646 ret=mono_image_walk_resource_tree (info, res_id,
2647 lang_id, name,
2648 sub_entry, root,
2649 level+1);
2650 if(ret!=NULL) {
2651 return(ret);
2655 return(NULL);
2656 } else {
2657 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2658 MonoPEResourceDataEntry *res;
2660 res = g_new0 (MonoPEResourceDataEntry, 1);
2662 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2663 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2664 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2665 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2667 return (res);
2672 * mono_image_lookup_resource:
2673 * \param image the image to look up the resource in
2674 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2675 * \param lang_id The language id.
2676 * \param name the resource name to lookup.
2677 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2678 * of the given resource. The caller should free it using \c g_free when no longer
2679 * needed.
2681 gpointer
2682 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2684 MonoCLIImageInfo *info;
2685 MonoDotNetHeader *header;
2686 MonoPEDatadir *datadir;
2687 MonoPEDirEntry *rsrc;
2688 MonoPEResourceDir *resource_dir;
2689 MonoPEResourceDirEntry *res_entries;
2690 guint32 entries, i;
2692 if(image==NULL) {
2693 return(NULL);
2696 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2698 info = (MonoCLIImageInfo *)image->image_info;
2699 if(info==NULL) {
2700 return(NULL);
2703 header=&info->cli_header;
2704 if(header==NULL) {
2705 return(NULL);
2708 datadir=&header->datadir;
2709 if(datadir==NULL) {
2710 return(NULL);
2713 rsrc=&datadir->pe_resource_table;
2714 if(rsrc==NULL) {
2715 return(NULL);
2718 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2719 if(resource_dir==NULL) {
2720 return(NULL);
2723 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2724 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2726 for(i=0; i<entries; i++) {
2727 MonoPEResourceDirEntry *entry=&res_entries[i];
2728 gpointer ret;
2730 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2731 name, entry, resource_dir,
2733 if(ret!=NULL) {
2734 return(ret);
2738 return(NULL);
2741 /**
2742 * mono_image_get_entry_point:
2743 * \param image the image where the entry point will be looked up.
2744 * Use this routine to determine the metadata token for method that
2745 * has been flagged as the entry point.
2746 * \returns the token for the entry point method in the image
2748 guint32
2749 mono_image_get_entry_point (MonoImage *image)
2751 return image->image_info->cli_cli_header.ch_entry_point;
2755 * mono_image_get_resource:
2756 * \param image the image where the resource will be looked up.
2757 * \param offset The offset to add to the resource
2758 * \param size a pointer to an int where the size of the resource will be stored
2760 * This is a low-level routine that fetches a resource from the
2761 * metadata that starts at a given \p offset. The \p size parameter is
2762 * filled with the data field as encoded in the metadata.
2764 * \returns the pointer to the resource whose offset is \p offset.
2766 const char*
2767 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2769 MonoCLIImageInfo *iinfo = image->image_info;
2770 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2771 const char* data;
2773 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2774 return NULL;
2776 data = mono_image_rva_map (image, ch->ch_resources.rva);
2777 if (!data)
2778 return NULL;
2779 data += offset;
2780 if (size)
2781 *size = read32 (data);
2782 data += 4;
2783 return data;
2786 // Returning NULL with no error set will be interpeted as "not found"
2787 MonoImage*
2788 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2790 char *base_dir, *name;
2791 MonoImage *res;
2792 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2793 const char *fname;
2794 guint32 fname_id;
2796 error_init (error);
2798 if (fileidx < 1 || fileidx > t->rows)
2799 return NULL;
2801 mono_image_lock (image);
2802 if (image->files && image->files [fileidx - 1]) {
2803 mono_image_unlock (image);
2804 return image->files [fileidx - 1];
2806 mono_image_unlock (image);
2808 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2809 fname = mono_metadata_string_heap (image, fname_id);
2810 base_dir = g_path_get_dirname (image->name);
2811 name = g_build_filename (base_dir, fname, NULL);
2812 res = mono_image_open (name, NULL);
2813 if (!res)
2814 goto done;
2816 mono_image_lock (image);
2817 if (image->files && image->files [fileidx - 1]) {
2818 MonoImage *old = res;
2819 res = image->files [fileidx - 1];
2820 mono_image_unlock (image);
2821 mono_image_close (old);
2822 } else {
2823 int i;
2824 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2825 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2826 mono_image_unlock (image);
2827 mono_image_close (res);
2828 return NULL;
2831 for (i = 0; i < res->module_count; ++i) {
2832 if (res->modules [i] && !res->modules [i]->assembly)
2833 res->modules [i]->assembly = image->assembly;
2836 if (!image->files) {
2837 image->files = g_new0 (MonoImage*, t->rows);
2838 image->file_count = t->rows;
2840 image->files [fileidx - 1] = res;
2841 mono_image_unlock (image);
2842 /* vtable fixup can't happen with the image lock held */
2843 #ifdef HOST_WIN32
2844 if (m_image_is_module_handle (res))
2845 mono_image_fixup_vtable (res);
2846 #endif
2849 done:
2850 g_free (name);
2851 g_free (base_dir);
2852 return res;
2856 * mono_image_load_file_for_image:
2858 MonoImage*
2859 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2861 ERROR_DECL (error);
2862 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, error);
2863 mono_error_assert_ok (error);
2864 return result;
2868 * mono_image_get_strong_name:
2869 * \param image a MonoImage
2870 * \param size a \c guint32 pointer, or NULL.
2872 * If the image has a strong name, and \p size is not NULL, the value
2873 * pointed to by size will have the size of the strong name.
2875 * \returns NULL if the image does not have a strong name, or a
2876 * pointer to the public key.
2878 const char*
2879 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2881 MonoCLIImageInfo *iinfo = image->image_info;
2882 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2883 const char* data;
2885 if (!de->size || !de->rva)
2886 return NULL;
2887 data = mono_image_rva_map (image, de->rva);
2888 if (!data)
2889 return NULL;
2890 if (size)
2891 *size = de->size;
2892 return data;
2896 * mono_image_strong_name_position:
2897 * \param image a \c MonoImage
2898 * \param size a \c guint32 pointer, or NULL.
2900 * If the image has a strong name, and \p size is not NULL, the value
2901 * pointed to by size will have the size of the strong name.
2903 * \returns the position within the image file where the strong name
2904 * is stored.
2906 guint32
2907 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2909 MonoCLIImageInfo *iinfo = image->image_info;
2910 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2911 guint32 pos;
2913 if (size)
2914 *size = de->size;
2915 if (!de->size || !de->rva)
2916 return 0;
2917 pos = mono_cli_rva_image_map (image, de->rva);
2918 return pos == INVALID_ADDRESS ? 0 : pos;
2922 * mono_image_get_public_key:
2923 * \param image a \c MonoImage
2924 * \param size a \c guint32 pointer, or NULL.
2926 * This is used to obtain the public key in the \p image.
2928 * If the image has a public key, and \p size is not NULL, the value
2929 * pointed to by size will have the size of the public key.
2931 * \returns NULL if the image does not have a public key, or a pointer
2932 * to the public key.
2934 const char*
2935 mono_image_get_public_key (MonoImage *image, guint32 *size)
2937 const char *pubkey;
2938 guint32 len, tok;
2940 if (image_is_dynamic (image)) {
2941 if (size)
2942 *size = ((MonoDynamicImage*)image)->public_key_len;
2943 return (char*)((MonoDynamicImage*)image)->public_key;
2945 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2946 return NULL;
2947 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2948 if (!tok)
2949 return NULL;
2950 pubkey = mono_metadata_blob_heap (image, tok);
2951 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2952 if (size)
2953 *size = len;
2954 return pubkey;
2958 * mono_image_get_name:
2959 * \param name a \c MonoImage
2960 * \returns the name of the assembly.
2962 const char*
2963 mono_image_get_name (MonoImage *image)
2965 return image->assembly_name;
2969 * mono_image_get_filename:
2970 * \param image a \c MonoImage
2971 * Used to get the filename that hold the actual \c MonoImage
2972 * \returns the filename.
2974 const char*
2975 mono_image_get_filename (MonoImage *image)
2977 return image->name;
2981 * mono_image_get_guid:
2983 const char*
2984 mono_image_get_guid (MonoImage *image)
2986 return image->guid;
2990 * mono_image_get_table_info:
2992 const MonoTableInfo*
2993 mono_image_get_table_info (MonoImage *image, int table_id)
2995 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2996 return NULL;
2997 return &image->tables [table_id];
3001 * mono_image_get_table_rows:
3004 mono_image_get_table_rows (MonoImage *image, int table_id)
3006 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
3007 return 0;
3008 return image->tables [table_id].rows;
3012 * mono_table_info_get_rows:
3015 mono_table_info_get_rows (const MonoTableInfo *table)
3017 return table->rows;
3021 * mono_image_get_assembly:
3022 * \param image the \c MonoImage .
3023 * Use this routine to get the assembly that owns this image.
3024 * \returns the assembly that holds this image.
3026 MonoAssembly*
3027 mono_image_get_assembly (MonoImage *image)
3029 return image->assembly;
3033 * mono_image_is_dynamic:
3034 * \param image the \c MonoImage
3036 * Determines if the given image was created dynamically through the
3037 * \c System.Reflection.Emit API
3038 * \returns TRUE if the image was created dynamically, FALSE if not.
3040 gboolean
3041 mono_image_is_dynamic (MonoImage *image)
3043 return image_is_dynamic (image);
3047 * mono_image_has_authenticode_entry:
3048 * \param image the \c MonoImage
3049 * Use this routine to determine if the image has a Authenticode
3050 * Certificate Table.
3051 * \returns TRUE if the image contains an authenticode entry in the PE
3052 * directory.
3054 gboolean
3055 mono_image_has_authenticode_entry (MonoImage *image)
3057 MonoCLIImageInfo *iinfo = image->image_info;
3058 MonoDotNetHeader *header = &iinfo->cli_header;
3059 if (!header)
3060 return FALSE;
3061 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
3062 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
3063 return ((de->rva != 0) && (de->size > 8));
3066 gpointer
3067 mono_image_alloc (MonoImage *image, guint size)
3069 gpointer res;
3071 #ifndef DISABLE_PERFCOUNTERS
3072 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
3073 #endif
3074 mono_image_lock (image);
3075 res = mono_mempool_alloc (image->mempool, size);
3076 mono_image_unlock (image);
3078 return res;
3081 gpointer
3082 mono_image_alloc0 (MonoImage *image, guint size)
3084 gpointer res;
3086 #ifndef DISABLE_PERFCOUNTERS
3087 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
3088 #endif
3089 mono_image_lock (image);
3090 res = mono_mempool_alloc0 (image->mempool, size);
3091 mono_image_unlock (image);
3093 return res;
3096 char*
3097 mono_image_strdup (MonoImage *image, const char *s)
3099 char *res;
3101 #ifndef DISABLE_PERFCOUNTERS
3102 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (s));
3103 #endif
3104 mono_image_lock (image);
3105 res = mono_mempool_strdup (image->mempool, s);
3106 mono_image_unlock (image);
3108 return res;
3111 char*
3112 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
3114 char *buf;
3115 mono_image_lock (image);
3116 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
3117 mono_image_unlock (image);
3118 #ifndef DISABLE_PERFCOUNTERS
3119 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (buf));
3120 #endif
3121 return buf;
3124 char*
3125 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
3127 char *buf;
3128 va_list args;
3130 va_start (args, format);
3131 buf = mono_image_strdup_vprintf (image, format, args);
3132 va_end (args);
3133 return buf;
3136 GList*
3137 mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
3139 GList *new_list;
3141 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
3142 new_list->data = data;
3143 new_list->prev = list ? list->prev : NULL;
3144 new_list->next = list;
3146 if (new_list->prev)
3147 new_list->prev->next = new_list;
3148 if (list)
3149 list->prev = new_list;
3151 return new_list;
3154 GSList*
3155 mono_g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
3157 GSList *new_list;
3159 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
3160 new_list->data = data;
3161 new_list->next = NULL;
3163 return g_slist_concat (list, new_list);
3166 void
3167 mono_image_lock (MonoImage *image)
3169 mono_locks_os_acquire (&image->lock, ImageDataLock);
3172 void
3173 mono_image_unlock (MonoImage *image)
3175 mono_locks_os_release (&image->lock, ImageDataLock);
3180 * mono_image_property_lookup:
3181 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
3183 * LOCKING: Takes the image lock
3185 gpointer
3186 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
3188 gpointer res;
3190 mono_image_lock (image);
3191 res = mono_property_hash_lookup (image->property_hash, subject, property);
3192 mono_image_unlock (image);
3194 return res;
3198 * mono_image_property_insert:
3199 * Insert a new property \p property with value \p value on \p subject in \p
3200 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
3202 * LOCKING: Takes the image lock
3204 void
3205 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
3207 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
3208 mono_image_lock (image);
3209 mono_property_hash_insert (image->property_hash, subject, property, value);
3210 mono_image_unlock (image);
3214 * mono_image_property_remove:
3215 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
3217 * LOCKING: Takes the image lock
3219 void
3220 mono_image_property_remove (MonoImage *image, gpointer subject)
3222 mono_image_lock (image);
3223 mono_property_hash_remove_object (image->property_hash, subject);
3224 mono_image_unlock (image);
3227 void
3228 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
3230 MonoImage *image = m_class_get_image (klass);
3231 g_assert (image_is_dynamic (image));
3232 mono_image_lock (image);
3233 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
3234 mono_image_unlock (image);