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