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