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