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