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