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