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