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