Merge pull request #5714 from alexischr/update_bockbuild
[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 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1117 If any assemblies are added/removed, then this should be regenerated with:
1118
1119   $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1120
1121 */
1122
1123 typedef enum {
1124         SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1125         SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1126         SYS_IO_COMPRESSION = 2, //System.IO.Compression
1127         SYS_NET_HTTP = 3, //System.Net.Http
1128         SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1129         SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1130 } IgnoredAssemblyNames;
1131
1132 typedef struct {
1133         int hash;
1134         int assembly_name;
1135         const char guid [40];
1136 } IgnoredAssembly;
1137
1138 typedef struct {
1139         int assembly_name;
1140         guint16 major, minor, build, revision;
1141 } IgnoredAssemblyVersion;
1142
1143 const char *ignored_assemblies_file_names[] = {
1144         "System.Runtime.InteropServices.RuntimeInformation.dll",
1145         "System.Globalization.Extensions.dll",
1146         "System.IO.Compression.dll",
1147         "System.Net.Http.dll",
1148         "System.Text.Encoding.CodePages.dll",
1149         "System.Threading.Overlapped.dll"
1150 };
1151
1152 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR)     { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1153
1154 static const IgnoredAssembly ignored_assemblies [] = {
1155         IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1156         IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1157         IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1158         IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1159         IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1160         IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1161         IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1162         IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1163         IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1164         IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1165         IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1166         IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1167         IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1168         IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1169         IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1170         IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1171         IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1172         IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46")
1173 };
1174
1175
1176 const char *ignored_assemblies_names[] = {
1177         "System.Runtime.InteropServices.RuntimeInformation",
1178         "System.Globalization.Extensions",
1179         "System.IO.Compression",
1180         "System.Net.Http",
1181         "System.Text.Encoding.CodePages",
1182         "System.Threading.Overlapped"
1183 };
1184
1185 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1186
1187 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1188         IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1189         IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1190         IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1191         IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1192         IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1193         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1194         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1195         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1196         IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1197         IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1198         IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1199         IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1200         IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1201         IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 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_RAISE (image_loading, (image));
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_RAISE (image_loaded, (image));
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_RAISE (image_failed, (image));
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_RAISE (image_unloading, (image));
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_RAISE (image_unloaded, (image));
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         /* FIXME: use an explicit subtraction method as soon as it's available */
2176         InterlockedAdd (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2177 #endif
2178
2179         if (!image_is_dynamic (image)) {
2180                 if (debug_assembly_unload)
2181                         mono_mempool_invalidate (image->mempool);
2182                 else {
2183                         mono_mempool_destroy (image->mempool);
2184                         g_free (image);
2185                 }
2186         } else {
2187                 if (debug_assembly_unload)
2188                         mono_mempool_invalidate (image->mempool);
2189                 else {
2190                         mono_mempool_destroy (image->mempool);
2191                         mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2192                 }
2193         }
2194 }
2195
2196 /**
2197  * mono_image_close:
2198  * \param image The image file we wish to close
2199  * Closes an image file, deallocates all memory consumed and
2200  * unmaps all possible sections of the file
2201  */
2202 void
2203 mono_image_close (MonoImage *image)
2204 {
2205         if (mono_image_close_except_pools (image))
2206                 mono_image_close_finish (image);
2207 }
2208
2209 /** 
2210  * mono_image_strerror:
2211  * \param status an code indicating the result from a recent operation
2212  * \returns a string describing the error
2213  */
2214 const char *
2215 mono_image_strerror (MonoImageOpenStatus status)
2216 {
2217         switch (status){
2218         case MONO_IMAGE_OK:
2219                 return "success";
2220         case MONO_IMAGE_ERROR_ERRNO:
2221                 return strerror (errno);
2222         case MONO_IMAGE_IMAGE_INVALID:
2223                 return "File does not contain a valid CIL image";
2224         case MONO_IMAGE_MISSING_ASSEMBLYREF:
2225                 return "An assembly was referenced, but could not be found";
2226         }
2227         return "Internal error";
2228 }
2229
2230 static gpointer
2231 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2232                                guint32 lang_id, gunichar2 *name,
2233                                MonoPEResourceDirEntry *entry,
2234                                MonoPEResourceDir *root, guint32 level)
2235 {
2236         gboolean is_string, is_dir;
2237         guint32 name_offset, dir_offset;
2238
2239         /* Level 0 holds a directory entry for each type of resource
2240          * (identified by ID or name).
2241          *
2242          * Level 1 holds a directory entry for each named resource
2243          * item, and each "anonymous" item of a particular type of
2244          * resource.
2245          *
2246          * Level 2 holds a directory entry for each language pointing to
2247          * the actual data.
2248          */
2249         is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2250         name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2251
2252         is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2253         dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2254
2255         if(level==0) {
2256                 if (is_string)
2257                         return NULL;
2258         } else if (level==1) {
2259                 if (res_id != name_offset)
2260                         return NULL;
2261 #if 0
2262                 if(name!=NULL &&
2263                    is_string==TRUE && name!=lookup (name_offset)) {
2264                         return(NULL);
2265                 }
2266 #endif
2267         } else if (level==2) {
2268                 if (is_string || (lang_id != 0 && name_offset != lang_id))
2269                         return NULL;
2270         } else {
2271                 g_assert_not_reached ();
2272         }
2273
2274         if (is_dir) {
2275                 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2276                 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2277                 guint32 entries, i;
2278
2279                 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2280
2281                 for(i=0; i<entries; i++) {
2282                         MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2283                         gpointer ret;
2284                         
2285                         ret=mono_image_walk_resource_tree (info, res_id,
2286                                                            lang_id, name,
2287                                                            sub_entry, root,
2288                                                            level+1);
2289                         if(ret!=NULL) {
2290                                 return(ret);
2291                         }
2292                 }
2293
2294                 return(NULL);
2295         } else {
2296                 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2297                 MonoPEResourceDataEntry *res;
2298
2299                 res = g_new0 (MonoPEResourceDataEntry, 1);
2300
2301                 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2302                 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2303                 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2304                 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2305
2306                 return (res);
2307         }
2308 }
2309
2310 /**
2311  * mono_image_lookup_resource:
2312  * \param image the image to look up the resource in
2313  * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2314  * \param lang_id The language id.
2315  * \param name the resource name to lookup.
2316  * \returns NULL if not found, otherwise a pointer to the in-memory representation
2317  * of the given resource. The caller should free it using \c g_free when no longer
2318  * needed.
2319  */
2320 gpointer
2321 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2322 {
2323         MonoCLIImageInfo *info;
2324         MonoDotNetHeader *header;
2325         MonoPEDatadir *datadir;
2326         MonoPEDirEntry *rsrc;
2327         MonoPEResourceDir *resource_dir;
2328         MonoPEResourceDirEntry *res_entries;
2329         guint32 entries, i;
2330
2331         if(image==NULL) {
2332                 return(NULL);
2333         }
2334
2335         mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2336
2337         info = (MonoCLIImageInfo *)image->image_info;
2338         if(info==NULL) {
2339                 return(NULL);
2340         }
2341
2342         header=&info->cli_header;
2343         if(header==NULL) {
2344                 return(NULL);
2345         }
2346
2347         datadir=&header->datadir;
2348         if(datadir==NULL) {
2349                 return(NULL);
2350         }
2351
2352         rsrc=&datadir->pe_resource_table;
2353         if(rsrc==NULL) {
2354                 return(NULL);
2355         }
2356
2357         resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2358         if(resource_dir==NULL) {
2359                 return(NULL);
2360         }
2361
2362         entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2363         res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2364         
2365         for(i=0; i<entries; i++) {
2366                 MonoPEResourceDirEntry *entry=&res_entries[i];
2367                 gpointer ret;
2368                 
2369                 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2370                                                    name, entry, resource_dir,
2371                                                    0);
2372                 if(ret!=NULL) {
2373                         return(ret);
2374                 }
2375         }
2376
2377         return(NULL);
2378 }
2379
2380 /** 
2381  * mono_image_get_entry_point:
2382  * \param image the image where the entry point will be looked up.
2383  * Use this routine to determine the metadata token for method that
2384  * has been flagged as the entry point.
2385  * \returns the token for the entry point method in the image
2386  */
2387 guint32
2388 mono_image_get_entry_point (MonoImage *image)
2389 {
2390         return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2391 }
2392
2393 /**
2394  * mono_image_get_resource:
2395  * \param image the image where the resource will be looked up.
2396  * \param offset The offset to add to the resource
2397  * \param size a pointer to an int where the size of the resource will be stored
2398  *
2399  * This is a low-level routine that fetches a resource from the
2400  * metadata that starts at a given \p offset.  The \p size parameter is
2401  * filled with the data field as encoded in the metadata.
2402  *
2403  * \returns the pointer to the resource whose offset is \p offset.
2404  */
2405 const char*
2406 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2407 {
2408         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2409         MonoCLIHeader *ch = &iinfo->cli_cli_header;
2410         const char* data;
2411
2412         if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2413                 return NULL;
2414         
2415         data = mono_image_rva_map (image, ch->ch_resources.rva);
2416         if (!data)
2417                 return NULL;
2418         data += offset;
2419         if (size)
2420                 *size = read32 (data);
2421         data += 4;
2422         return data;
2423 }
2424
2425 // Returning NULL with no error set will be interpeted as "not found"
2426 MonoImage*
2427 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2428 {
2429         char *base_dir, *name;
2430         MonoImage *res;
2431         MonoTableInfo  *t = &image->tables [MONO_TABLE_FILE];
2432         const char *fname;
2433         guint32 fname_id;
2434
2435         error_init (error);
2436
2437         if (fileidx < 1 || fileidx > t->rows)
2438                 return NULL;
2439
2440         mono_image_lock (image);
2441         if (image->files && image->files [fileidx - 1]) {
2442                 mono_image_unlock (image);
2443                 return image->files [fileidx - 1];
2444         }
2445         mono_image_unlock (image);
2446
2447         fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2448         fname = mono_metadata_string_heap (image, fname_id);
2449         base_dir = g_path_get_dirname (image->name);
2450         name = g_build_filename (base_dir, fname, NULL);
2451         res = mono_image_open (name, NULL);
2452         if (!res)
2453                 goto done;
2454
2455         mono_image_lock (image);
2456         if (image->files && image->files [fileidx - 1]) {
2457                 MonoImage *old = res;
2458                 res = image->files [fileidx - 1];
2459                 mono_image_unlock (image);
2460                 mono_image_close (old);
2461         } else {
2462                 int i;
2463                 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2464                 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2465                         mono_image_unlock (image);
2466                         mono_image_close (res);
2467                         return NULL;
2468                 }
2469
2470                 for (i = 0; i < res->module_count; ++i) {
2471                         if (res->modules [i] && !res->modules [i]->assembly)
2472                                 res->modules [i]->assembly = image->assembly;
2473                 }
2474
2475                 if (!image->files) {
2476                         image->files = g_new0 (MonoImage*, t->rows);
2477                         image->file_count = t->rows;
2478                 }
2479                 image->files [fileidx - 1] = res;
2480                 mono_image_unlock (image);
2481                 /* vtable fixup can't happen with the image lock held */
2482 #ifdef HOST_WIN32
2483                 if (res->is_module_handle)
2484                         mono_image_fixup_vtable (res);
2485 #endif
2486         }
2487
2488 done:
2489         g_free (name);
2490         g_free (base_dir);
2491         return res;
2492 }
2493
2494 /**
2495  * mono_image_load_file_for_image:
2496  */
2497 MonoImage*
2498 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2499 {
2500         MonoError error;
2501         MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2502         mono_error_assert_ok (&error);
2503         return result;
2504 }
2505
2506 /**
2507  * mono_image_get_strong_name:
2508  * \param image a MonoImage
2509  * \param size a \c guint32 pointer, or NULL.
2510  *
2511  * If the image has a strong name, and \p size is not NULL, the value
2512  * pointed to by size will have the size of the strong name.
2513  *
2514  * \returns NULL if the image does not have a strong name, or a
2515  * pointer to the public key.
2516  */
2517 const char*
2518 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2519 {
2520         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2521         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2522         const char* data;
2523
2524         if (!de->size || !de->rva)
2525                 return NULL;
2526         data = mono_image_rva_map (image, de->rva);
2527         if (!data)
2528                 return NULL;
2529         if (size)
2530                 *size = de->size;
2531         return data;
2532 }
2533
2534 /**
2535  * mono_image_strong_name_position:
2536  * \param image a \c MonoImage
2537  * \param size a \c guint32 pointer, or NULL.
2538  *
2539  * If the image has a strong name, and \p size is not NULL, the value
2540  * pointed to by size will have the size of the strong name.
2541  *
2542  * \returns the position within the image file where the strong name
2543  * is stored.
2544  */
2545 guint32
2546 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2547 {
2548         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2549         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2550         guint32 pos;
2551
2552         if (size)
2553                 *size = de->size;
2554         if (!de->size || !de->rva)
2555                 return 0;
2556         pos = mono_cli_rva_image_map (image, de->rva);
2557         return pos == INVALID_ADDRESS ? 0 : pos;
2558 }
2559
2560 /**
2561  * mono_image_get_public_key:
2562  * \param image a \c MonoImage
2563  * \param size a \c guint32 pointer, or NULL.
2564  *
2565  * This is used to obtain the public key in the \p image.
2566  * 
2567  * If the image has a public key, and \p size is not NULL, the value
2568  * pointed to by size will have the size of the public key.
2569  * 
2570  * \returns NULL if the image does not have a public key, or a pointer
2571  * to the public key.
2572  */
2573 const char*
2574 mono_image_get_public_key (MonoImage *image, guint32 *size)
2575 {
2576         const char *pubkey;
2577         guint32 len, tok;
2578
2579         if (image_is_dynamic (image)) {
2580                 if (size)
2581                         *size = ((MonoDynamicImage*)image)->public_key_len;
2582                 return (char*)((MonoDynamicImage*)image)->public_key;
2583         }
2584         if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2585                 return NULL;
2586         tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2587         if (!tok)
2588                 return NULL;
2589         pubkey = mono_metadata_blob_heap (image, tok);
2590         len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2591         if (size)
2592                 *size = len;
2593         return pubkey;
2594 }
2595
2596 /**
2597  * mono_image_get_name:
2598  * \param name a \c MonoImage
2599  * \returns the name of the assembly.
2600  */
2601 const char*
2602 mono_image_get_name (MonoImage *image)
2603 {
2604         return image->assembly_name;
2605 }
2606
2607 /**
2608  * mono_image_get_filename:
2609  * \param image a \c MonoImage
2610  * Used to get the filename that hold the actual \c MonoImage
2611  * \returns the filename.
2612  */
2613 const char*
2614 mono_image_get_filename (MonoImage *image)
2615 {
2616         return image->name;
2617 }
2618
2619 /**
2620  * mono_image_get_guid:
2621  */
2622 const char*
2623 mono_image_get_guid (MonoImage *image)
2624 {
2625         return image->guid;
2626 }
2627
2628 /**
2629  * mono_image_get_table_info:
2630  */
2631 const MonoTableInfo*
2632 mono_image_get_table_info (MonoImage *image, int table_id)
2633 {
2634         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2635                 return NULL;
2636         return &image->tables [table_id];
2637 }
2638
2639 /**
2640  * mono_image_get_table_rows:
2641  */
2642 int
2643 mono_image_get_table_rows (MonoImage *image, int table_id)
2644 {
2645         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2646                 return 0;
2647         return image->tables [table_id].rows;
2648 }
2649
2650 /**
2651  * mono_table_info_get_rows:
2652  */
2653 int
2654 mono_table_info_get_rows (const MonoTableInfo *table)
2655 {
2656         return table->rows;
2657 }
2658
2659 /**
2660  * mono_image_get_assembly:
2661  * \param image the \c MonoImage .
2662  * Use this routine to get the assembly that owns this image.
2663  * \returns the assembly that holds this image.
2664  */
2665 MonoAssembly* 
2666 mono_image_get_assembly (MonoImage *image)
2667 {
2668         return image->assembly;
2669 }
2670
2671 /**
2672  * mono_image_is_dynamic:
2673  * \param image the \c MonoImage
2674  *
2675  * Determines if the given image was created dynamically through the
2676  * \c System.Reflection.Emit API
2677  * \returns TRUE if the image was created dynamically, FALSE if not.
2678  */
2679 gboolean
2680 mono_image_is_dynamic (MonoImage *image)
2681 {
2682         return image_is_dynamic (image);
2683 }
2684
2685 /**
2686  * mono_image_has_authenticode_entry:
2687  * \param image the \c MonoImage
2688  * Use this routine to determine if the image has a Authenticode
2689  * Certificate Table.
2690  * \returns TRUE if the image contains an authenticode entry in the PE
2691  * directory.
2692  */
2693 gboolean
2694 mono_image_has_authenticode_entry (MonoImage *image)
2695 {
2696         MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2697         MonoDotNetHeader *header = &iinfo->cli_header;
2698         if (!header)
2699                 return FALSE;
2700         MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2701         // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2702         return ((de->rva != 0) && (de->size > 8));
2703 }
2704
2705 gpointer
2706 mono_image_alloc (MonoImage *image, guint size)
2707 {
2708         gpointer res;
2709
2710 #ifndef DISABLE_PERFCOUNTERS
2711         InterlockedAdd (&mono_perfcounters->loader_bytes, size);
2712 #endif
2713         mono_image_lock (image);
2714         res = mono_mempool_alloc (image->mempool, size);
2715         mono_image_unlock (image);
2716
2717         return res;
2718 }
2719
2720 gpointer
2721 mono_image_alloc0 (MonoImage *image, guint size)
2722 {
2723         gpointer res;
2724
2725 #ifndef DISABLE_PERFCOUNTERS
2726         InterlockedAdd (&mono_perfcounters->loader_bytes, size);
2727 #endif
2728         mono_image_lock (image);
2729         res = mono_mempool_alloc0 (image->mempool, size);
2730         mono_image_unlock (image);
2731
2732         return res;
2733 }
2734
2735 char*
2736 mono_image_strdup (MonoImage *image, const char *s)
2737 {
2738         char *res;
2739
2740 #ifndef DISABLE_PERFCOUNTERS
2741         InterlockedAdd (&mono_perfcounters->loader_bytes, strlen (s));
2742 #endif
2743         mono_image_lock (image);
2744         res = mono_mempool_strdup (image->mempool, s);
2745         mono_image_unlock (image);
2746
2747         return res;
2748 }
2749
2750 char*
2751 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2752 {
2753         char *buf;
2754         mono_image_lock (image);
2755         buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2756         mono_image_unlock (image);
2757 #ifndef DISABLE_PERFCOUNTERS
2758         InterlockedAdd (&mono_perfcounters->loader_bytes, strlen (buf));
2759 #endif
2760         return buf;
2761 }
2762
2763 char*
2764 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2765 {
2766         char *buf;
2767         va_list args;
2768
2769         va_start (args, format);
2770         buf = mono_image_strdup_vprintf (image, format, args);
2771         va_end (args);
2772         return buf;
2773 }
2774
2775 GList*
2776 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2777 {
2778         GList *new_list;
2779         
2780         new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2781         new_list->data = data;
2782         new_list->prev = list ? list->prev : NULL;
2783     new_list->next = list;
2784
2785     if (new_list->prev)
2786             new_list->prev->next = new_list;
2787     if (list)
2788             list->prev = new_list;
2789
2790         return new_list;
2791 }
2792
2793 GSList*
2794 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2795 {
2796         GSList *new_list;
2797
2798         new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2799         new_list->data = data;
2800         new_list->next = NULL;
2801
2802         return g_slist_concat (list, new_list);
2803 }
2804
2805 void
2806 mono_image_lock (MonoImage *image)
2807 {
2808         mono_locks_os_acquire (&image->lock, ImageDataLock);
2809 }
2810
2811 void
2812 mono_image_unlock (MonoImage *image)
2813 {
2814         mono_locks_os_release (&image->lock, ImageDataLock);
2815 }
2816
2817
2818 /**
2819  * mono_image_property_lookup:
2820  * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2821  *
2822  * LOCKING: Takes the image lock
2823  */
2824 gpointer 
2825 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2826 {
2827         gpointer res;
2828
2829         mono_image_lock (image);
2830         res = mono_property_hash_lookup (image->property_hash, subject, property);
2831         mono_image_unlock (image);
2832
2833         return res;
2834 }
2835
2836 /**
2837  * mono_image_property_insert:
2838  * Insert a new property \p property with value \p value on \p subject in \p
2839  * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2840  *
2841  * LOCKING: Takes the image lock
2842  */
2843 void
2844 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2845 {
2846         CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2847         mono_image_lock (image);
2848         mono_property_hash_insert (image->property_hash, subject, property, value);
2849         mono_image_unlock (image);
2850 }
2851
2852 /**
2853  * mono_image_property_remove:
2854  * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2855  *
2856  * LOCKING: Takes the image lock
2857  */
2858 void
2859 mono_image_property_remove (MonoImage *image, gpointer subject)
2860 {
2861         mono_image_lock (image);
2862         mono_property_hash_remove_object (image->property_hash, subject);
2863         mono_image_unlock (image);
2864 }
2865
2866 void
2867 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2868 {
2869         MonoImage *image = klass->image;
2870         g_assert (image_is_dynamic (image));
2871         mono_image_lock (image);
2872         image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2873         mono_image_unlock (image);
2874 }
2875
2876 // 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.
2877
2878 /**
2879  * mono_find_image_owner:
2880  *
2881  * Find the image, if any, which a given pointer is located in the memory of.
2882  */
2883 MonoImage *
2884 mono_find_image_owner (void *ptr)
2885 {
2886         mono_images_lock ();
2887
2888         MonoImage *owner = NULL;
2889
2890         // Iterate over both by-path image hashes
2891         const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2892         int hash_idx;
2893         for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2894         {
2895                 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2896                 GHashTableIter iter;
2897                 MonoImage *image;
2898
2899                 // Iterate over images within a hash
2900                 g_hash_table_iter_init (&iter, target);
2901                 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2902                 {
2903                         mono_image_lock (image);
2904                         if (mono_mempool_contains_addr (image->mempool, ptr))
2905                                 owner = image;
2906                         mono_image_unlock (image);
2907                 }
2908         }
2909
2910         mono_images_unlock ();
2911
2912         return owner;
2913 }