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