[runtime] Blacklist System.Threading.Overlapped nugets
[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 = mono_conc_hashtable_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         SYS_THREADING_OVERLAPPED = 7, //System.Threading.Overlapped
1127 } IgnoredAssemblyNames;
1128
1129 typedef struct {
1130         int hash;
1131         int assembly_name;
1132         const char guid [40];
1133 } IgnoredAssembly;
1134
1135 typedef struct {
1136         int assembly_name;
1137         guint16 major, minor, build, revision;
1138 } IgnoredAssemblyVersion;
1139
1140 const char *ignored_assemblies_file_names[] = {
1141         "System.Runtime.InteropServices.RuntimeInformation.dll",
1142         "System.Globalization.Extensions.dll",
1143         "System.IO.Compression.dll",
1144         "System.Net.Http.dll",
1145         "System.Text.Encoding.CodePages.dll",
1146         "System.Reflection.DispatchProxy.dll",
1147         "System.Threading.Overlapped.dll",
1148         "System.ValueTuple.dll"
1149 };
1150
1151 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR)     { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1152
1153 static const IgnoredAssembly ignored_assemblies [] = {
1154         IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1155         IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1156         IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1157         IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1158         IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1159         IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1160         IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1161         IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1162         IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1163         IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1164         IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1165         IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1166         IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1167         IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1168         IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1169         IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1170         IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1171         IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1172         IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46"),
1173         IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
1174 };
1175
1176
1177 const char *ignored_assemblies_names[] = {
1178         "System.Runtime.InteropServices.RuntimeInformation",
1179         "System.Globalization.Extensions",
1180         "System.IO.Compression",
1181         "System.Net.Http",
1182         "System.Text.Encoding.CodePages",
1183         "System.Reflection.DispatchProxy",
1184         "System.Threading.Overlapped",
1185         "System.ValueTuple"
1186 };
1187
1188 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1189
1190 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1191         IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1192         IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1193         IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1194         IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1195         IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1196         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1197         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1198         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1199         IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 0, 0),
1200         IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 1, 0),
1201         IGNORED_ASM_VER (SYS_REF_DISP_PROXY, 4, 0, 2, 0),
1202         IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1203         IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1204         IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1205         IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1206         IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1207         IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1208         IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1209         IGNORED_ASM_VER (SYS_VALUE_TUPLE, 4, 0, 1, 0),
1210 };
1211
1212 gboolean
1213 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1214 {
1215         for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1216                 if (ignored_assembly_versions [i].major != major ||
1217                         ignored_assembly_versions [i].minor != minor ||
1218                         ignored_assembly_versions [i].build != build ||
1219                         ignored_assembly_versions [i].revision != revision)
1220                                 continue;
1221                 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1222                         return TRUE;
1223         }
1224         return FALSE;
1225 }
1226
1227 /*
1228 Equivalent C# code:
1229         static void Main  () {
1230                 string str = "...";
1231                 int h = 5381;
1232         for (int i = 0;  i < str.Length; ++i)
1233             h = ((h << 5) + h) ^ str[i];
1234
1235                 Console.WriteLine ("{0:X}", h);
1236         }
1237 */
1238 static int
1239 hash_guid (const char *str)
1240 {
1241         int h = 5381;
1242     while (*str) {
1243         h = ((h << 5) + h) ^ *str;
1244                 ++str;
1245         }
1246
1247         return h;
1248 }
1249
1250 static gboolean
1251 is_problematic_image (MonoImage *image)
1252 {
1253         int h = hash_guid (image->guid);
1254
1255         //TODO make this more cache effiecient.
1256         // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1257         for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1258                 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1259                         const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1260                         size_t needle_len = strlen (needle);
1261                         size_t asm_len = strlen (image->name);
1262                         if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1263                                 return TRUE;
1264                 }
1265         }
1266         return FALSE;
1267 }
1268
1269 static MonoImage *
1270 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1271                     gboolean care_about_cli, gboolean care_about_pecoff)
1272 {
1273         MonoCLIImageInfo *iinfo;
1274         MonoDotNetHeader *header;
1275         GSList *errors = NULL;
1276         GSList *l;
1277
1278         mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1279
1280         mono_image_init (image);
1281
1282         iinfo = (MonoCLIImageInfo *)image->image_info;
1283         header = &iinfo->cli_header;
1284
1285         if (!image->metadata_only) {
1286                 for (l = image_loaders; l; l = l->next) {
1287                         MonoImageLoader *loader = (MonoImageLoader *)l->data;
1288                         if (loader->match (image)) {
1289                                 image->loader = loader;
1290                                 break;
1291                         }
1292                 }
1293                 if (!image->loader) {
1294                         if (status)
1295                                 *status = MONO_IMAGE_IMAGE_INVALID;
1296                         goto invalid_image;
1297                 }
1298
1299                 if (status)
1300                         *status = MONO_IMAGE_IMAGE_INVALID;
1301
1302                 if (care_about_pecoff == FALSE)
1303                         goto done;
1304
1305                 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1306                         goto invalid_image;
1307
1308                 if (!mono_image_load_pe_data (image))
1309                         goto invalid_image;
1310         } else {
1311                 image->loader = (MonoImageLoader*)&pe_loader;
1312         }
1313
1314         if (care_about_cli == FALSE) {
1315                 goto done;
1316         }
1317
1318         if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1319                 goto invalid_image;
1320
1321         if (!mono_image_load_cli_data (image))
1322                 goto invalid_image;
1323
1324         if (!image->ref_only && is_problematic_image (image)) {
1325                 if (image->load_from_context) {
1326                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1327                 } else {
1328                         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1329                         *status = MONO_IMAGE_IMAGE_INVALID;
1330                         goto invalid_image;
1331                 }
1332         }
1333
1334         if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1335                 goto invalid_image;
1336
1337         mono_image_load_names (image);
1338
1339         load_modules (image);
1340
1341 done:
1342         mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1343         if (status)
1344                 *status = MONO_IMAGE_OK;
1345
1346         return image;
1347
1348 invalid_image:
1349         if (errors) {
1350                 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1351                 g_warning ("Could not load image %s due to %s", image->name, info->message);
1352                 mono_free_verify_list (errors);
1353         }
1354         mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1355         mono_image_close (image);
1356         return NULL;
1357 }
1358
1359 static MonoImage *
1360 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1361                                         gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1362 {
1363         MonoCLIImageInfo *iinfo;
1364         MonoImage *image;
1365         MonoFileMap *filed;
1366
1367         if ((filed = mono_file_map_open (fname)) == NULL){
1368                 if (IS_PORTABILITY_SET) {
1369                         gchar *ffname = mono_portability_find_file (fname, TRUE);
1370                         if (ffname) {
1371                                 filed = mono_file_map_open (ffname);
1372                                 g_free (ffname);
1373                         }
1374                 }
1375
1376                 if (filed == NULL) {
1377                         if (status)
1378                                 *status = MONO_IMAGE_ERROR_ERRNO;
1379                         return NULL;
1380                 }
1381         }
1382
1383         image = g_new0 (MonoImage, 1);
1384         image->raw_buffer_used = TRUE;
1385         image->raw_data_len = mono_file_map_size (filed);
1386         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);
1387 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1388         if (!image->raw_data) {
1389                 image->fileio_used = TRUE;
1390                 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);
1391         }
1392 #endif
1393         if (!image->raw_data) {
1394                 mono_file_map_close (filed);
1395                 g_free (image);
1396                 if (status)
1397                         *status = MONO_IMAGE_IMAGE_INVALID;
1398                 return NULL;
1399         }
1400         iinfo = g_new0 (MonoCLIImageInfo, 1);
1401         image->image_info = iinfo;
1402         image->name = mono_path_resolve_symlinks (fname);
1403         image->ref_only = refonly;
1404         image->metadata_only = metadata_only;
1405         image->load_from_context = load_from_context;
1406         image->ref_count = 1;
1407         /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1408         image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1409
1410         mono_file_map_close (filed);
1411         return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1412 }
1413
1414 /**
1415  * mono_image_loaded_full:
1416  * \param name path or assembly name of the image to load
1417  * \param refonly Check with respect to reflection-only loads?
1418  *
1419  * This routine verifies that the given image is loaded.
1420  * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1421  *
1422  * \returns the loaded \c MonoImage, or NULL on failure.
1423  */
1424 MonoImage *
1425 mono_image_loaded_full (const char *name, gboolean refonly)
1426 {
1427         MonoImage *res;
1428
1429         mono_images_lock ();
1430         res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1431         if (!res)
1432                 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1433         mono_images_unlock ();
1434
1435         return res;
1436 }
1437
1438 /**
1439  * mono_image_loaded:
1440  * \param name path or assembly name of the image to load
1441  * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1442  * \returns the loaded \c MonoImage, or NULL on failure.
1443  */
1444 MonoImage *
1445 mono_image_loaded (const char *name)
1446 {
1447         return mono_image_loaded_full (name, FALSE);
1448 }
1449
1450 typedef struct {
1451         MonoImage *res;
1452         const char* guid;
1453 } GuidData;
1454
1455 static void
1456 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1457 {
1458         GuidData *data = (GuidData *)user_data;
1459         MonoImage *image;
1460
1461         if (data->res)
1462                 return;
1463         image = (MonoImage *)val;
1464         if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1465                 data->res = image;
1466 }
1467
1468 /**
1469  * mono_image_loaded_by_guid_full:
1470  */
1471 MonoImage *
1472 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1473 {
1474         GuidData data;
1475         GHashTable *loaded_images = get_loaded_images_hash (refonly);
1476         data.res = NULL;
1477         data.guid = guid;
1478
1479         mono_images_lock ();
1480         g_hash_table_foreach (loaded_images, find_by_guid, &data);
1481         mono_images_unlock ();
1482         return data.res;
1483 }
1484
1485 /**
1486  * mono_image_loaded_by_guid:
1487  */
1488 MonoImage *
1489 mono_image_loaded_by_guid (const char *guid)
1490 {
1491         return mono_image_loaded_by_guid_full (guid, FALSE);
1492 }
1493
1494 static MonoImage *
1495 register_image (MonoImage *image)
1496 {
1497         MonoImage *image2;
1498         GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1499
1500         mono_images_lock ();
1501         image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1502
1503         if (image2) {
1504                 /* Somebody else beat us to it */
1505                 mono_image_addref (image2);
1506                 mono_images_unlock ();
1507                 mono_image_close (image);
1508                 return image2;
1509         }
1510
1511         GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1512         g_hash_table_insert (loaded_images, image->name, image);
1513         if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1514                 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1515         mono_images_unlock ();
1516
1517         return image;
1518 }
1519
1520 MonoImage *
1521 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1522 {
1523         MonoCLIImageInfo *iinfo;
1524         MonoImage *image;
1525         char *datac;
1526
1527         if (!data || !data_len) {
1528                 if (status)
1529                         *status = MONO_IMAGE_IMAGE_INVALID;
1530                 return NULL;
1531         }
1532         datac = data;
1533         if (need_copy) {
1534                 datac = (char *)g_try_malloc (data_len);
1535                 if (!datac) {
1536                         if (status)
1537                                 *status = MONO_IMAGE_ERROR_ERRNO;
1538                         return NULL;
1539                 }
1540                 memcpy (datac, data, data_len);
1541         }
1542
1543         image = g_new0 (MonoImage, 1);
1544         image->raw_data = datac;
1545         image->raw_data_len = data_len;
1546         image->raw_data_allocated = need_copy;
1547         image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1548         iinfo = g_new0 (MonoCLIImageInfo, 1);
1549         image->image_info = iinfo;
1550         image->ref_only = refonly;
1551         image->metadata_only = metadata_only;
1552         image->ref_count = 1;
1553
1554         image = do_mono_image_load (image, status, TRUE, TRUE);
1555         if (image == NULL)
1556                 return NULL;
1557
1558         return register_image (image);
1559 }
1560
1561 /**
1562  * mono_image_open_from_data_with_name:
1563  */
1564 MonoImage *
1565 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1566 {
1567         return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1568 }
1569
1570 /**
1571  * mono_image_open_from_data_full:
1572  */
1573 MonoImage *
1574 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1575 {
1576   return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1577 }
1578
1579 /**
1580  * mono_image_open_from_data:
1581  */
1582 MonoImage *
1583 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1584 {
1585         return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1586 }
1587
1588 #ifdef HOST_WIN32
1589 /* fname is not duplicated. */
1590 MonoImage*
1591 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1592 {
1593         MonoImage* image;
1594         MonoCLIImageInfo* iinfo;
1595
1596         image = g_new0 (MonoImage, 1);
1597         image->raw_data = (char*) module_handle;
1598         image->is_module_handle = TRUE;
1599         iinfo = g_new0 (MonoCLIImageInfo, 1);
1600         image->image_info = iinfo;
1601         image->name = fname;
1602         image->ref_count = has_entry_point ? 0 : 1;
1603         image->has_entry_point = has_entry_point;
1604
1605         image = do_mono_image_load (image, status, TRUE, TRUE);
1606         if (image == NULL)
1607                 return NULL;
1608
1609         return register_image (image);
1610 }
1611 #endif
1612
1613 /**
1614  * mono_image_open_full:
1615  */
1616 MonoImage *
1617 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1618 {
1619         return mono_image_open_a_lot (fname, status, refonly, FALSE);
1620 }
1621
1622 MonoImage *
1623 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1624 {
1625         MonoImage *image;
1626         GHashTable *loaded_images = get_loaded_images_hash (refonly);
1627         char *absfname;
1628         
1629         g_return_val_if_fail (fname != NULL, NULL);
1630         
1631 #ifdef HOST_WIN32
1632         // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1633         // then assemblies need to be loaded with LoadLibrary:
1634         if (!refonly && coree_module_handle) {
1635                 HMODULE module_handle;
1636                 guint16 *fname_utf16;
1637                 DWORD last_error;
1638
1639                 absfname = mono_path_resolve_symlinks (fname);
1640                 fname_utf16 = NULL;
1641
1642                 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1643                 mono_images_lock ();
1644                 image = g_hash_table_lookup (loaded_images, absfname);
1645                 if (image) { // Image already loaded
1646                         g_assert (image->is_module_handle);
1647                         if (image->has_entry_point && image->ref_count == 0) {
1648                                 /* Increment reference count on images loaded outside of the runtime. */
1649                                 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1650                                 /* The image is already loaded because _CorDllMain removes images from the hash. */
1651                                 module_handle = LoadLibrary (fname_utf16);
1652                                 g_assert (module_handle == (HMODULE) image->raw_data);
1653                         }
1654                         mono_image_addref (image);
1655                         mono_images_unlock ();
1656                         if (fname_utf16)
1657                                 g_free (fname_utf16);
1658                         g_free (absfname);
1659                         return image;
1660                 }
1661
1662                 // Image not loaded, load it now
1663                 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1664                 module_handle = MonoLoadImage (fname_utf16);
1665                 if (status && module_handle == NULL)
1666                         last_error = mono_w32error_get_last ();
1667
1668                 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1669                 image = g_hash_table_lookup (loaded_images, absfname);
1670                 if (image)
1671                         mono_image_addref (image);
1672                 mono_images_unlock ();
1673
1674                 g_free (fname_utf16);
1675
1676                 if (module_handle == NULL) {
1677                         g_assert (!image);
1678                         g_free (absfname);
1679                         if (status) {
1680                                 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1681                                         *status = MONO_IMAGE_IMAGE_INVALID;
1682                                 else {
1683                                         if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1684                                                 errno = ENOENT;
1685                                         else
1686                                                 errno = 0;
1687                                 }
1688                         }
1689                         return NULL;
1690                 }
1691
1692                 if (image) {
1693                         g_assert (image->is_module_handle);
1694                         g_assert (image->has_entry_point);
1695                         g_free (absfname);
1696                         return image;
1697                 }
1698
1699                 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1700         }
1701 #endif
1702
1703         absfname = mono_path_canonicalize (fname);
1704
1705         /*
1706          * The easiest solution would be to do all the loading inside the mutex,
1707          * but that would lead to scalability problems. So we let the loading
1708          * happen outside the mutex, and if multiple threads happen to load
1709          * the same image, we discard all but the first copy.
1710          */
1711         mono_images_lock ();
1712         image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1713         g_free (absfname);
1714
1715         if (image) { // Image already loaded
1716                 mono_image_addref (image);
1717                 mono_images_unlock ();
1718                 return image;
1719         }
1720         mono_images_unlock ();
1721
1722         // Image not loaded, load it now
1723         image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1724         if (image == NULL)
1725                 return NULL;
1726
1727         return register_image (image);
1728 }
1729
1730 /**
1731  * mono_image_open:
1732  * \param fname filename that points to the module we want to open
1733  * \param status An error condition is returned in this field
1734  * \returns An open image of type \c MonoImage or NULL on error. 
1735  * The caller holds a temporary reference to the returned image which should be cleared 
1736  * when no longer needed by calling \c mono_image_close.
1737  * if NULL, then check the value of \p status for details on the error
1738  */
1739 MonoImage *
1740 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1741 {
1742         return mono_image_open_full (fname, status, FALSE);
1743 }
1744
1745 /**
1746  * mono_pe_file_open:
1747  * \param fname filename that points to the module we want to open
1748  * \param status An error condition is returned in this field
1749  * \returns An open image of type \c MonoImage or NULL on error.  if
1750  * NULL, then check the value of \p status for details on the error.
1751  * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
1752  * It's just a PE file loader, used for \c FileVersionInfo.  It also does
1753  * not use the image cache.
1754  */
1755 MonoImage *
1756 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1757 {
1758         g_return_val_if_fail (fname != NULL, NULL);
1759         
1760         return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1761 }
1762
1763 /**
1764  * mono_image_open_raw
1765  * \param fname filename that points to the module we want to open
1766  * \param status An error condition is returned in this field
1767  * \returns an image without loading neither pe or cli data.
1768  * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.  
1769  */
1770 MonoImage *
1771 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1772 {
1773         g_return_val_if_fail (fname != NULL, NULL);
1774         
1775         return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1776 }
1777
1778 /*
1779  * mono_image_open_metadata_only:
1780  *
1781  *   Open an image which contains metadata only without a PE header.
1782  */
1783 MonoImage *
1784 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1785 {
1786         return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1787 }
1788
1789 /**
1790  * mono_image_fixup_vtable:
1791  */
1792 void
1793 mono_image_fixup_vtable (MonoImage *image)
1794 {
1795 #ifdef HOST_WIN32
1796         MonoCLIImageInfo *iinfo;
1797         MonoPEDirEntry *de;
1798         MonoVTableFixup *vtfixup;
1799         int count;
1800         gpointer slot;
1801         guint16 slot_type;
1802         int slot_count;
1803
1804         g_assert (image->is_module_handle);
1805
1806         iinfo = image->image_info;
1807         de = &iinfo->cli_cli_header.ch_vtable_fixups;
1808         if (!de->rva || !de->size)
1809                 return;
1810         vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1811         if (!vtfixup)
1812                 return;
1813         
1814         count = de->size / sizeof (MonoVTableFixup);
1815         while (count--) {
1816                 if (!vtfixup->rva || !vtfixup->count)
1817                         continue;
1818
1819                 slot = mono_image_rva_map (image, vtfixup->rva);
1820                 g_assert (slot);
1821                 slot_type = vtfixup->type;
1822                 slot_count = vtfixup->count;
1823                 if (slot_type & VTFIXUP_TYPE_32BIT)
1824                         while (slot_count--) {
1825                                 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1826                                 slot = ((guint32*) slot) + 1;
1827                         }
1828                 else if (slot_type & VTFIXUP_TYPE_64BIT)
1829                         while (slot_count--) {
1830                                 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1831                                 slot = ((guint32*) slot) + 1;
1832                         }
1833                 else
1834                         g_assert_not_reached();
1835
1836                 vtfixup++;
1837         }
1838 #else
1839         g_assert_not_reached();
1840 #endif
1841 }
1842
1843 static void
1844 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1845 {
1846         g_hash_table_destroy ((GHashTable*)val);
1847 }
1848
1849 /*
1850 static void
1851 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1852 {
1853         mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1854 }
1855 */
1856
1857 static void
1858 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1859 {
1860         g_slist_free ((GSList*)val);
1861 }
1862
1863 /**
1864  * mono_image_addref:
1865  * \param image The image file we wish to add a reference to
1866  * Increases the reference count of an image.
1867  */
1868 void
1869 mono_image_addref (MonoImage *image)
1870 {
1871         InterlockedIncrement (&image->ref_count);
1872 }       
1873
1874 void
1875 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1876 {
1877         stream->alloc_size = stream->index = stream->offset = 0;
1878         g_free (stream->data);
1879         stream->data = NULL;
1880         if (stream->hash) {
1881                 g_hash_table_destroy (stream->hash);
1882                 stream->hash = NULL;
1883         }
1884 }
1885
1886 static inline void
1887 free_hash (GHashTable *hash)
1888 {
1889         if (hash)
1890                 g_hash_table_destroy (hash);
1891 }
1892
1893 void
1894 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1895 {
1896         free_hash (cache->delegate_invoke_cache);
1897         free_hash (cache->delegate_begin_invoke_cache);
1898         free_hash (cache->delegate_end_invoke_cache);
1899         free_hash (cache->runtime_invoke_cache);
1900         free_hash (cache->runtime_invoke_vtype_cache);
1901         
1902         free_hash (cache->delegate_abstract_invoke_cache);
1903
1904         free_hash (cache->runtime_invoke_direct_cache);
1905         free_hash (cache->managed_wrapper_cache);
1906
1907         free_hash (cache->native_wrapper_cache);
1908         free_hash (cache->native_wrapper_aot_cache);
1909         free_hash (cache->native_wrapper_check_cache);
1910         free_hash (cache->native_wrapper_aot_check_cache);
1911
1912         free_hash (cache->native_func_wrapper_aot_cache);
1913         free_hash (cache->remoting_invoke_cache);
1914         free_hash (cache->synchronized_cache);
1915         free_hash (cache->unbox_wrapper_cache);
1916         free_hash (cache->cominterop_invoke_cache);
1917         free_hash (cache->cominterop_wrapper_cache);
1918         free_hash (cache->thunk_invoke_cache);
1919 }
1920
1921 static void
1922 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1923 {
1924         for (int i = 0; i < image_count; ++i) {
1925                 if (images [i]) {
1926                         if (!mono_image_close_except_pools (images [i]))
1927                                 images [i] = NULL;
1928                 }
1929         }
1930 }
1931
1932 /*
1933  * Returns whether mono_image_close_finish() must be called as well.
1934  * We must unload images in two steps because clearing the domain in
1935  * SGen requires the class metadata to be intact, but we need to free
1936  * the mono_g_hash_tables in case a collection occurs during domain
1937  * unloading and the roots would trip up the GC.
1938  */
1939 gboolean
1940 mono_image_close_except_pools (MonoImage *image)
1941 {
1942         MonoImage *image2;
1943         GHashTable *loaded_images, *loaded_images_by_name;
1944         int i;
1945
1946         g_return_val_if_fail (image != NULL, FALSE);
1947
1948         /*
1949          * Atomically decrement the refcount and remove ourselves from the hash tables, so
1950          * register_image () can't grab an image which is being closed.
1951          */
1952         mono_images_lock ();
1953
1954         if (InterlockedDecrement (&image->ref_count) > 0) {
1955                 mono_images_unlock ();
1956                 return FALSE;
1957         }
1958
1959         loaded_images         = get_loaded_images_hash (image->ref_only);
1960         loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1961         image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1962         if (image == image2) {
1963                 /* This is not true if we are called from mono_image_open () */
1964                 g_hash_table_remove (loaded_images, image->name);
1965         }
1966         if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1967                 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);     
1968
1969         mono_images_unlock ();
1970
1971 #ifdef HOST_WIN32
1972         if (image->is_module_handle && image->has_entry_point) {
1973                 mono_images_lock ();
1974                 if (image->ref_count == 0) {
1975                         /* Image will be closed by _CorDllMain. */
1976                         FreeLibrary ((HMODULE) image->raw_data);
1977                         mono_images_unlock ();
1978                         return FALSE;
1979                 }
1980                 mono_images_unlock ();
1981         }
1982 #endif
1983
1984         mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1985
1986         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1987
1988         mono_image_invoke_unload_hook (image);
1989
1990         mono_metadata_clean_for_image (image);
1991
1992         /*
1993          * The caches inside a MonoImage might refer to metadata which is stored in referenced 
1994          * assemblies, so we can't release these references in mono_assembly_close () since the
1995          * MonoImage might outlive its associated MonoAssembly.
1996          */
1997         if (image->references && !image_is_dynamic (image)) {
1998                 for (i = 0; i < image->nreferences; i++) {
1999                         if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2000                                 if (!mono_assembly_close_except_image_pools (image->references [i]))
2001                                         image->references [i] = NULL;
2002                         }
2003                 }
2004         } else {
2005                 if (image->references) {
2006                         g_free (image->references);
2007                         image->references = NULL;
2008                 }
2009         }
2010
2011 #ifdef HOST_WIN32
2012         mono_images_lock ();
2013         if (image->is_module_handle && !image->has_entry_point)
2014                 FreeLibrary ((HMODULE) image->raw_data);
2015         mono_images_unlock ();
2016 #endif
2017
2018         if (image->raw_buffer_used) {
2019                 if (image->raw_data != NULL) {
2020 #ifndef HOST_WIN32
2021                         if (image->fileio_used)
2022                                 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
2023                         else
2024 #endif
2025                                 mono_file_unmap (image->raw_data, image->raw_data_handle);
2026                 }
2027         }
2028         
2029         if (image->raw_data_allocated) {
2030                 /* FIXME: do we need this? (image is disposed anyway) */
2031                 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2032                 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2033
2034                 if ((image->raw_metadata > image->raw_data) &&
2035                         (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2036                         image->raw_metadata = NULL;
2037
2038                 for (i = 0; i < ii->cli_section_count; i++)
2039                         if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2040                                 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2041                                 ii->cli_sections [i] = NULL;
2042
2043                 g_free (image->raw_data);
2044         }
2045
2046         if (debug_assembly_unload) {
2047                 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2048         } else {
2049                 g_free (image->name);
2050                 g_free (image->guid);
2051                 g_free (image->version);
2052         }
2053
2054         if (image->method_cache)
2055                 g_hash_table_destroy (image->method_cache);
2056         if (image->methodref_cache)
2057                 g_hash_table_destroy (image->methodref_cache);
2058         mono_internal_hash_table_destroy (&image->class_cache);
2059         mono_conc_hashtable_destroy (image->field_cache);
2060         if (image->array_cache) {
2061                 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2062                 g_hash_table_destroy (image->array_cache);
2063         }
2064         if (image->szarray_cache)
2065                 g_hash_table_destroy (image->szarray_cache);
2066         if (image->ptr_cache)
2067                 g_hash_table_destroy (image->ptr_cache);
2068         if (image->name_cache) {
2069                 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2070                 g_hash_table_destroy (image->name_cache);
2071         }
2072
2073         free_hash (image->delegate_bound_static_invoke_cache);
2074         free_hash (image->runtime_invoke_vcall_cache);
2075         free_hash (image->ldfld_wrapper_cache);
2076         free_hash (image->ldflda_wrapper_cache);
2077         free_hash (image->stfld_wrapper_cache);
2078         free_hash (image->isinst_cache);
2079         free_hash (image->castclass_cache);
2080         free_hash (image->icall_wrapper_cache);
2081         free_hash (image->proxy_isinst_cache);
2082         free_hash (image->var_cache_slow);
2083         free_hash (image->mvar_cache_slow);
2084         free_hash (image->var_cache_constrained);
2085         free_hash (image->mvar_cache_constrained);
2086         free_hash (image->wrapper_param_names);
2087         free_hash (image->pinvoke_scopes);
2088         free_hash (image->pinvoke_scope_filenames);
2089         free_hash (image->native_func_wrapper_cache);
2090         mono_conc_hashtable_destroy (image->typespec_cache);
2091
2092         mono_wrapper_caches_free (&image->wrapper_caches);
2093
2094         for (i = 0; i < image->gshared_types_len; ++i)
2095                 free_hash (image->gshared_types [i]);
2096         g_free (image->gshared_types);
2097
2098         /* The ownership of signatures is not well defined */
2099         g_hash_table_destroy (image->memberref_signatures);
2100         g_hash_table_destroy (image->helper_signatures);
2101         g_hash_table_destroy (image->method_signatures);
2102
2103         if (image->rgctx_template_hash)
2104                 g_hash_table_destroy (image->rgctx_template_hash);
2105
2106         if (image->property_hash)
2107                 mono_property_hash_destroy (image->property_hash);
2108
2109         /*
2110         reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2111         cleared during shutdown as we don't perform regular appdomain unload for the root one.
2112         */
2113         g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2114         image->reflection_info_unregister_classes = NULL;
2115
2116         if (image->interface_bitset) {
2117                 mono_unload_interface_ids (image->interface_bitset);
2118                 mono_bitset_free (image->interface_bitset);
2119         }
2120         if (image->image_info){
2121                 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2122
2123                 if (ii->cli_section_tables)
2124                         g_free (ii->cli_section_tables);
2125                 if (ii->cli_sections)
2126                         g_free (ii->cli_sections);
2127                 g_free (image->image_info);
2128         }
2129
2130         mono_image_close_except_pools_all (image->files, image->file_count);
2131         mono_image_close_except_pools_all (image->modules, image->module_count);
2132         if (image->modules_loaded)
2133                 g_free (image->modules_loaded);
2134
2135         mono_os_mutex_destroy (&image->szarray_cache_lock);
2136         mono_os_mutex_destroy (&image->lock);
2137
2138         /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2139         if (image_is_dynamic (image)) {
2140                 /* Dynamic images are GC_MALLOCed */
2141                 g_free ((char*)image->module_name);
2142                 mono_dynamic_image_free ((MonoDynamicImage*)image);
2143         }
2144
2145         mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2146
2147         return TRUE;
2148 }
2149
2150 static void
2151 mono_image_close_all (MonoImage**images, int image_count)
2152 {
2153         for (int i = 0; i < image_count; ++i) {
2154                 if (images [i])
2155                         mono_image_close_finish (images [i]);
2156         }
2157         if (images)
2158                 g_free (images);
2159 }
2160
2161 void
2162 mono_image_close_finish (MonoImage *image)
2163 {
2164         int i;
2165
2166         if (image->references && !image_is_dynamic (image)) {
2167                 for (i = 0; i < image->nreferences; i++) {
2168                         if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2169                                 mono_assembly_close_finish (image->references [i]);
2170                 }
2171
2172                 g_free (image->references);
2173                 image->references = NULL;
2174         }
2175
2176         mono_image_close_all (image->files, image->file_count);
2177         mono_image_close_all (image->modules, image->module_count);
2178
2179 #ifndef DISABLE_PERFCOUNTERS
2180         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2181 #endif
2182
2183         if (!image_is_dynamic (image)) {
2184                 if (debug_assembly_unload)
2185                         mono_mempool_invalidate (image->mempool);
2186                 else {
2187                         mono_mempool_destroy (image->mempool);
2188                         g_free (image);
2189                 }
2190         } else {
2191                 if (debug_assembly_unload)
2192                         mono_mempool_invalidate (image->mempool);
2193                 else {
2194                         mono_mempool_destroy (image->mempool);
2195                         mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2196                 }
2197         }
2198 }
2199
2200 /**
2201  * mono_image_close:
2202  * \param image The image file we wish to close
2203  * Closes an image file, deallocates all memory consumed and
2204  * unmaps all possible sections of the file
2205  */
2206 void
2207 mono_image_close (MonoImage *image)
2208 {
2209         if (mono_image_close_except_pools (image))
2210                 mono_image_close_finish (image);
2211 }
2212
2213 /** 
2214  * mono_image_strerror:
2215  * \param status an code indicating the result from a recent operation
2216  * \returns a string describing the error
2217  */
2218 const char *
2219 mono_image_strerror (MonoImageOpenStatus status)
2220 {
2221         switch (status){
2222         case MONO_IMAGE_OK:
2223                 return "success";
2224         case MONO_IMAGE_ERROR_ERRNO:
2225                 return strerror (errno);
2226         case MONO_IMAGE_IMAGE_INVALID:
2227                 return "File does not contain a valid CIL image";
2228         case MONO_IMAGE_MISSING_ASSEMBLYREF:
2229                 return "An assembly was referenced, but could not be found";
2230         }
2231         return "Internal error";
2232 }
2233
2234 static gpointer
2235 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2236                                guint32 lang_id, gunichar2 *name,
2237                                MonoPEResourceDirEntry *entry,
2238                                MonoPEResourceDir *root, guint32 level)
2239 {
2240         gboolean is_string, is_dir;
2241         guint32 name_offset, dir_offset;
2242
2243         /* Level 0 holds a directory entry for each type of resource
2244          * (identified by ID or name).
2245          *
2246          * Level 1 holds a directory entry for each named resource
2247          * item, and each "anonymous" item of a particular type of
2248          * resource.
2249          *
2250          * Level 2 holds a directory entry for each language pointing to
2251          * the actual data.
2252          */
2253         is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2254         name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2255
2256         is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2257         dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2258
2259         if(level==0) {
2260                 if (is_string)
2261                         return NULL;
2262         } else if (level==1) {
2263                 if (res_id != name_offset)
2264                         return NULL;
2265 #if 0
2266                 if(name!=NULL &&
2267                    is_string==TRUE && name!=lookup (name_offset)) {
2268                         return(NULL);
2269                 }
2270 #endif
2271         } else if (level==2) {
2272                 if (is_string || (lang_id != 0 && name_offset != lang_id))
2273                         return NULL;
2274         } else {
2275                 g_assert_not_reached ();
2276         }
2277
2278         if (is_dir) {
2279                 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2280                 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2281                 guint32 entries, i;
2282
2283                 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2284
2285                 for(i=0; i<entries; i++) {
2286                         MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2287                         gpointer ret;
2288                         
2289                         ret=mono_image_walk_resource_tree (info, res_id,
2290                                                            lang_id, name,
2291                                                            sub_entry, root,
2292                                                            level+1);
2293                         if(ret!=NULL) {
2294                                 return(ret);
2295                         }
2296                 }
2297
2298                 return(NULL);
2299         } else {
2300                 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2301                 MonoPEResourceDataEntry *res;
2302
2303                 res = g_new0 (MonoPEResourceDataEntry, 1);
2304
2305                 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2306                 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2307                 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2308                 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2309
2310                 return (res);
2311         }
2312 }
2313
2314 /**
2315  * mono_image_lookup_resource:
2316  * \param image the image to look up the resource in
2317  * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2318  * \param lang_id The language id.
2319  * \param name the resource name to lookup.
2320  * \returns NULL if not found, otherwise a pointer to the in-memory representation
2321  * of the given resource. The caller should free it using \c g_free when no longer
2322  * needed.
2323  */
2324 gpointer
2325 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2326 {
2327         MonoCLIImageInfo *info;
2328         MonoDotNetHeader *header;
2329         MonoPEDatadir *datadir;
2330         MonoPEDirEntry *rsrc;
2331         MonoPEResourceDir *resource_dir;
2332         MonoPEResourceDirEntry *res_entries;
2333         guint32 entries, i;
2334
2335         if(image==NULL) {
2336                 return(NULL);
2337         }
2338
2339         mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2340
2341         info = (MonoCLIImageInfo *)image->image_info;
2342         if(info==NULL) {
2343                 return(NULL);
2344         }
2345
2346         header=&info->cli_header;
2347         if(header==NULL) {
2348                 return(NULL);
2349         }
2350
2351         datadir=&header->datadir;
2352         if(datadir==NULL) {
2353                 return(NULL);
2354         }
2355
2356         rsrc=&datadir->pe_resource_table;
2357         if(rsrc==NULL) {
2358                 return(NULL);
2359         }
2360
2361         resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2362         if(resource_dir==NULL) {
2363                 return(NULL);
2364         }
2365
2366         entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2367         res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2368         
2369         for(i=0; i<entries; i++) {
2370                 MonoPEResourceDirEntry *entry=&res_entries[i];
2371                 gpointer ret;
2372                 
2373                 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2374                                                    name, entry, resource_dir,
2375                                                    0);
2376                 if(ret!=NULL) {
2377                         return(ret);
2378                 }
2379         }
2380
2381         return(NULL);
2382 }
2383
2384 /** 
2385  * mono_image_get_entry_point:
2386  * \param image the image where the entry point will be looked up.
2387  * Use this routine to determine the metadata token for method that
2388  * has been flagged as the entry point.
2389  * \returns the token for the entry point method in the image
2390  */
2391 guint32
2392 mono_image_get_entry_point (MonoImage *image)
2393 {
2394         return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2395 }
2396
2397 /**
2398  * mono_image_get_resource:
2399  * \param image the image where the resource will be looked up.
2400  * \param offset The offset to add to the resource
2401  * \param size a pointer to an int where the size of the resource will be stored
2402  *
2403  * This is a low-level routine that fetches a resource from the
2404  * metadata that starts at a given \p offset.  The \p size parameter is
2405  * filled with the data field as encoded in the metadata.
2406  *
2407  * \returns the pointer to the resource whose offset is \p offset.
2408  */
2409 const char*
2410 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2411 {
2412         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2413         MonoCLIHeader *ch = &iinfo->cli_cli_header;
2414         const char* data;
2415
2416         if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2417                 return NULL;
2418         
2419         data = mono_image_rva_map (image, ch->ch_resources.rva);
2420         if (!data)
2421                 return NULL;
2422         data += offset;
2423         if (size)
2424                 *size = read32 (data);
2425         data += 4;
2426         return data;
2427 }
2428
2429 // Returning NULL with no error set will be interpeted as "not found"
2430 MonoImage*
2431 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2432 {
2433         char *base_dir, *name;
2434         MonoImage *res;
2435         MonoTableInfo  *t = &image->tables [MONO_TABLE_FILE];
2436         const char *fname;
2437         guint32 fname_id;
2438
2439         error_init (error);
2440
2441         if (fileidx < 1 || fileidx > t->rows)
2442                 return NULL;
2443
2444         mono_image_lock (image);
2445         if (image->files && image->files [fileidx - 1]) {
2446                 mono_image_unlock (image);
2447                 return image->files [fileidx - 1];
2448         }
2449         mono_image_unlock (image);
2450
2451         fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2452         fname = mono_metadata_string_heap (image, fname_id);
2453         base_dir = g_path_get_dirname (image->name);
2454         name = g_build_filename (base_dir, fname, NULL);
2455         res = mono_image_open (name, NULL);
2456         if (!res)
2457                 goto done;
2458
2459         mono_image_lock (image);
2460         if (image->files && image->files [fileidx - 1]) {
2461                 MonoImage *old = res;
2462                 res = image->files [fileidx - 1];
2463                 mono_image_unlock (image);
2464                 mono_image_close (old);
2465         } else {
2466                 int i;
2467                 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2468                 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2469                         mono_image_unlock (image);
2470                         mono_image_close (res);
2471                         return NULL;
2472                 }
2473
2474                 for (i = 0; i < res->module_count; ++i) {
2475                         if (res->modules [i] && !res->modules [i]->assembly)
2476                                 res->modules [i]->assembly = image->assembly;
2477                 }
2478
2479                 if (!image->files) {
2480                         image->files = g_new0 (MonoImage*, t->rows);
2481                         image->file_count = t->rows;
2482                 }
2483                 image->files [fileidx - 1] = res;
2484                 mono_image_unlock (image);
2485                 /* vtable fixup can't happen with the image lock held */
2486 #ifdef HOST_WIN32
2487                 if (res->is_module_handle)
2488                         mono_image_fixup_vtable (res);
2489 #endif
2490         }
2491
2492 done:
2493         g_free (name);
2494         g_free (base_dir);
2495         return res;
2496 }
2497
2498 /**
2499  * mono_image_load_file_for_image:
2500  */
2501 MonoImage*
2502 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2503 {
2504         MonoError error;
2505         MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2506         mono_error_assert_ok (&error);
2507         return result;
2508 }
2509
2510 /**
2511  * mono_image_get_strong_name:
2512  * \param image a MonoImage
2513  * \param size a \c guint32 pointer, or NULL.
2514  *
2515  * If the image has a strong name, and \p size is not NULL, the value
2516  * pointed to by size will have the size of the strong name.
2517  *
2518  * \returns NULL if the image does not have a strong name, or a
2519  * pointer to the public key.
2520  */
2521 const char*
2522 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2523 {
2524         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2525         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2526         const char* data;
2527
2528         if (!de->size || !de->rva)
2529                 return NULL;
2530         data = mono_image_rva_map (image, de->rva);
2531         if (!data)
2532                 return NULL;
2533         if (size)
2534                 *size = de->size;
2535         return data;
2536 }
2537
2538 /**
2539  * mono_image_strong_name_position:
2540  * \param image a \c MonoImage
2541  * \param size a \c guint32 pointer, or NULL.
2542  *
2543  * If the image has a strong name, and \p size is not NULL, the value
2544  * pointed to by size will have the size of the strong name.
2545  *
2546  * \returns the position within the image file where the strong name
2547  * is stored.
2548  */
2549 guint32
2550 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2551 {
2552         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2553         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2554         guint32 pos;
2555
2556         if (size)
2557                 *size = de->size;
2558         if (!de->size || !de->rva)
2559                 return 0;
2560         pos = mono_cli_rva_image_map (image, de->rva);
2561         return pos == INVALID_ADDRESS ? 0 : pos;
2562 }
2563
2564 /**
2565  * mono_image_get_public_key:
2566  * \param image a \c MonoImage
2567  * \param size a \c guint32 pointer, or NULL.
2568  *
2569  * This is used to obtain the public key in the \p image.
2570  * 
2571  * If the image has a public key, and \p size is not NULL, the value
2572  * pointed to by size will have the size of the public key.
2573  * 
2574  * \returns NULL if the image does not have a public key, or a pointer
2575  * to the public key.
2576  */
2577 const char*
2578 mono_image_get_public_key (MonoImage *image, guint32 *size)
2579 {
2580         const char *pubkey;
2581         guint32 len, tok;
2582
2583         if (image_is_dynamic (image)) {
2584                 if (size)
2585                         *size = ((MonoDynamicImage*)image)->public_key_len;
2586                 return (char*)((MonoDynamicImage*)image)->public_key;
2587         }
2588         if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2589                 return NULL;
2590         tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2591         if (!tok)
2592                 return NULL;
2593         pubkey = mono_metadata_blob_heap (image, tok);
2594         len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2595         if (size)
2596                 *size = len;
2597         return pubkey;
2598 }
2599
2600 /**
2601  * mono_image_get_name:
2602  * \param name a \c MonoImage
2603  * \returns the name of the assembly.
2604  */
2605 const char*
2606 mono_image_get_name (MonoImage *image)
2607 {
2608         return image->assembly_name;
2609 }
2610
2611 /**
2612  * mono_image_get_filename:
2613  * \param image a \c MonoImage
2614  * Used to get the filename that hold the actual \c MonoImage
2615  * \returns the filename.
2616  */
2617 const char*
2618 mono_image_get_filename (MonoImage *image)
2619 {
2620         return image->name;
2621 }
2622
2623 /**
2624  * mono_image_get_guid:
2625  */
2626 const char*
2627 mono_image_get_guid (MonoImage *image)
2628 {
2629         return image->guid;
2630 }
2631
2632 /**
2633  * mono_image_get_table_info:
2634  */
2635 const MonoTableInfo*
2636 mono_image_get_table_info (MonoImage *image, int table_id)
2637 {
2638         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2639                 return NULL;
2640         return &image->tables [table_id];
2641 }
2642
2643 /**
2644  * mono_image_get_table_rows:
2645  */
2646 int
2647 mono_image_get_table_rows (MonoImage *image, int table_id)
2648 {
2649         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2650                 return 0;
2651         return image->tables [table_id].rows;
2652 }
2653
2654 /**
2655  * mono_table_info_get_rows:
2656  */
2657 int
2658 mono_table_info_get_rows (const MonoTableInfo *table)
2659 {
2660         return table->rows;
2661 }
2662
2663 /**
2664  * mono_image_get_assembly:
2665  * \param image the \c MonoImage .
2666  * Use this routine to get the assembly that owns this image.
2667  * \returns the assembly that holds this image.
2668  */
2669 MonoAssembly* 
2670 mono_image_get_assembly (MonoImage *image)
2671 {
2672         return image->assembly;
2673 }
2674
2675 /**
2676  * mono_image_is_dynamic:
2677  * \param image the \c MonoImage
2678  *
2679  * Determines if the given image was created dynamically through the
2680  * \c System.Reflection.Emit API
2681  * \returns TRUE if the image was created dynamically, FALSE if not.
2682  */
2683 gboolean
2684 mono_image_is_dynamic (MonoImage *image)
2685 {
2686         return image_is_dynamic (image);
2687 }
2688
2689 /**
2690  * mono_image_has_authenticode_entry:
2691  * \param image the \c MonoImage
2692  * Use this routine to determine if the image has a Authenticode
2693  * Certificate Table.
2694  * \returns TRUE if the image contains an authenticode entry in the PE
2695  * directory.
2696  */
2697 gboolean
2698 mono_image_has_authenticode_entry (MonoImage *image)
2699 {
2700         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2701         MonoDotNetHeader *header = &iinfo->cli_header;
2702         if (!header)
2703                 return FALSE;
2704         MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2705         // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2706         return ((de->rva != 0) && (de->size > 8));
2707 }
2708
2709 gpointer
2710 mono_image_alloc (MonoImage *image, guint size)
2711 {
2712         gpointer res;
2713
2714 #ifndef DISABLE_PERFCOUNTERS
2715         mono_perfcounters->loader_bytes += size;
2716 #endif
2717         mono_image_lock (image);
2718         res = mono_mempool_alloc (image->mempool, size);
2719         mono_image_unlock (image);
2720
2721         return res;
2722 }
2723
2724 gpointer
2725 mono_image_alloc0 (MonoImage *image, guint size)
2726 {
2727         gpointer res;
2728
2729 #ifndef DISABLE_PERFCOUNTERS
2730         mono_perfcounters->loader_bytes += size;
2731 #endif
2732         mono_image_lock (image);
2733         res = mono_mempool_alloc0 (image->mempool, size);
2734         mono_image_unlock (image);
2735
2736         return res;
2737 }
2738
2739 char*
2740 mono_image_strdup (MonoImage *image, const char *s)
2741 {
2742         char *res;
2743
2744 #ifndef DISABLE_PERFCOUNTERS
2745         mono_perfcounters->loader_bytes += strlen (s);
2746 #endif
2747         mono_image_lock (image);
2748         res = mono_mempool_strdup (image->mempool, s);
2749         mono_image_unlock (image);
2750
2751         return res;
2752 }
2753
2754 char*
2755 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2756 {
2757         char *buf;
2758         mono_image_lock (image);
2759         buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2760         mono_image_unlock (image);
2761 #ifndef DISABLE_PERFCOUNTERS
2762         mono_perfcounters->loader_bytes += strlen (buf);
2763 #endif
2764         return buf;
2765 }
2766
2767 char*
2768 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2769 {
2770         char *buf;
2771         va_list args;
2772
2773         va_start (args, format);
2774         buf = mono_image_strdup_vprintf (image, format, args);
2775         va_end (args);
2776         return buf;
2777 }
2778
2779 GList*
2780 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2781 {
2782         GList *new_list;
2783         
2784         new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2785         new_list->data = data;
2786         new_list->prev = list ? list->prev : NULL;
2787     new_list->next = list;
2788
2789     if (new_list->prev)
2790             new_list->prev->next = new_list;
2791     if (list)
2792             list->prev = new_list;
2793
2794         return new_list;
2795 }
2796
2797 GSList*
2798 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2799 {
2800         GSList *new_list;
2801
2802         new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2803         new_list->data = data;
2804         new_list->next = NULL;
2805
2806         return g_slist_concat (list, new_list);
2807 }
2808
2809 void
2810 mono_image_lock (MonoImage *image)
2811 {
2812         mono_locks_os_acquire (&image->lock, ImageDataLock);
2813 }
2814
2815 void
2816 mono_image_unlock (MonoImage *image)
2817 {
2818         mono_locks_os_release (&image->lock, ImageDataLock);
2819 }
2820
2821
2822 /**
2823  * mono_image_property_lookup:
2824  * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2825  *
2826  * LOCKING: Takes the image lock
2827  */
2828 gpointer 
2829 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2830 {
2831         gpointer res;
2832
2833         mono_image_lock (image);
2834         res = mono_property_hash_lookup (image->property_hash, subject, property);
2835         mono_image_unlock (image);
2836
2837         return res;
2838 }
2839
2840 /**
2841  * mono_image_property_insert:
2842  * Insert a new property \p property with value \p value on \p subject in \p
2843  * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2844  *
2845  * LOCKING: Takes the image lock
2846  */
2847 void
2848 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2849 {
2850         CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2851         mono_image_lock (image);
2852         mono_property_hash_insert (image->property_hash, subject, property, value);
2853         mono_image_unlock (image);
2854 }
2855
2856 /**
2857  * mono_image_property_remove:
2858  * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2859  *
2860  * LOCKING: Takes the image lock
2861  */
2862 void
2863 mono_image_property_remove (MonoImage *image, gpointer subject)
2864 {
2865         mono_image_lock (image);
2866         mono_property_hash_remove_object (image->property_hash, subject);
2867         mono_image_unlock (image);
2868 }
2869
2870 void
2871 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2872 {
2873         MonoImage *image = klass->image;
2874         g_assert (image_is_dynamic (image));
2875         mono_image_lock (image);
2876         image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2877         mono_image_unlock (image);
2878 }
2879
2880 // 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.
2881
2882 /**
2883  * mono_find_image_owner:
2884  *
2885  * Find the image, if any, which a given pointer is located in the memory of.
2886  */
2887 MonoImage *
2888 mono_find_image_owner (void *ptr)
2889 {
2890         mono_images_lock ();
2891
2892         MonoImage *owner = NULL;
2893
2894         // Iterate over both by-path image hashes
2895         const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2896         int hash_idx;
2897         for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2898         {
2899                 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2900                 GHashTableIter iter;
2901                 MonoImage *image;
2902
2903                 // Iterate over images within a hash
2904                 g_hash_table_iter_init (&iter, target);
2905                 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2906                 {
2907                         mono_image_lock (image);
2908                         if (mono_mempool_contains_addr (image->mempool, ptr))
2909                                 owner = image;
2910                         mono_image_unlock (image);
2911                 }
2912         }
2913
2914         mono_images_unlock ();
2915
2916         return owner;
2917 }