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