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