Safety check for "diamond dependencies" on netmodules
[mono.git] / mono / metadata / image.c
1 /*
2  * image.c: Routines for manipulating an image stored in an
3  * extended PE/COFF file.
4  * 
5  * Authors:
6  *   Miguel de Icaza (miguel@ximian.com)
7  *   Paolo Molaro (lupus@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  *
12  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13  */
14 #include <config.h>
15 #include <stdio.h>
16 #include <glib.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <string.h>
20 #include "image.h"
21 #include "cil-coff.h"
22 #include "mono-endian.h"
23 #include "tabledefs.h"
24 #include "tokentype.h"
25 #include "metadata-internals.h"
26 #include "profiler-private.h"
27 #include "loader.h"
28 #include "marshal.h"
29 #include "coree.h"
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/utils/mono-logger-internals.h>
32 #include <mono/utils/mono-path.h>
33 #include <mono/utils/mono-mmap.h>
34 #include <mono/utils/mono-io-portability.h>
35 #include <mono/utils/atomic.h>
36 #include <mono/metadata/class-internals.h>
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/object-internals.h>
39 #include <mono/metadata/security-core-clr.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/verify.h>
42 #include <mono/metadata/image-internals.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48
49 #define INVALID_ADDRESS 0xffffffff
50
51 // Amount initially reserved in each image's mempool.
52 // FIXME: This number is arbitrary, a more practical number should be found
53 #define INITIAL_IMAGE_SIZE    512
54
55 /*
56  * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
57  * There are four, for all combinations of [look up by path or assembly name?]
58  * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
59  */
60 enum {
61         IMAGES_HASH_PATH = 0,
62         IMAGES_HASH_PATH_REFONLY = 1,
63         IMAGES_HASH_NAME = 2,
64         IMAGES_HASH_NAME_REFONLY = 3,
65         IMAGES_HASH_COUNT = 4
66 };
67 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
68
69 static GHashTable *
70 get_loaded_images_hash (gboolean refonly)
71 {
72         int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
73         return loaded_images_hashes [idx];
74 }
75
76 static GHashTable *
77 get_loaded_images_by_name_hash (gboolean refonly)
78 {
79         int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
80         return loaded_images_hashes [idx];
81 }
82
83 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
84 // Can be used on modules loaded through either the "file" or "module" mechanism
85 static gboolean
86 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
87 {
88         // Assembly to assign
89         MonoAssembly *assembly = assemblyImage->assembly;
90
91         while (1) {
92                 // Assembly currently assigned
93                 MonoAssembly *assemblyOld = image->assembly;
94                 if (assemblyOld) {
95                         if (assemblyOld == assembly)
96                                 return TRUE;
97                         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);
98                         return FALSE;
99                 }
100                 gpointer result = InterlockedExchangePointer((gpointer *)&image->assembly, assembly);
101                 if (result == assembly)
102                         return TRUE;
103         }
104 }
105
106 static gboolean debug_assembly_unload = FALSE;
107
108 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
109 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
110 static gboolean mutex_inited;
111 static mono_mutex_t images_mutex;
112
113 static void install_pe_loader (void);
114
115 typedef struct ImageUnloadHook ImageUnloadHook;
116 struct ImageUnloadHook {
117         MonoImageUnloadFunc func;
118         gpointer user_data;
119 };
120
121 static GSList *image_unload_hooks;
122
123 void
124 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
125 {
126         ImageUnloadHook *hook;
127         
128         g_return_if_fail (func != NULL);
129
130         hook = g_new0 (ImageUnloadHook, 1);
131         hook->func = func;
132         hook->user_data = user_data;
133         image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
134 }
135
136 void
137 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
138 {
139         GSList *l;
140         ImageUnloadHook *hook;
141
142         for (l = image_unload_hooks; l; l = l->next) {
143                 hook = (ImageUnloadHook *)l->data;
144
145                 if (hook->func == func && hook->user_data == user_data) {
146                         g_free (hook);
147                         image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
148                         break;
149                 }
150         }
151 }
152
153 static void
154 mono_image_invoke_unload_hook (MonoImage *image)
155 {
156         GSList *l;
157         ImageUnloadHook *hook;
158
159         for (l = image_unload_hooks; l; l = l->next) {
160                 hook = (ImageUnloadHook *)l->data;
161
162                 hook->func (image, hook->user_data);
163         }
164 }
165
166 static GSList *image_loaders;
167
168 void
169 mono_install_image_loader (const MonoImageLoader *loader)
170 {
171         image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
172 }
173
174 /* returns offset relative to image->raw_data */
175 guint32
176 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
177 {
178         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
179         const int top = iinfo->cli_section_count;
180         MonoSectionTable *tables = iinfo->cli_section_tables;
181         int i;
182
183         if (image->metadata_only)
184                 return addr;
185
186         for (i = 0; i < top; i++){
187                 if ((addr >= tables->st_virtual_address) &&
188                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
189 #ifdef HOST_WIN32
190                         if (image->is_module_handle)
191                                 return addr;
192 #endif
193                         return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
194                 }
195                 tables++;
196         }
197         return INVALID_ADDRESS;
198 }
199
200 /**
201  * mono_images_rva_map:
202  * @image: a MonoImage
203  * @addr: relative virtual address (RVA)
204  *
205  * This is a low-level routine used by the runtime to map relative
206  * virtual address (RVA) into their location in memory. 
207  *
208  * Returns: the address in memory for the given RVA, or NULL if the
209  * RVA is not valid for this image. 
210  */
211 char *
212 mono_image_rva_map (MonoImage *image, guint32 addr)
213 {
214         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
215         const int top = iinfo->cli_section_count;
216         MonoSectionTable *tables = iinfo->cli_section_tables;
217         int i;
218
219 #ifdef HOST_WIN32
220         if (image->is_module_handle) {
221                 if (addr && addr < image->raw_data_len)
222                         return image->raw_data + addr;
223                 else
224                         return NULL;
225         }
226 #endif
227
228         for (i = 0; i < top; i++){
229                 if ((addr >= tables->st_virtual_address) &&
230                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
231                         if (!iinfo->cli_sections [i]) {
232                                 if (!mono_image_ensure_section_idx (image, i))
233                                         return NULL;
234                         }
235                         return (char*)iinfo->cli_sections [i] +
236                                 (addr - tables->st_virtual_address);
237                 }
238                 tables++;
239         }
240         return NULL;
241 }
242
243 /**
244  * mono_images_init:
245  *
246  *  Initialize the global variables used by this module.
247  */
248 void
249 mono_images_init (void)
250 {
251         mono_os_mutex_init_recursive (&images_mutex);
252
253         int hash_idx;
254         for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
255                 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
256
257         debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
258
259         install_pe_loader ();
260
261         mutex_inited = TRUE;
262 }
263
264 /**
265  * mono_images_cleanup:
266  *
267  *  Free all resources used by this module.
268  */
269 void
270 mono_images_cleanup (void)
271 {
272         GHashTableIter iter;
273         MonoImage *image;
274
275         mono_os_mutex_destroy (&images_mutex);
276
277         // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
278         // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
279         g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
280         while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
281                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
282
283         int hash_idx;
284         for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
285                 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
286
287         mutex_inited = FALSE;
288 }
289
290 /**
291  * mono_image_ensure_section_idx:
292  * @image: The image we are operating on
293  * @section: section number that we will load/map into memory
294  *
295  * This routine makes sure that we have an in-memory copy of
296  * an image section (.text, .rsrc, .data).
297  *
298  * Returns: TRUE on success
299  */
300 int
301 mono_image_ensure_section_idx (MonoImage *image, int section)
302 {
303         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
304         MonoSectionTable *sect;
305         
306         g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
307
308         if (iinfo->cli_sections [section] != NULL)
309                 return TRUE;
310
311         sect = &iinfo->cli_section_tables [section];
312         
313         if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
314                 return FALSE;
315 #ifdef HOST_WIN32
316         if (image->is_module_handle)
317                 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
318         else
319 #endif
320         /* FIXME: we ignore the writable flag since we don't patch the binary */
321         iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
322         return TRUE;
323 }
324
325 /**
326  * mono_image_ensure_section:
327  * @image: The image we are operating on
328  * @section: section name that we will load/map into memory
329  *
330  * This routine makes sure that we have an in-memory copy of
331  * an image section (.text, .rsrc, .data).
332  *
333  * Returns: TRUE on success
334  */
335 int
336 mono_image_ensure_section (MonoImage *image, const char *section)
337 {
338         MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
339         int i;
340         
341         for (i = 0; i < ii->cli_section_count; i++){
342                 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
343                         continue;
344                 
345                 return mono_image_ensure_section_idx (image, i);
346         }
347         return FALSE;
348 }
349
350 static int
351 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
352 {
353         const int top = iinfo->cli_header.coff.coff_sections;
354         int i;
355
356         iinfo->cli_section_count = top;
357         iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
358         iinfo->cli_sections = g_new0 (void *, top);
359         
360         for (i = 0; i < top; i++){
361                 MonoSectionTable *t = &iinfo->cli_section_tables [i];
362
363                 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
364                         return FALSE;
365                 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
366                 offset += sizeof (MonoSectionTable);
367
368 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
369                 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
370                 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
371                 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
372                 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
373                 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
374                 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
375                 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
376                 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
377                 t->st_flags = GUINT32_FROM_LE (t->st_flags);
378 #endif
379                 /* consistency checks here */
380         }
381
382         return TRUE;
383 }
384
385 gboolean
386 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
387 {
388         guint32 offset;
389         
390         offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
391         if (offset == INVALID_ADDRESS)
392                 return FALSE;
393
394         if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
395                 return FALSE;
396         memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
397
398 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
399 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
400 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
401 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
402         SWAP32 (iinfo->cli_cli_header.ch_size);
403         SWAP32 (iinfo->cli_cli_header.ch_flags);
404         SWAP32 (iinfo->cli_cli_header.ch_entry_point);
405         SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
406         SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
407         SWAPPDE (iinfo->cli_cli_header.ch_metadata);
408         SWAPPDE (iinfo->cli_cli_header.ch_resources);
409         SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
410         SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
411         SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
412         SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
413         SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
414         SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
415         SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
416         SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
417         SWAPPDE (iinfo->cli_cli_header.ch_module_image);
418         SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
419         SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
420         SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
421         SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
422 #undef SWAP32
423 #undef SWAP16
424 #undef SWAPPDE
425 #endif
426         /* Catch new uses of the fields that are supposed to be zero */
427
428         if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
429             (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
430             (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
431             (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
432             (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
433             (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
434             (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
435             (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
436             (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
437
438                 /*
439                  * No need to scare people who are testing this, I am just
440                  * labelling this as a LAMESPEC
441                  */
442                 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
443
444         }
445             
446         return TRUE;
447 }
448
449 static gboolean
450 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
451 {
452         guint32 offset, size;
453         guint16 streams;
454         int i;
455         guint32 pad;
456         char *ptr;
457         
458         offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
459         if (offset == INVALID_ADDRESS)
460                 return FALSE;
461
462         size = iinfo->cli_cli_header.ch_metadata.size;
463
464         if (offset + size > image->raw_data_len)
465                 return FALSE;
466         image->raw_metadata = image->raw_data + offset;
467
468         /* 24.2.1: Metadata root starts here */
469         ptr = image->raw_metadata;
470
471         if (strncmp (ptr, "BSJB", 4) == 0){
472                 guint32 version_string_len;
473
474                 ptr += 4;
475                 image->md_version_major = read16 (ptr);
476                 ptr += 2;
477                 image->md_version_minor = read16 (ptr);
478                 ptr += 6;
479
480                 version_string_len = read32 (ptr);
481                 ptr += 4;
482                 image->version = g_strndup (ptr, version_string_len);
483                 ptr += version_string_len;
484                 pad = ptr - image->raw_metadata;
485                 if (pad % 4)
486                         ptr += 4 - (pad % 4);
487         } else
488                 return FALSE;
489
490         /* skip over flags */
491         ptr += 2;
492         
493         streams = read16 (ptr);
494         ptr += 2;
495
496         for (i = 0; i < streams; i++){
497                 if (strncmp (ptr + 8, "#~", 3) == 0){
498                         image->heap_tables.data = image->raw_metadata + read32 (ptr);
499                         image->heap_tables.size = read32 (ptr + 4);
500                         ptr += 8 + 3;
501                 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
502                         image->heap_strings.data = image->raw_metadata + read32 (ptr);
503                         image->heap_strings.size = read32 (ptr + 4);
504                         ptr += 8 + 9;
505                 } else if (strncmp (ptr + 8, "#US", 4) == 0){
506                         image->heap_us.data = image->raw_metadata + read32 (ptr);
507                         image->heap_us.size = read32 (ptr + 4);
508                         ptr += 8 + 4;
509                 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
510                         image->heap_blob.data = image->raw_metadata + read32 (ptr);
511                         image->heap_blob.size = read32 (ptr + 4);
512                         ptr += 8 + 6;
513                 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
514                         image->heap_guid.data = image->raw_metadata + read32 (ptr);
515                         image->heap_guid.size = read32 (ptr + 4);
516                         ptr += 8 + 6;
517                 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
518                         image->heap_tables.data = image->raw_metadata + read32 (ptr);
519                         image->heap_tables.size = read32 (ptr + 4);
520                         ptr += 8 + 3;
521                         image->uncompressed_metadata = TRUE;
522                         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).\n", image->name);
523                 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
524                         image->heap_pdb.data = image->raw_metadata + read32 (ptr);
525                         image->heap_pdb.size = read32 (ptr + 4);
526                         ptr += 8 + 5;
527                 } else {
528                         g_message ("Unknown heap type: %s\n", ptr + 8);
529                         ptr += 8 + strlen (ptr + 8) + 1;
530                 }
531                 pad = ptr - image->raw_metadata;
532                 if (pad % 4)
533                         ptr += 4 - (pad % 4);
534         }
535
536         i = ((MonoImageLoader*)image->loader)->load_tables (image);
537         g_assert (image->heap_guid.data);
538
539         if (!image->metadata_only) {
540                 g_assert (image->heap_guid.size >= 16);
541
542                 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
543         } else {
544                 /* PPDB files have no guid */
545                 guint8 empty_guid [16];
546
547                 memset (empty_guid, 0, sizeof (empty_guid));
548
549                 image->guid = mono_guid_to_string (empty_guid);
550         }
551
552         return i;
553 }
554
555 /*
556  * Load representation of logical metadata tables, from the "#~" stream
557  */
558 static gboolean
559 load_tables (MonoImage *image)
560 {
561         const char *heap_tables = image->heap_tables.data;
562         const guint32 *rows;
563         guint64 valid_mask;
564         int valid = 0, table;
565         int heap_sizes;
566         
567         heap_sizes = heap_tables [6];
568         image->idx_string_wide = ((heap_sizes & 0x01) == 1);
569         image->idx_guid_wide   = ((heap_sizes & 0x02) == 2);
570         image->idx_blob_wide   = ((heap_sizes & 0x04) == 4);
571         
572         valid_mask = read64 (heap_tables + 8);
573         rows = (const guint32 *) (heap_tables + 24);
574         
575         for (table = 0; table < 64; table++){
576                 if ((valid_mask & ((guint64) 1 << table)) == 0){
577                         if (table > MONO_TABLE_LAST)
578                                 continue;
579                         image->tables [table].rows = 0;
580                         continue;
581                 }
582                 if (table > MONO_TABLE_LAST) {
583                         g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
584                 } else {
585                         image->tables [table].rows = read32 (rows);
586                 }
587                 rows++;
588                 valid++;
589         }
590
591         image->tables_base = (heap_tables + 24) + (4 * valid);
592
593         /* They must be the same */
594         g_assert ((const void *) image->tables_base == (const void *) rows);
595
596         mono_metadata_compute_table_bases (image);
597         return TRUE;
598 }
599
600 gboolean
601 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
602 {
603         if (!load_metadata_ptrs (image, iinfo))
604                 return FALSE;
605
606         return load_tables (image);
607 }
608
609 void
610 mono_image_check_for_module_cctor (MonoImage *image)
611 {
612         MonoTableInfo *t, *mt;
613         t = &image->tables [MONO_TABLE_TYPEDEF];
614         mt = &image->tables [MONO_TABLE_METHOD];
615         if (image_is_dynamic (image)) {
616                 /* FIXME: */
617                 image->checked_module_cctor = TRUE;
618                 return;
619         }
620         if (t->rows >= 1) {
621                 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
622                 const char *name = mono_metadata_string_heap (image, nameidx);
623                 if (strcmp (name, "<Module>") == 0) {
624                         guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
625                         guint32 last_method;
626                         if (t->rows > 1)
627                                 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
628                         else 
629                                 last_method = mt->rows;
630                         for (; first_method < last_method; first_method++) {
631                                 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
632                                 name = mono_metadata_string_heap (image, nameidx);
633                                 if (strcmp (name, ".cctor") == 0) {
634                                         image->has_module_cctor = TRUE;
635                                         image->checked_module_cctor = TRUE;
636                                         return;
637                                 }
638                         }
639                 }
640         }
641         image->has_module_cctor = FALSE;
642         image->checked_module_cctor = TRUE;
643 }
644
645 static void
646 load_modules (MonoImage *image)
647 {
648         MonoTableInfo *t;
649
650         if (image->modules)
651                 return;
652
653         t = &image->tables [MONO_TABLE_MODULEREF];
654         image->modules = g_new0 (MonoImage *, t->rows);
655         image->modules_loaded = g_new0 (gboolean, t->rows);
656         image->module_count = t->rows;
657 }
658
659 /**
660  * mono_image_load_module_checked:
661  *
662  *   Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
663  * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
664  */
665 MonoImage*
666 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
667 {
668         MonoTableInfo *t;
669         MonoTableInfo *file_table;
670         int i;
671         char *base_dir;
672         gboolean refonly = image->ref_only;
673         GList *list_iter, *valid_modules = NULL;
674         MonoImageOpenStatus status;
675
676         if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
677                 return NULL;
678         if (image->modules_loaded [idx - 1])
679                 return image->modules [idx - 1];
680
681         file_table = &image->tables [MONO_TABLE_FILE];
682         for (i = 0; i < file_table->rows; i++) {
683                 guint32 cols [MONO_FILE_SIZE];
684                 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
685                 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
686                         continue;
687                 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
688         }
689
690         t = &image->tables [MONO_TABLE_MODULEREF];
691         base_dir = g_path_get_dirname (image->name);
692
693         {
694                 char *module_ref;
695                 const char *name;
696                 guint32 cols [MONO_MODULEREF_SIZE];
697                 /* if there is no file table, we try to load the module... */
698                 int valid = file_table->rows == 0;
699
700                 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
701                 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
702                 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
703                         /* be safe with string dups, but we could just compare string indexes  */
704                         if (strcmp (list_iter->data, name) == 0) {
705                                 valid = TRUE;
706                                 break;
707                         }
708                 }
709                 if (valid) {
710                         module_ref = g_build_filename (base_dir, name, NULL);
711                         MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
712                         if (image->modules [idx - 1]) {
713                                 g_assert(!image->modules [idx - 1]->assembly || image->modules [idx - 1]->assembly == image->assembly);
714                                 image->modules [idx - 1]->assembly = image->assembly;
715
716                                 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
717                                         mono_image_close (moduleImage);
718                                         g_free (module_ref);
719                                         g_free (base_dir);
720                                         g_list_free (valid_modules);
721                                         return NULL;
722                                 }
723
724                                 image->modules [idx - 1] = image;
725
726 #ifdef HOST_WIN32
727                                 if (image->modules [idx - 1]->is_module_handle)
728                                         mono_image_fixup_vtable (image->modules [idx - 1]);
729 #endif
730                                 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
731                         }
732                         g_free (module_ref);
733                 }
734         }
735
736         image->modules_loaded [idx - 1] = TRUE;
737
738         g_free (base_dir);
739         g_list_free (valid_modules);
740
741         return image->modules [idx - 1];
742 }
743
744 MonoImage*
745 mono_image_load_module (MonoImage *image, int idx)
746 {
747         MonoError error;
748         mono_error_init (&error);
749         MonoImage *result = mono_image_load_module_checked (image, idx, &error);
750         mono_error_assert_ok (&error);
751         mono_error_cleanup (&error);
752         return result;
753 }
754
755 static gpointer
756 class_key_extract (gpointer value)
757 {
758         MonoClass *klass = (MonoClass *)value;
759
760         return GUINT_TO_POINTER (klass->type_token);
761 }
762
763 static gpointer*
764 class_next_value (gpointer value)
765 {
766         MonoClass *klass = (MonoClass *)value;
767
768         return (gpointer*)&klass->next_class_cache;
769 }
770
771 void
772 mono_image_init (MonoImage *image)
773 {
774         mono_os_mutex_init_recursive (&image->lock);
775         mono_os_mutex_init_recursive (&image->szarray_cache_lock);
776
777         image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
778         mono_internal_hash_table_init (&image->class_cache,
779                                        g_direct_hash,
780                                        class_key_extract,
781                                        class_next_value);
782         image->field_cache = mono_conc_hashtable_new (NULL, NULL);
783
784         image->typespec_cache = g_hash_table_new (NULL, NULL);
785         image->memberref_signatures = g_hash_table_new (NULL, NULL);
786         image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
787         image->method_signatures = g_hash_table_new (NULL, NULL);
788
789         image->property_hash = mono_property_hash_new ();
790 }
791
792 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
793 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
794 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
795 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
796 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
797 #else
798 #define SWAP64(x)
799 #define SWAP32(x)
800 #define SWAP16(x)
801 #define SWAPPDE(x)
802 #endif
803
804 /*
805  * Returns < 0 to indicate an error.
806  */
807 static int
808 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
809 {
810         MonoDotNetHeader64 header64;
811
812 #ifdef HOST_WIN32
813         if (!image->is_module_handle)
814 #endif
815         if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
816                 return -1;
817
818         memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
819
820         if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
821                 return -1;
822
823         /* endian swap the fields common between PE and PE+ */
824         SWAP32 (header->coff.coff_time);
825         SWAP32 (header->coff.coff_symptr);
826         SWAP32 (header->coff.coff_symcount);
827         SWAP16 (header->coff.coff_machine);
828         SWAP16 (header->coff.coff_sections);
829         SWAP16 (header->coff.coff_opt_header_size);
830         SWAP16 (header->coff.coff_attributes);
831         /* MonoPEHeader */
832         SWAP32 (header->pe.pe_code_size);
833         SWAP32 (header->pe.pe_uninit_data_size);
834         SWAP32 (header->pe.pe_rva_entry_point);
835         SWAP32 (header->pe.pe_rva_code_base);
836         SWAP32 (header->pe.pe_rva_data_base);
837         SWAP16 (header->pe.pe_magic);
838
839         /* now we are ready for the basic tests */
840
841         if (header->pe.pe_magic == 0x10B) {
842                 offset += sizeof (MonoDotNetHeader);
843                 SWAP32 (header->pe.pe_data_size);
844                 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
845                         return -1;
846
847                 SWAP32  (header->nt.pe_image_base);     /* must be 0x400000 */
848                 SWAP32  (header->nt.pe_stack_reserve);
849                 SWAP32  (header->nt.pe_stack_commit);
850                 SWAP32  (header->nt.pe_heap_reserve);
851                 SWAP32  (header->nt.pe_heap_commit);
852         } else if (header->pe.pe_magic == 0x20B) {
853                 /* PE32+ file format */
854                 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
855                         return -1;
856                 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
857                 offset += sizeof (MonoDotNetHeader64);
858                 /* copy the fields already swapped. the last field, pe_data_size, is missing */
859                 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
860                 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
861                  * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
862                  */
863                 SWAP64  (header64.nt.pe_image_base);
864                 header->nt.pe_image_base = header64.nt.pe_image_base;
865                 SWAP64  (header64.nt.pe_stack_reserve);
866                 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
867                 SWAP64  (header64.nt.pe_stack_commit);
868                 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
869                 SWAP64  (header64.nt.pe_heap_reserve);
870                 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
871                 SWAP64  (header64.nt.pe_heap_commit);
872                 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
873
874                 header->nt.pe_section_align = header64.nt.pe_section_align;
875                 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
876                 header->nt.pe_os_major = header64.nt.pe_os_major;
877                 header->nt.pe_os_minor = header64.nt.pe_os_minor;
878                 header->nt.pe_user_major = header64.nt.pe_user_major;
879                 header->nt.pe_user_minor = header64.nt.pe_user_minor;
880                 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
881                 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
882                 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
883                 header->nt.pe_image_size = header64.nt.pe_image_size;
884                 header->nt.pe_header_size = header64.nt.pe_header_size;
885                 header->nt.pe_checksum = header64.nt.pe_checksum;
886                 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
887                 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
888                 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
889                 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
890
891                 /* copy the datadir */
892                 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
893         } else {
894                 return -1;
895         }
896
897         /* MonoPEHeaderNT: not used yet */
898         SWAP32  (header->nt.pe_section_align);       /* must be 8192 */
899         SWAP32  (header->nt.pe_file_alignment);      /* must be 512 or 4096 */
900         SWAP16  (header->nt.pe_os_major);            /* must be 4 */
901         SWAP16  (header->nt.pe_os_minor);            /* must be 0 */
902         SWAP16  (header->nt.pe_user_major);
903         SWAP16  (header->nt.pe_user_minor);
904         SWAP16  (header->nt.pe_subsys_major);
905         SWAP16  (header->nt.pe_subsys_minor);
906         SWAP32  (header->nt.pe_reserved_1);
907         SWAP32  (header->nt.pe_image_size);
908         SWAP32  (header->nt.pe_header_size);
909         SWAP32  (header->nt.pe_checksum);
910         SWAP16  (header->nt.pe_subsys_required);
911         SWAP16  (header->nt.pe_dll_flags);
912         SWAP32  (header->nt.pe_loader_flags);
913         SWAP32  (header->nt.pe_data_dir_count);
914
915         /* MonoDotNetHeader: mostly unused */
916         SWAPPDE (header->datadir.pe_export_table);
917         SWAPPDE (header->datadir.pe_import_table);
918         SWAPPDE (header->datadir.pe_resource_table);
919         SWAPPDE (header->datadir.pe_exception_table);
920         SWAPPDE (header->datadir.pe_certificate_table);
921         SWAPPDE (header->datadir.pe_reloc_table);
922         SWAPPDE (header->datadir.pe_debug);
923         SWAPPDE (header->datadir.pe_copyright);
924         SWAPPDE (header->datadir.pe_global_ptr);
925         SWAPPDE (header->datadir.pe_tls_table);
926         SWAPPDE (header->datadir.pe_load_config_table);
927         SWAPPDE (header->datadir.pe_bound_import);
928         SWAPPDE (header->datadir.pe_iat);
929         SWAPPDE (header->datadir.pe_delay_import_desc);
930         SWAPPDE (header->datadir.pe_cli_header);
931         SWAPPDE (header->datadir.pe_reserved);
932
933 #ifdef HOST_WIN32
934         if (image->is_module_handle)
935                 image->raw_data_len = header->nt.pe_image_size;
936 #endif
937
938         return offset;
939 }
940
941 gboolean
942 mono_image_load_pe_data (MonoImage *image)
943 {
944         return ((MonoImageLoader*)image->loader)->load_pe_data (image);
945 }
946
947 static gboolean
948 pe_image_load_pe_data (MonoImage *image)
949 {
950         MonoCLIImageInfo *iinfo;
951         MonoDotNetHeader *header;
952         MonoMSDOSHeader msdos;
953         gint32 offset = 0;
954
955         iinfo = (MonoCLIImageInfo *)image->image_info;
956         header = &iinfo->cli_header;
957
958 #ifdef HOST_WIN32
959         if (!image->is_module_handle)
960 #endif
961         if (offset + sizeof (msdos) > image->raw_data_len)
962                 goto invalid_image;
963         memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
964         
965         if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
966                 goto invalid_image;
967         
968         msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
969
970         offset = msdos.pe_offset;
971
972         offset = do_load_header (image, header, offset);
973         if (offset < 0)
974                 goto invalid_image;
975
976         /*
977          * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
978          * we skip this test.
979         if (header->coff.coff_machine != 0x14c)
980                 goto invalid_image;
981         */
982
983 #if 0
984         /*
985          * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
986          * which produces binaries with 7.0.  From Sergey:
987          *
988          * The reason is that MSVC7 uses traditional compile/link
989          * sequence for CIL executables, and VS.NET (and Framework
990          * SDK) includes linker version 7, that puts 7.0 in this
991          * field.  That's why it's currently not possible to load VC
992          * binaries with Mono.  This field is pretty much meaningless
993          * anyway (what linker?).
994          */
995         if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
996                 goto invalid_image;
997 #endif
998
999         /*
1000          * FIXME: byte swap all addresses here for header.
1001          */
1002         
1003         if (!load_section_tables (image, iinfo, offset))
1004                 goto invalid_image;
1005
1006         return TRUE;
1007
1008 invalid_image:
1009         return FALSE;
1010 }
1011
1012 gboolean
1013 mono_image_load_cli_data (MonoImage *image)
1014 {
1015         return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1016 }
1017
1018 static gboolean
1019 pe_image_load_cli_data (MonoImage *image)
1020 {
1021         MonoCLIImageInfo *iinfo;
1022         MonoDotNetHeader *header;
1023
1024         iinfo = (MonoCLIImageInfo *)image->image_info;
1025         header = &iinfo->cli_header;
1026
1027         /* Load the CLI header */
1028         if (!mono_image_load_cli_header (image, iinfo))
1029                 return FALSE;
1030
1031         if (!mono_image_load_metadata (image, iinfo))
1032                 return FALSE;
1033
1034         return TRUE;
1035 }
1036
1037 void
1038 mono_image_load_names (MonoImage *image)
1039 {
1040         /* modules don't have an assembly table row */
1041         if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1042                 image->assembly_name = mono_metadata_string_heap (image, 
1043                         mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1044                                         0, MONO_ASSEMBLY_NAME));
1045         }
1046
1047         /* Portable pdb images don't have a MODULE row */
1048         if (image->tables [MONO_TABLE_MODULE].rows) {
1049                 image->module_name = mono_metadata_string_heap (image,
1050                         mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1051                                         0, MONO_MODULE_NAME));
1052         }
1053 }
1054
1055 static gboolean
1056 pe_image_load_tables (MonoImage *image)
1057 {
1058         return TRUE;
1059 }
1060
1061 static gboolean
1062 pe_image_match (MonoImage *image)
1063 {
1064         if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1065                 return TRUE;
1066         return FALSE;
1067 }
1068
1069 static const MonoImageLoader pe_loader = {
1070         pe_image_match,
1071         pe_image_load_pe_data,
1072         pe_image_load_cli_data,
1073         pe_image_load_tables,
1074 };
1075
1076 static void
1077 install_pe_loader (void)
1078 {
1079         mono_install_image_loader (&pe_loader);
1080 }
1081
1082 static MonoImage *
1083 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1084                     gboolean care_about_cli, gboolean care_about_pecoff)
1085 {
1086         MonoCLIImageInfo *iinfo;
1087         MonoDotNetHeader *header;
1088         GSList *errors = NULL;
1089         GSList *l;
1090
1091         mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1092
1093         mono_image_init (image);
1094
1095         iinfo = (MonoCLIImageInfo *)image->image_info;
1096         header = &iinfo->cli_header;
1097
1098         if (!image->metadata_only) {
1099                 for (l = image_loaders; l; l = l->next) {
1100                         MonoImageLoader *loader = (MonoImageLoader *)l->data;
1101                         if (loader->match (image)) {
1102                                 image->loader = loader;
1103                                 break;
1104                         }
1105                 }
1106                 if (!image->loader) {
1107                         if (status)
1108                                 *status = MONO_IMAGE_IMAGE_INVALID;
1109                         goto invalid_image;
1110                 }
1111
1112                 if (status)
1113                         *status = MONO_IMAGE_IMAGE_INVALID;
1114
1115                 if (care_about_pecoff == FALSE)
1116                         goto done;
1117
1118                 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1119                         goto invalid_image;
1120
1121                 if (!mono_image_load_pe_data (image))
1122                         goto invalid_image;
1123         } else {
1124                 image->loader = (MonoImageLoader*)&pe_loader;
1125         }
1126
1127         if (care_about_cli == FALSE) {
1128                 goto done;
1129         }
1130
1131         if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1132                 goto invalid_image;
1133
1134         if (!mono_image_load_cli_data (image))
1135                 goto invalid_image;
1136
1137         if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1138                 goto invalid_image;
1139
1140         mono_image_load_names (image);
1141
1142         load_modules (image);
1143
1144 done:
1145         mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1146         if (status)
1147                 *status = MONO_IMAGE_OK;
1148
1149         return image;
1150
1151 invalid_image:
1152         if (errors) {
1153                 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1154                 g_warning ("Could not load image %s due to %s", image->name, info->message);
1155                 mono_free_verify_list (errors);
1156         }
1157         mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1158         mono_image_close (image);
1159         return NULL;
1160 }
1161
1162 static MonoImage *
1163 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1164                                         gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1165 {
1166         MonoCLIImageInfo *iinfo;
1167         MonoImage *image;
1168         MonoFileMap *filed;
1169
1170         if ((filed = mono_file_map_open (fname)) == NULL){
1171                 if (IS_PORTABILITY_SET) {
1172                         gchar *ffname = mono_portability_find_file (fname, TRUE);
1173                         if (ffname) {
1174                                 filed = mono_file_map_open (ffname);
1175                                 g_free (ffname);
1176                         }
1177                 }
1178
1179                 if (filed == NULL) {
1180                         if (status)
1181                                 *status = MONO_IMAGE_ERROR_ERRNO;
1182                         return NULL;
1183                 }
1184         }
1185
1186         image = g_new0 (MonoImage, 1);
1187         image->raw_buffer_used = TRUE;
1188         image->raw_data_len = mono_file_map_size (filed);
1189         image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1190 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1191         if (!image->raw_data) {
1192                 image->fileio_used = TRUE;
1193                 image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1194         }
1195 #endif
1196         if (!image->raw_data) {
1197                 mono_file_map_close (filed);
1198                 g_free (image);
1199                 if (status)
1200                         *status = MONO_IMAGE_IMAGE_INVALID;
1201                 return NULL;
1202         }
1203         iinfo = g_new0 (MonoCLIImageInfo, 1);
1204         image->image_info = iinfo;
1205         image->name = mono_path_resolve_symlinks (fname);
1206         image->ref_only = refonly;
1207         image->metadata_only = metadata_only;
1208         image->ref_count = 1;
1209         /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1210         image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1211
1212         mono_file_map_close (filed);
1213         return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1214 }
1215
1216 /**
1217  * mono_image_loaded:
1218  * @name: path or assembly name of the image to load
1219  * @refonly: Check with respect to reflection-only loads?
1220  *
1221  * This routine verifies that the given image is loaded.
1222  * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1223  *
1224  * Returns: the loaded MonoImage, or NULL on failure.
1225  */
1226 MonoImage *
1227 mono_image_loaded_full (const char *name, gboolean refonly)
1228 {
1229         MonoImage *res;
1230
1231         mono_images_lock ();
1232         res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1233         if (!res)
1234                 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1235         mono_images_unlock ();
1236
1237         return res;
1238 }
1239
1240 /**
1241  * mono_image_loaded:
1242  * @name: path or assembly name of the image to load
1243  *
1244  * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1245  *
1246  * Returns: the loaded MonoImage, or NULL on failure.
1247  */
1248 MonoImage *
1249 mono_image_loaded (const char *name)
1250 {
1251         return mono_image_loaded_full (name, FALSE);
1252 }
1253
1254 typedef struct {
1255         MonoImage *res;
1256         const char* guid;
1257 } GuidData;
1258
1259 static void
1260 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1261 {
1262         GuidData *data = (GuidData *)user_data;
1263         MonoImage *image;
1264
1265         if (data->res)
1266                 return;
1267         image = (MonoImage *)val;
1268         if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1269                 data->res = image;
1270 }
1271
1272 MonoImage *
1273 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1274 {
1275         GuidData data;
1276         GHashTable *loaded_images = get_loaded_images_hash (refonly);
1277         data.res = NULL;
1278         data.guid = guid;
1279
1280         mono_images_lock ();
1281         g_hash_table_foreach (loaded_images, find_by_guid, &data);
1282         mono_images_unlock ();
1283         return data.res;
1284 }
1285
1286 MonoImage *
1287 mono_image_loaded_by_guid (const char *guid)
1288 {
1289         return mono_image_loaded_by_guid_full (guid, FALSE);
1290 }
1291
1292 static MonoImage *
1293 register_image (MonoImage *image)
1294 {
1295         MonoImage *image2;
1296         GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1297
1298         mono_images_lock ();
1299         image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1300
1301         if (image2) {
1302                 /* Somebody else beat us to it */
1303                 mono_image_addref (image2);
1304                 mono_images_unlock ();
1305                 mono_image_close (image);
1306                 return image2;
1307         }
1308
1309         GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1310         g_hash_table_insert (loaded_images, image->name, image);
1311         if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1312                 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1313         mono_images_unlock ();
1314
1315         return image;
1316 }
1317
1318 MonoImage *
1319 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1320 {
1321         MonoCLIImageInfo *iinfo;
1322         MonoImage *image;
1323         char *datac;
1324
1325         if (!data || !data_len) {
1326                 if (status)
1327                         *status = MONO_IMAGE_IMAGE_INVALID;
1328                 return NULL;
1329         }
1330         datac = data;
1331         if (need_copy) {
1332                 datac = (char *)g_try_malloc (data_len);
1333                 if (!datac) {
1334                         if (status)
1335                                 *status = MONO_IMAGE_ERROR_ERRNO;
1336                         return NULL;
1337                 }
1338                 memcpy (datac, data, data_len);
1339         }
1340
1341         image = g_new0 (MonoImage, 1);
1342         image->raw_data = datac;
1343         image->raw_data_len = data_len;
1344         image->raw_data_allocated = need_copy;
1345         image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1346         iinfo = g_new0 (MonoCLIImageInfo, 1);
1347         image->image_info = iinfo;
1348         image->ref_only = refonly;
1349         image->metadata_only = metadata_only;
1350         image->ref_count = 1;
1351
1352         image = do_mono_image_load (image, status, TRUE, TRUE);
1353         if (image == NULL)
1354                 return NULL;
1355
1356         return register_image (image);
1357 }
1358
1359 MonoImage *
1360 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1361 {
1362         return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1363 }
1364
1365 MonoImage *
1366 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1367 {
1368   return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1369 }
1370
1371 MonoImage *
1372 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1373 {
1374         return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1375 }
1376
1377 #ifdef HOST_WIN32
1378 /* fname is not duplicated. */
1379 MonoImage*
1380 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1381 {
1382         MonoImage* image;
1383         MonoCLIImageInfo* iinfo;
1384
1385         image = g_new0 (MonoImage, 1);
1386         image->raw_data = (char*) module_handle;
1387         image->is_module_handle = TRUE;
1388         iinfo = g_new0 (MonoCLIImageInfo, 1);
1389         image->image_info = iinfo;
1390         image->name = fname;
1391         image->ref_count = has_entry_point ? 0 : 1;
1392         image->has_entry_point = has_entry_point;
1393
1394         image = do_mono_image_load (image, status, TRUE, TRUE);
1395         if (image == NULL)
1396                 return NULL;
1397
1398         return register_image (image);
1399 }
1400 #endif
1401
1402 MonoImage *
1403 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1404 {
1405         MonoImage *image;
1406         GHashTable *loaded_images = get_loaded_images_hash (refonly);
1407         char *absfname;
1408         
1409         g_return_val_if_fail (fname != NULL, NULL);
1410         
1411 #ifdef HOST_WIN32
1412         // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1413         // then assemblies need to be loaded with LoadLibrary:
1414         if (!refonly && coree_module_handle) {
1415                 HMODULE module_handle;
1416                 guint16 *fname_utf16;
1417                 DWORD last_error;
1418
1419                 absfname = mono_path_resolve_symlinks (fname);
1420                 fname_utf16 = NULL;
1421
1422                 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1423                 mono_images_lock ();
1424                 image = g_hash_table_lookup (loaded_images, absfname);
1425                 if (image) { // Image already loaded
1426                         g_assert (image->is_module_handle);
1427                         if (image->has_entry_point && image->ref_count == 0) {
1428                                 /* Increment reference count on images loaded outside of the runtime. */
1429                                 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1430                                 /* The image is already loaded because _CorDllMain removes images from the hash. */
1431                                 module_handle = LoadLibrary (fname_utf16);
1432                                 g_assert (module_handle == (HMODULE) image->raw_data);
1433                         }
1434                         mono_image_addref (image);
1435                         mono_images_unlock ();
1436                         if (fname_utf16)
1437                                 g_free (fname_utf16);
1438                         g_free (absfname);
1439                         return image;
1440                 }
1441
1442                 // Image not loaded, load it now
1443                 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1444                 module_handle = MonoLoadImage (fname_utf16);
1445                 if (status && module_handle == NULL)
1446                         last_error = GetLastError ();
1447
1448                 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1449                 image = g_hash_table_lookup (loaded_images, absfname);
1450                 if (image)
1451                         mono_image_addref (image);
1452                 mono_images_unlock ();
1453
1454                 g_free (fname_utf16);
1455
1456                 if (module_handle == NULL) {
1457                         g_assert (!image);
1458                         g_free (absfname);
1459                         if (status) {
1460                                 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1461                                         *status = MONO_IMAGE_IMAGE_INVALID;
1462                                 else {
1463                                         if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1464                                                 errno = ENOENT;
1465                                         else
1466                                                 errno = 0;
1467                                 }
1468                         }
1469                         return NULL;
1470                 }
1471
1472                 if (image) {
1473                         g_assert (image->is_module_handle);
1474                         g_assert (image->has_entry_point);
1475                         g_free (absfname);
1476                         return image;
1477                 }
1478
1479                 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1480         }
1481 #endif
1482
1483         absfname = mono_path_canonicalize (fname);
1484
1485         /*
1486          * The easiest solution would be to do all the loading inside the mutex,
1487          * but that would lead to scalability problems. So we let the loading
1488          * happen outside the mutex, and if multiple threads happen to load
1489          * the same image, we discard all but the first copy.
1490          */
1491         mono_images_lock ();
1492         image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1493         g_free (absfname);
1494
1495         if (image) { // Image already loaded
1496                 mono_image_addref (image);
1497                 mono_images_unlock ();
1498                 return image;
1499         }
1500         mono_images_unlock ();
1501
1502         // Image not loaded, load it now
1503         image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1504         if (image == NULL)
1505                 return NULL;
1506
1507         return register_image (image);
1508 }
1509
1510 /**
1511  * mono_image_open:
1512  * @fname: filename that points to the module we want to open
1513  * @status: An error condition is returned in this field
1514  *
1515  * Returns: An open image of type %MonoImage or NULL on error. 
1516  * The caller holds a temporary reference to the returned image which should be cleared 
1517  * when no longer needed by calling mono_image_close ().
1518  * if NULL, then check the value of @status for details on the error
1519  */
1520 MonoImage *
1521 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1522 {
1523         return mono_image_open_full (fname, status, FALSE);
1524 }
1525
1526 /**
1527  * mono_pe_file_open:
1528  * @fname: filename that points to the module we want to open
1529  * @status: An error condition is returned in this field
1530  *
1531  * Returns: An open image of type %MonoImage or NULL on error.  if
1532  * NULL, then check the value of @status for details on the error.
1533  * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1534  * It's just a PE file loader, used for FileVersionInfo.  It also does
1535  * not use the image cache.
1536  */
1537 MonoImage *
1538 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1539 {
1540         g_return_val_if_fail (fname != NULL, NULL);
1541         
1542         return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1543 }
1544
1545 /**
1546  * mono_image_open_raw
1547  * @fname: filename that points to the module we want to open
1548  * @status: An error condition is returned in this field
1549  * 
1550  * Returns an image without loading neither pe or cli data.
1551  * 
1552  * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.  
1553  */
1554 MonoImage *
1555 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1556 {
1557         g_return_val_if_fail (fname != NULL, NULL);
1558         
1559         return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1560 }
1561
1562 /*
1563  * mono_image_open_metadata_only:
1564  *
1565  *   Open an image which contains metadata only without a PE header.
1566  */
1567 MonoImage *
1568 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1569 {
1570         return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1571 }
1572
1573 void
1574 mono_image_fixup_vtable (MonoImage *image)
1575 {
1576 #ifdef HOST_WIN32
1577         MonoCLIImageInfo *iinfo;
1578         MonoPEDirEntry *de;
1579         MonoVTableFixup *vtfixup;
1580         int count;
1581         gpointer slot;
1582         guint16 slot_type;
1583         int slot_count;
1584
1585         g_assert (image->is_module_handle);
1586
1587         iinfo = image->image_info;
1588         de = &iinfo->cli_cli_header.ch_vtable_fixups;
1589         if (!de->rva || !de->size)
1590                 return;
1591         vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1592         if (!vtfixup)
1593                 return;
1594         
1595         count = de->size / sizeof (MonoVTableFixup);
1596         while (count--) {
1597                 if (!vtfixup->rva || !vtfixup->count)
1598                         continue;
1599
1600                 slot = mono_image_rva_map (image, vtfixup->rva);
1601                 g_assert (slot);
1602                 slot_type = vtfixup->type;
1603                 slot_count = vtfixup->count;
1604                 if (slot_type & VTFIXUP_TYPE_32BIT)
1605                         while (slot_count--) {
1606                                 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1607                                 slot = ((guint32*) slot) + 1;
1608                         }
1609                 else if (slot_type & VTFIXUP_TYPE_64BIT)
1610                         while (slot_count--) {
1611                                 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1612                                 slot = ((guint32*) slot) + 1;
1613                         }
1614                 else
1615                         g_assert_not_reached();
1616
1617                 vtfixup++;
1618         }
1619 #else
1620         g_assert_not_reached();
1621 #endif
1622 }
1623
1624 static void
1625 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1626 {
1627         g_hash_table_destroy ((GHashTable*)val);
1628 }
1629
1630 /*
1631 static void
1632 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1633 {
1634         mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1635 }
1636 */
1637
1638 static void
1639 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1640 {
1641         g_slist_free ((GSList*)val);
1642 }
1643
1644 /**
1645  * mono_image_addref:
1646  * @image: The image file we wish to add a reference to
1647  *
1648  *  Increases the reference count of an image.
1649  */
1650 void
1651 mono_image_addref (MonoImage *image)
1652 {
1653         InterlockedIncrement (&image->ref_count);
1654 }       
1655
1656 void
1657 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1658 {
1659         stream->alloc_size = stream->index = stream->offset = 0;
1660         g_free (stream->data);
1661         stream->data = NULL;
1662         if (stream->hash) {
1663                 g_hash_table_destroy (stream->hash);
1664                 stream->hash = NULL;
1665         }
1666 }
1667
1668 static inline void
1669 free_hash (GHashTable *hash)
1670 {
1671         if (hash)
1672                 g_hash_table_destroy (hash);
1673 }
1674
1675 void
1676 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1677 {
1678         free_hash (cache->delegate_invoke_cache);
1679         free_hash (cache->delegate_begin_invoke_cache);
1680         free_hash (cache->delegate_end_invoke_cache);
1681         free_hash (cache->runtime_invoke_cache);
1682         free_hash (cache->runtime_invoke_vtype_cache);
1683         
1684         free_hash (cache->delegate_abstract_invoke_cache);
1685
1686         free_hash (cache->runtime_invoke_direct_cache);
1687         free_hash (cache->managed_wrapper_cache);
1688
1689         free_hash (cache->native_wrapper_cache);
1690         free_hash (cache->native_wrapper_aot_cache);
1691         free_hash (cache->native_wrapper_check_cache);
1692         free_hash (cache->native_wrapper_aot_check_cache);
1693
1694         free_hash (cache->native_func_wrapper_aot_cache);
1695         free_hash (cache->remoting_invoke_cache);
1696         free_hash (cache->synchronized_cache);
1697         free_hash (cache->unbox_wrapper_cache);
1698         free_hash (cache->cominterop_invoke_cache);
1699         free_hash (cache->cominterop_wrapper_cache);
1700         free_hash (cache->thunk_invoke_cache);
1701 }
1702
1703 static void
1704 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1705 {
1706         for (int i = 0; i < image_count; ++i) {
1707                 if (images [i]) {
1708                         if (!mono_image_close_except_pools (images [i]))
1709                                 images [i] = NULL;
1710                 }
1711         }
1712 }
1713
1714 /*
1715  * Returns whether mono_image_close_finish() must be called as well.
1716  * We must unload images in two steps because clearing the domain in
1717  * SGen requires the class metadata to be intact, but we need to free
1718  * the mono_g_hash_tables in case a collection occurs during domain
1719  * unloading and the roots would trip up the GC.
1720  */
1721 gboolean
1722 mono_image_close_except_pools (MonoImage *image)
1723 {
1724         MonoImage *image2;
1725         GHashTable *loaded_images, *loaded_images_by_name;
1726         int i;
1727
1728         g_return_val_if_fail (image != NULL, FALSE);
1729
1730         /*
1731          * Atomically decrement the refcount and remove ourselves from the hash tables, so
1732          * register_image () can't grab an image which is being closed.
1733          */
1734         mono_images_lock ();
1735
1736         if (InterlockedDecrement (&image->ref_count) > 0) {
1737                 mono_images_unlock ();
1738                 return FALSE;
1739         }
1740
1741         loaded_images         = get_loaded_images_hash (image->ref_only);
1742         loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1743         image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1744         if (image == image2) {
1745                 /* This is not true if we are called from mono_image_open () */
1746                 g_hash_table_remove (loaded_images, image->name);
1747         }
1748         if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1749                 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);     
1750
1751         mono_images_unlock ();
1752
1753 #ifdef HOST_WIN32
1754         if (image->is_module_handle && image->has_entry_point) {
1755                 mono_images_lock ();
1756                 if (image->ref_count == 0) {
1757                         /* Image will be closed by _CorDllMain. */
1758                         FreeLibrary ((HMODULE) image->raw_data);
1759                         mono_images_unlock ();
1760                         return FALSE;
1761                 }
1762                 mono_images_unlock ();
1763         }
1764 #endif
1765
1766         mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1767
1768         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1769
1770         mono_image_invoke_unload_hook (image);
1771
1772         mono_metadata_clean_for_image (image);
1773
1774         /*
1775          * The caches inside a MonoImage might refer to metadata which is stored in referenced 
1776          * assemblies, so we can't release these references in mono_assembly_close () since the
1777          * MonoImage might outlive its associated MonoAssembly.
1778          */
1779         if (image->references && !image_is_dynamic (image)) {
1780                 for (i = 0; i < image->nreferences; i++) {
1781                         if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1782                                 if (!mono_assembly_close_except_image_pools (image->references [i]))
1783                                         image->references [i] = NULL;
1784                         }
1785                 }
1786         } else {
1787                 if (image->references) {
1788                         g_free (image->references);
1789                         image->references = NULL;
1790                 }
1791         }
1792
1793 #ifdef HOST_WIN32
1794         mono_images_lock ();
1795         if (image->is_module_handle && !image->has_entry_point)
1796                 FreeLibrary ((HMODULE) image->raw_data);
1797         mono_images_unlock ();
1798 #endif
1799
1800         if (image->raw_buffer_used) {
1801                 if (image->raw_data != NULL) {
1802 #ifndef HOST_WIN32
1803                         if (image->fileio_used)
1804                                 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1805                         else
1806 #endif
1807                                 mono_file_unmap (image->raw_data, image->raw_data_handle);
1808                 }
1809         }
1810         
1811         if (image->raw_data_allocated) {
1812                 /* FIXME: do we need this? (image is disposed anyway) */
1813                 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1814                 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1815
1816                 if ((image->raw_metadata > image->raw_data) &&
1817                         (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1818                         image->raw_metadata = NULL;
1819
1820                 for (i = 0; i < ii->cli_section_count; i++)
1821                         if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1822                                 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1823                                 ii->cli_sections [i] = NULL;
1824
1825                 g_free (image->raw_data);
1826         }
1827
1828         if (debug_assembly_unload) {
1829                 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1830         } else {
1831                 g_free (image->name);
1832                 g_free (image->guid);
1833                 g_free (image->version);
1834         }
1835
1836         if (image->method_cache)
1837                 g_hash_table_destroy (image->method_cache);
1838         if (image->methodref_cache)
1839                 g_hash_table_destroy (image->methodref_cache);
1840         mono_internal_hash_table_destroy (&image->class_cache);
1841         mono_conc_hashtable_destroy (image->field_cache);
1842         if (image->array_cache) {
1843                 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1844                 g_hash_table_destroy (image->array_cache);
1845         }
1846         if (image->szarray_cache)
1847                 g_hash_table_destroy (image->szarray_cache);
1848         if (image->ptr_cache)
1849                 g_hash_table_destroy (image->ptr_cache);
1850         if (image->name_cache) {
1851                 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1852                 g_hash_table_destroy (image->name_cache);
1853         }
1854
1855         free_hash (image->delegate_bound_static_invoke_cache);
1856         free_hash (image->runtime_invoke_vcall_cache);
1857         free_hash (image->ldfld_wrapper_cache);
1858         free_hash (image->ldflda_wrapper_cache);
1859         free_hash (image->stfld_wrapper_cache);
1860         free_hash (image->isinst_cache);
1861         free_hash (image->castclass_cache);
1862         free_hash (image->icall_wrapper_cache);
1863         free_hash (image->proxy_isinst_cache);
1864         free_hash (image->var_cache_slow);
1865         free_hash (image->mvar_cache_slow);
1866         free_hash (image->var_cache_constrained);
1867         free_hash (image->mvar_cache_constrained);
1868         free_hash (image->wrapper_param_names);
1869         free_hash (image->pinvoke_scopes);
1870         free_hash (image->pinvoke_scope_filenames);
1871         free_hash (image->native_func_wrapper_cache);
1872         free_hash (image->typespec_cache);
1873
1874         mono_wrapper_caches_free (&image->wrapper_caches);
1875
1876         for (i = 0; i < image->gshared_types_len; ++i)
1877                 free_hash (image->gshared_types [i]);
1878         g_free (image->gshared_types);
1879
1880         /* The ownership of signatures is not well defined */
1881         g_hash_table_destroy (image->memberref_signatures);
1882         g_hash_table_destroy (image->helper_signatures);
1883         g_hash_table_destroy (image->method_signatures);
1884
1885         if (image->rgctx_template_hash)
1886                 g_hash_table_destroy (image->rgctx_template_hash);
1887
1888         if (image->property_hash)
1889                 mono_property_hash_destroy (image->property_hash);
1890
1891         /*
1892         reflection_info_unregister_classes is only required by dynamic images, which will not be properly
1893         cleared during shutdown as we don't perform regular appdomain unload for the root one.
1894         */
1895         g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
1896         image->reflection_info_unregister_classes = NULL;
1897
1898         if (image->interface_bitset) {
1899                 mono_unload_interface_ids (image->interface_bitset);
1900                 mono_bitset_free (image->interface_bitset);
1901         }
1902         if (image->image_info){
1903                 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1904
1905                 if (ii->cli_section_tables)
1906                         g_free (ii->cli_section_tables);
1907                 if (ii->cli_sections)
1908                         g_free (ii->cli_sections);
1909                 g_free (image->image_info);
1910         }
1911
1912         mono_image_close_except_pools_all (image->files, image->file_count);
1913         mono_image_close_except_pools_all (image->modules, image->module_count);
1914         if (image->modules_loaded)
1915                 g_free (image->modules_loaded);
1916
1917         mono_os_mutex_destroy (&image->szarray_cache_lock);
1918         mono_os_mutex_destroy (&image->lock);
1919
1920         /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
1921         if (image_is_dynamic (image)) {
1922                 /* Dynamic images are GC_MALLOCed */
1923                 g_free ((char*)image->module_name);
1924                 mono_dynamic_image_free ((MonoDynamicImage*)image);
1925         }
1926
1927         mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
1928
1929         return TRUE;
1930 }
1931
1932 static void
1933 mono_image_close_all (MonoImage**images, int image_count)
1934 {
1935         for (int i = 0; i < image_count; ++i) {
1936                 if (images [i])
1937                         mono_image_close_finish (images [i]);
1938         }
1939         if (images)
1940                 g_free (images);
1941 }
1942
1943 void
1944 mono_image_close_finish (MonoImage *image)
1945 {
1946         int i;
1947
1948         if (image->references && !image_is_dynamic (image)) {
1949                 for (i = 0; i < image->nreferences; i++) {
1950                         if (image->references [i] && image->references [i] != REFERENCE_MISSING)
1951                                 mono_assembly_close_finish (image->references [i]);
1952                 }
1953
1954                 g_free (image->references);
1955                 image->references = NULL;
1956         }
1957
1958         mono_image_close_all (image->files, image->file_count);
1959         mono_image_close_all (image->modules, image->module_count);
1960
1961 #ifndef DISABLE_PERFCOUNTERS
1962         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
1963 #endif
1964
1965         if (!image_is_dynamic (image)) {
1966                 if (debug_assembly_unload)
1967                         mono_mempool_invalidate (image->mempool);
1968                 else {
1969                         mono_mempool_destroy (image->mempool);
1970                         g_free (image);
1971                 }
1972         } else {
1973                 if (debug_assembly_unload)
1974                         mono_mempool_invalidate (image->mempool);
1975                 else {
1976                         mono_mempool_destroy (image->mempool);
1977                         mono_dynamic_image_free_image ((MonoDynamicImage*)image);
1978                 }
1979         }
1980 }
1981
1982 /**
1983  * mono_image_close:
1984  * @image: The image file we wish to close
1985  *
1986  * Closes an image file, deallocates all memory consumed and
1987  * unmaps all possible sections of the file
1988  */
1989 void
1990 mono_image_close (MonoImage *image)
1991 {
1992         if (mono_image_close_except_pools (image))
1993                 mono_image_close_finish (image);
1994 }
1995
1996 /** 
1997  * mono_image_strerror:
1998  * @status: an code indicating the result from a recent operation
1999  *
2000  * Returns: a string describing the error
2001  */
2002 const char *
2003 mono_image_strerror (MonoImageOpenStatus status)
2004 {
2005         switch (status){
2006         case MONO_IMAGE_OK:
2007                 return "success";
2008         case MONO_IMAGE_ERROR_ERRNO:
2009                 return strerror (errno);
2010         case MONO_IMAGE_IMAGE_INVALID:
2011                 return "File does not contain a valid CIL image";
2012         case MONO_IMAGE_MISSING_ASSEMBLYREF:
2013                 return "An assembly was referenced, but could not be found";
2014         }
2015         return "Internal error";
2016 }
2017
2018 static gpointer
2019 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2020                                guint32 lang_id, gunichar2 *name,
2021                                MonoPEResourceDirEntry *entry,
2022                                MonoPEResourceDir *root, guint32 level)
2023 {
2024         gboolean is_string, is_dir;
2025         guint32 name_offset, dir_offset;
2026
2027         /* Level 0 holds a directory entry for each type of resource
2028          * (identified by ID or name).
2029          *
2030          * Level 1 holds a directory entry for each named resource
2031          * item, and each "anonymous" item of a particular type of
2032          * resource.
2033          *
2034          * Level 2 holds a directory entry for each language pointing to
2035          * the actual data.
2036          */
2037         is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2038         name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2039
2040         is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2041         dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2042
2043         if(level==0) {
2044                 if (is_string)
2045                         return NULL;
2046         } else if (level==1) {
2047                 if (res_id != name_offset)
2048                         return NULL;
2049 #if 0
2050                 if(name!=NULL &&
2051                    is_string==TRUE && name!=lookup (name_offset)) {
2052                         return(NULL);
2053                 }
2054 #endif
2055         } else if (level==2) {
2056                 if (is_string || (lang_id != 0 && name_offset != lang_id))
2057                         return NULL;
2058         } else {
2059                 g_assert_not_reached ();
2060         }
2061
2062         if (is_dir) {
2063                 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2064                 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2065                 guint32 entries, i;
2066
2067                 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2068
2069                 for(i=0; i<entries; i++) {
2070                         MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2071                         gpointer ret;
2072                         
2073                         ret=mono_image_walk_resource_tree (info, res_id,
2074                                                            lang_id, name,
2075                                                            sub_entry, root,
2076                                                            level+1);
2077                         if(ret!=NULL) {
2078                                 return(ret);
2079                         }
2080                 }
2081
2082                 return(NULL);
2083         } else {
2084                 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2085                 MonoPEResourceDataEntry *res;
2086
2087                 res = g_new0 (MonoPEResourceDataEntry, 1);
2088
2089                 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2090                 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2091                 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2092                 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2093
2094                 return (res);
2095         }
2096 }
2097
2098 /**
2099  * mono_image_lookup_resource:
2100  * @image: the image to look up the resource in
2101  * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2102  * @lang_id: The language id.
2103  * @name: the resource name to lookup.
2104  *
2105  * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2106  * of the given resource. The caller should free it using g_free () when no longer
2107  * needed.
2108  */
2109 gpointer
2110 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2111 {
2112         MonoCLIImageInfo *info;
2113         MonoDotNetHeader *header;
2114         MonoPEDatadir *datadir;
2115         MonoPEDirEntry *rsrc;
2116         MonoPEResourceDir *resource_dir;
2117         MonoPEResourceDirEntry *res_entries;
2118         guint32 entries, i;
2119
2120         if(image==NULL) {
2121                 return(NULL);
2122         }
2123
2124         mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2125
2126         info = (MonoCLIImageInfo *)image->image_info;
2127         if(info==NULL) {
2128                 return(NULL);
2129         }
2130
2131         header=&info->cli_header;
2132         if(header==NULL) {
2133                 return(NULL);
2134         }
2135
2136         datadir=&header->datadir;
2137         if(datadir==NULL) {
2138                 return(NULL);
2139         }
2140
2141         rsrc=&datadir->pe_resource_table;
2142         if(rsrc==NULL) {
2143                 return(NULL);
2144         }
2145
2146         resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2147         if(resource_dir==NULL) {
2148                 return(NULL);
2149         }
2150
2151         entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2152         res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2153         
2154         for(i=0; i<entries; i++) {
2155                 MonoPEResourceDirEntry *entry=&res_entries[i];
2156                 gpointer ret;
2157                 
2158                 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2159                                                    name, entry, resource_dir,
2160                                                    0);
2161                 if(ret!=NULL) {
2162                         return(ret);
2163                 }
2164         }
2165
2166         return(NULL);
2167 }
2168
2169 /** 
2170  * mono_image_get_entry_point:
2171  * @image: the image where the entry point will be looked up.
2172  *
2173  * Use this routine to determine the metadata token for method that
2174  * has been flagged as the entry point.
2175  *
2176  * Returns: the token for the entry point method in the image
2177  */
2178 guint32
2179 mono_image_get_entry_point (MonoImage *image)
2180 {
2181         return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2182 }
2183
2184 /**
2185  * mono_image_get_resource:
2186  * @image: the image where the resource will be looked up.
2187  * @offset: The offset to add to the resource
2188  * @size: a pointer to an int where the size of the resource will be stored
2189  *
2190  * This is a low-level routine that fetches a resource from the
2191  * metadata that starts at a given @offset.  The @size parameter is
2192  * filled with the data field as encoded in the metadata.
2193  *
2194  * Returns: the pointer to the resource whose offset is @offset.
2195  */
2196 const char*
2197 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2198 {
2199         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2200         MonoCLIHeader *ch = &iinfo->cli_cli_header;
2201         const char* data;
2202
2203         if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2204                 return NULL;
2205         
2206         data = mono_image_rva_map (image, ch->ch_resources.rva);
2207         if (!data)
2208                 return NULL;
2209         data += offset;
2210         if (size)
2211                 *size = read32 (data);
2212         data += 4;
2213         return data;
2214 }
2215
2216 // Returning NULL with no error set will be interpeted as "not found"
2217 MonoImage*
2218 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2219 {
2220         char *base_dir, *name;
2221         MonoImage *res;
2222         MonoTableInfo  *t = &image->tables [MONO_TABLE_FILE];
2223         const char *fname;
2224         guint32 fname_id;
2225
2226         if (fileidx < 1 || fileidx > t->rows)
2227                 return NULL;
2228
2229         mono_image_lock (image);
2230         if (image->files && image->files [fileidx - 1]) {
2231                 mono_image_unlock (image);
2232                 return image->files [fileidx - 1];
2233         }
2234         mono_image_unlock (image);
2235
2236         fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2237         fname = mono_metadata_string_heap (image, fname_id);
2238         base_dir = g_path_get_dirname (image->name);
2239         name = g_build_filename (base_dir, fname, NULL);
2240         res = mono_image_open (name, NULL);
2241         if (!res)
2242                 goto done;
2243
2244         mono_image_lock (image);
2245         if (image->files && image->files [fileidx - 1]) {
2246                 MonoImage *old = res;
2247                 res = image->files [fileidx - 1];
2248                 mono_image_unlock (image);
2249                 mono_image_close (old);
2250         } else {
2251                 int i;
2252                 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2253                 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2254                         mono_image_unlock (image);
2255                         mono_image_close (res);
2256                         return NULL;
2257                 }
2258
2259                 for (i = 0; i < res->module_count; ++i) {
2260                         if (res->modules [i] && !res->modules [i]->assembly)
2261                                 res->modules [i]->assembly = image->assembly;
2262                 }
2263
2264                 if (!image->files) {
2265                         image->files = g_new0 (MonoImage*, t->rows);
2266                         image->file_count = t->rows;
2267                 }
2268                 image->files [fileidx - 1] = res;
2269                 mono_image_unlock (image);
2270                 /* vtable fixup can't happen with the image lock held */
2271 #ifdef HOST_WIN32
2272                 if (res->is_module_handle)
2273                         mono_image_fixup_vtable (res);
2274 #endif
2275         }
2276
2277 done:
2278         g_free (name);
2279         g_free (base_dir);
2280         return res;
2281 }
2282
2283 MonoImage*
2284 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2285 {
2286         MonoError error;
2287         mono_error_init (&error);
2288         MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2289         mono_error_assert_ok (&error);
2290         mono_error_cleanup (&error);
2291         return result;
2292 }
2293
2294 /**
2295  * mono_image_get_strong_name:
2296  * @image: a MonoImage
2297  * @size: a guint32 pointer, or NULL.
2298  *
2299  * If the image has a strong name, and @size is not NULL, the value
2300  * pointed to by size will have the size of the strong name.
2301  *
2302  * Returns: NULL if the image does not have a strong name, or a
2303  * pointer to the public key.
2304  */
2305 const char*
2306 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2307 {
2308         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2309         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2310         const char* data;
2311
2312         if (!de->size || !de->rva)
2313                 return NULL;
2314         data = mono_image_rva_map (image, de->rva);
2315         if (!data)
2316                 return NULL;
2317         if (size)
2318                 *size = de->size;
2319         return data;
2320 }
2321
2322 /**
2323  * mono_image_strong_name_position:
2324  * @image: a MonoImage
2325  * @size: a guint32 pointer, or NULL.
2326  *
2327  * If the image has a strong name, and @size is not NULL, the value
2328  * pointed to by size will have the size of the strong name.
2329  *
2330  * Returns: the position within the image file where the strong name
2331  * is stored.
2332  */
2333 guint32
2334 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2335 {
2336         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2337         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2338         guint32 pos;
2339
2340         if (size)
2341                 *size = de->size;
2342         if (!de->size || !de->rva)
2343                 return 0;
2344         pos = mono_cli_rva_image_map (image, de->rva);
2345         return pos == INVALID_ADDRESS ? 0 : pos;
2346 }
2347
2348 /**
2349  * mono_image_get_public_key:
2350  * @image: a MonoImage
2351  * @size: a guint32 pointer, or NULL.
2352  *
2353  * This is used to obtain the public key in the @image.
2354  * 
2355  * If the image has a public key, and @size is not NULL, the value
2356  * pointed to by size will have the size of the public key.
2357  * 
2358  * Returns: NULL if the image does not have a public key, or a pointer
2359  * to the public key.
2360  */
2361 const char*
2362 mono_image_get_public_key (MonoImage *image, guint32 *size)
2363 {
2364         const char *pubkey;
2365         guint32 len, tok;
2366
2367         if (image_is_dynamic (image)) {
2368                 if (size)
2369                         *size = ((MonoDynamicImage*)image)->public_key_len;
2370                 return (char*)((MonoDynamicImage*)image)->public_key;
2371         }
2372         if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2373                 return NULL;
2374         tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2375         if (!tok)
2376                 return NULL;
2377         pubkey = mono_metadata_blob_heap (image, tok);
2378         len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2379         if (size)
2380                 *size = len;
2381         return pubkey;
2382 }
2383
2384 /**
2385  * mono_image_get_name:
2386  * @name: a MonoImage
2387  *
2388  * Returns: the name of the assembly.
2389  */
2390 const char*
2391 mono_image_get_name (MonoImage *image)
2392 {
2393         return image->assembly_name;
2394 }
2395
2396 /**
2397  * mono_image_get_filename:
2398  * @image: a MonoImage
2399  *
2400  * Used to get the filename that hold the actual MonoImage
2401  *
2402  * Returns: the filename.
2403  */
2404 const char*
2405 mono_image_get_filename (MonoImage *image)
2406 {
2407         return image->name;
2408 }
2409
2410 const char*
2411 mono_image_get_guid (MonoImage *image)
2412 {
2413         return image->guid;
2414 }
2415
2416 const MonoTableInfo*
2417 mono_image_get_table_info (MonoImage *image, int table_id)
2418 {
2419         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2420                 return NULL;
2421         return &image->tables [table_id];
2422 }
2423
2424 int
2425 mono_image_get_table_rows (MonoImage *image, int table_id)
2426 {
2427         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2428                 return 0;
2429         return image->tables [table_id].rows;
2430 }
2431
2432 int
2433 mono_table_info_get_rows (const MonoTableInfo *table)
2434 {
2435         return table->rows;
2436 }
2437
2438 /**
2439  * mono_image_get_assembly:
2440  * @image: the MonoImage.
2441  *
2442  * Use this routine to get the assembly that owns this image.
2443  *
2444  * Returns: the assembly that holds this image.
2445  */
2446 MonoAssembly* 
2447 mono_image_get_assembly (MonoImage *image)
2448 {
2449         return image->assembly;
2450 }
2451
2452 /**
2453  * mono_image_is_dynamic:
2454  * @image: the MonoImage
2455  *
2456  * Determines if the given image was created dynamically through the
2457  * System.Reflection.Emit API
2458  *
2459  * Returns: TRUE if the image was created dynamically, FALSE if not.
2460  */
2461 gboolean
2462 mono_image_is_dynamic (MonoImage *image)
2463 {
2464         return image_is_dynamic (image);
2465 }
2466
2467 /**
2468  * mono_image_has_authenticode_entry:
2469  * @image: the MonoImage
2470  *
2471  * Use this routine to determine if the image has a Authenticode
2472  * Certificate Table.
2473  *
2474  * Returns: TRUE if the image contains an authenticode entry in the PE
2475  * directory.
2476  */
2477 gboolean
2478 mono_image_has_authenticode_entry (MonoImage *image)
2479 {
2480         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2481         MonoDotNetHeader *header = &iinfo->cli_header;
2482         MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2483         // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2484         return ((de->rva != 0) && (de->size > 8));
2485 }
2486
2487 gpointer
2488 mono_image_alloc (MonoImage *image, guint size)
2489 {
2490         gpointer res;
2491
2492 #ifndef DISABLE_PERFCOUNTERS
2493         mono_perfcounters->loader_bytes += size;
2494 #endif
2495         mono_image_lock (image);
2496         res = mono_mempool_alloc (image->mempool, size);
2497         mono_image_unlock (image);
2498
2499         return res;
2500 }
2501
2502 gpointer
2503 mono_image_alloc0 (MonoImage *image, guint size)
2504 {
2505         gpointer res;
2506
2507 #ifndef DISABLE_PERFCOUNTERS
2508         mono_perfcounters->loader_bytes += size;
2509 #endif
2510         mono_image_lock (image);
2511         res = mono_mempool_alloc0 (image->mempool, size);
2512         mono_image_unlock (image);
2513
2514         return res;
2515 }
2516
2517 char*
2518 mono_image_strdup (MonoImage *image, const char *s)
2519 {
2520         char *res;
2521
2522 #ifndef DISABLE_PERFCOUNTERS
2523         mono_perfcounters->loader_bytes += strlen (s);
2524 #endif
2525         mono_image_lock (image);
2526         res = mono_mempool_strdup (image->mempool, s);
2527         mono_image_unlock (image);
2528
2529         return res;
2530 }
2531
2532 GList*
2533 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2534 {
2535         GList *new_list;
2536         
2537         new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2538         new_list->data = data;
2539         new_list->prev = list ? list->prev : NULL;
2540     new_list->next = list;
2541
2542     if (new_list->prev)
2543             new_list->prev->next = new_list;
2544     if (list)
2545             list->prev = new_list;
2546
2547         return new_list;
2548 }
2549
2550 GSList*
2551 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2552 {
2553         GSList *new_list;
2554
2555         new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2556         new_list->data = data;
2557         new_list->next = NULL;
2558
2559         return g_slist_concat (list, new_list);
2560 }
2561
2562 void
2563 mono_image_lock (MonoImage *image)
2564 {
2565         mono_locks_os_acquire (&image->lock, ImageDataLock);
2566 }
2567
2568 void
2569 mono_image_unlock (MonoImage *image)
2570 {
2571         mono_locks_os_release (&image->lock, ImageDataLock);
2572 }
2573
2574
2575 /**
2576  * mono_image_property_lookup:
2577  *
2578  * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2579  *
2580  * LOCKING: Takes the image lock
2581  */
2582 gpointer 
2583 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2584 {
2585         gpointer res;
2586
2587         mono_image_lock (image);
2588         res = mono_property_hash_lookup (image->property_hash, subject, property);
2589         mono_image_unlock (image);
2590
2591         return res;
2592 }
2593
2594 /**
2595  * mono_image_property_insert:
2596  *
2597  * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2598  *
2599  * LOCKING: Takes the image lock
2600  */
2601 void
2602 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2603 {
2604         mono_image_lock (image);
2605         mono_property_hash_insert (image->property_hash, subject, property, value);
2606         mono_image_unlock (image);
2607 }
2608
2609 /**
2610  * mono_image_property_remove:
2611  *
2612  * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2613  *
2614  * LOCKING: Takes the image lock
2615  */
2616 void
2617 mono_image_property_remove (MonoImage *image, gpointer subject)
2618 {
2619         mono_image_lock (image);
2620         mono_property_hash_remove_object (image->property_hash, subject);
2621         mono_image_unlock (image);
2622 }
2623
2624 void
2625 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2626 {
2627         MonoImage *image = klass->image;
2628         g_assert (image_is_dynamic (image));
2629         mono_image_lock (image);
2630         image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2631         mono_image_unlock (image);
2632 }
2633
2634 // This is support for the mempool reference tracking feature in checked-build, but lives in image.c due to use of static variables of this file.
2635
2636 /**
2637  * mono_find_image_owner:
2638  *
2639  * Find the image, if any, which a given pointer is located in the memory of.
2640  */
2641 MonoImage *
2642 mono_find_image_owner (void *ptr)
2643 {
2644         mono_images_lock ();
2645
2646         MonoImage *owner = NULL;
2647
2648         // Iterate over both by-path image hashes
2649         const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2650         int hash_idx;
2651         for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2652         {
2653                 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2654                 GHashTableIter iter;
2655                 MonoImage *image;
2656
2657                 // Iterate over images within a hash
2658                 g_hash_table_iter_init (&iter, target);
2659                 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2660                 {
2661                         mono_image_lock (image);
2662                         if (mono_mempool_contains_addr (image->mempool, ptr))
2663                                 owner = image;
2664                         mono_image_unlock (image);
2665                 }
2666         }
2667
2668         mono_images_unlock ();
2669
2670         return owner;
2671 }