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