[packaging] Bundle the msvc compiled monograph.exe on Windows
[mono-project.git] / mono / metadata / image.c
blob54d30ec04be97cb475de1aad2651120a193d3dea
1 /**
2 * \file
3 * Routines for manipulating an image stored in an
4 * extended PE/COFF file.
5 *
6 * Authors:
7 * Miguel de Icaza (miguel@ximian.com)
8 * Paolo Molaro (lupus@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
15 #include <config.h>
16 #include <stdio.h>
17 #include <glib.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <string.h>
21 #include "image.h"
22 #include "cil-coff.h"
23 #include "mono-endian.h"
24 #include "tabledefs.h"
25 #include "tokentype.h"
26 #include "metadata-internals.h"
27 #include "profiler-private.h"
28 #include "loader.h"
29 #include "marshal.h"
30 #include "coree.h"
31 #include <mono/metadata/exception-internals.h>
32 #include <mono/utils/checked-build.h>
33 #include <mono/utils/mono-logger-internals.h>
34 #include <mono/utils/mono-path.h>
35 #include <mono/utils/mono-mmap.h>
36 #include <mono/utils/mono-io-portability.h>
37 #include <mono/utils/atomic.h>
38 #include <mono/metadata/class-internals.h>
39 #include <mono/metadata/assembly.h>
40 #include <mono/metadata/object-internals.h>
41 #include <mono/metadata/security-core-clr.h>
42 #include <mono/metadata/verify-internals.h>
43 #include <mono/metadata/verify.h>
44 #include <mono/metadata/image-internals.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 #include <mono/metadata/w32error.h>
52 #define INVALID_ADDRESS 0xffffffff
54 // Amount initially reserved in each image's mempool.
55 // FIXME: This number is arbitrary, a more practical number should be found
56 #define INITIAL_IMAGE_SIZE 512
59 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
60 * There are four, for all combinations of [look up by path or assembly name?]
61 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
63 enum {
64 IMAGES_HASH_PATH = 0,
65 IMAGES_HASH_PATH_REFONLY = 1,
66 IMAGES_HASH_NAME = 2,
67 IMAGES_HASH_NAME_REFONLY = 3,
68 IMAGES_HASH_COUNT = 4
70 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
72 static GHashTable *
73 get_loaded_images_hash (gboolean refonly)
75 int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
76 return loaded_images_hashes [idx];
79 static GHashTable *
80 get_loaded_images_by_name_hash (gboolean refonly)
82 int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
83 return loaded_images_hashes [idx];
86 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
87 // Can be used on modules loaded through either the "file" or "module" mechanism
88 static gboolean
89 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
91 // Assembly to assign
92 MonoAssembly *assembly = assemblyImage->assembly;
94 while (1) {
95 // Assembly currently assigned
96 MonoAssembly *assemblyOld = image->assembly;
97 if (assemblyOld) {
98 if (assemblyOld == assembly)
99 return TRUE;
100 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);
101 return FALSE;
103 gpointer result = mono_atomic_xchg_ptr((gpointer *)&image->assembly, assembly);
104 if (result == assembly)
105 return TRUE;
109 static gboolean debug_assembly_unload = FALSE;
111 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
112 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
113 static gboolean mutex_inited;
114 static mono_mutex_t images_mutex;
116 static void install_pe_loader (void);
118 typedef struct ImageUnloadHook ImageUnloadHook;
119 struct ImageUnloadHook {
120 MonoImageUnloadFunc func;
121 gpointer user_data;
124 static GSList *image_unload_hooks;
126 void
127 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
129 ImageUnloadHook *hook;
131 g_return_if_fail (func != NULL);
133 hook = g_new0 (ImageUnloadHook, 1);
134 hook->func = func;
135 hook->user_data = user_data;
136 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
139 void
140 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
142 GSList *l;
143 ImageUnloadHook *hook;
145 for (l = image_unload_hooks; l; l = l->next) {
146 hook = (ImageUnloadHook *)l->data;
148 if (hook->func == func && hook->user_data == user_data) {
149 g_free (hook);
150 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
151 break;
156 static void
157 mono_image_invoke_unload_hook (MonoImage *image)
159 GSList *l;
160 ImageUnloadHook *hook;
162 for (l = image_unload_hooks; l; l = l->next) {
163 hook = (ImageUnloadHook *)l->data;
165 hook->func (image, hook->user_data);
169 static GSList *image_loaders;
171 void
172 mono_install_image_loader (const MonoImageLoader *loader)
174 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
177 /* returns offset relative to image->raw_data */
178 guint32
179 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
181 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
182 const int top = iinfo->cli_section_count;
183 MonoSectionTable *tables = iinfo->cli_section_tables;
184 int i;
186 if (image->metadata_only)
187 return addr;
189 for (i = 0; i < top; i++){
190 if ((addr >= tables->st_virtual_address) &&
191 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
192 #ifdef HOST_WIN32
193 if (image->is_module_handle)
194 return addr;
195 #endif
196 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
198 tables++;
200 return INVALID_ADDRESS;
204 * mono_image_rva_map:
205 * \param image a \c MonoImage
206 * \param addr relative virtual address (RVA)
208 * This is a low-level routine used by the runtime to map relative
209 * virtual address (RVA) into their location in memory.
211 * \returns the address in memory for the given RVA, or NULL if the
212 * RVA is not valid for this image.
214 char *
215 mono_image_rva_map (MonoImage *image, guint32 addr)
217 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
218 const int top = iinfo->cli_section_count;
219 MonoSectionTable *tables = iinfo->cli_section_tables;
220 int i;
222 #ifdef HOST_WIN32
223 if (image->is_module_handle) {
224 if (addr && addr < image->raw_data_len)
225 return image->raw_data + addr;
226 else
227 return NULL;
229 #endif
231 for (i = 0; i < top; i++){
232 if ((addr >= tables->st_virtual_address) &&
233 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
234 if (!iinfo->cli_sections [i]) {
235 if (!mono_image_ensure_section_idx (image, i))
236 return NULL;
238 return (char*)iinfo->cli_sections [i] +
239 (addr - tables->st_virtual_address);
241 tables++;
243 return NULL;
247 * mono_images_init:
249 * Initialize the global variables used by this module.
251 void
252 mono_images_init (void)
254 mono_os_mutex_init_recursive (&images_mutex);
256 int hash_idx;
257 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
258 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
260 debug_assembly_unload = g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
262 install_pe_loader ();
264 mutex_inited = TRUE;
268 * mono_images_cleanup:
270 * Free all resources used by this module.
272 void
273 mono_images_cleanup (void)
275 GHashTableIter iter;
276 MonoImage *image;
278 mono_os_mutex_destroy (&images_mutex);
280 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
281 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
282 g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
283 while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
284 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
286 int hash_idx;
287 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
288 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
290 mutex_inited = FALSE;
294 * mono_image_ensure_section_idx:
295 * \param image The image we are operating on
296 * \param section section number that we will load/map into memory
298 * This routine makes sure that we have an in-memory copy of
299 * an image section (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
301 * \returns TRUE on success
304 mono_image_ensure_section_idx (MonoImage *image, int section)
306 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
307 MonoSectionTable *sect;
309 g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
311 if (iinfo->cli_sections [section] != NULL)
312 return TRUE;
314 sect = &iinfo->cli_section_tables [section];
316 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
317 return FALSE;
318 #ifdef HOST_WIN32
319 if (image->is_module_handle)
320 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
321 else
322 #endif
323 /* FIXME: we ignore the writable flag since we don't patch the binary */
324 iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
325 return TRUE;
329 * mono_image_ensure_section:
330 * \param image The image we are operating on
331 * \param section section name that we will load/map into memory
333 * This routine makes sure that we have an in-memory copy of
334 * an image section (.text, .rsrc, .data).
336 * \returns TRUE on success
339 mono_image_ensure_section (MonoImage *image, const char *section)
341 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
342 int i;
344 for (i = 0; i < ii->cli_section_count; i++){
345 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
346 continue;
348 return mono_image_ensure_section_idx (image, i);
350 return FALSE;
353 static int
354 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
356 const int top = iinfo->cli_header.coff.coff_sections;
357 int i;
359 iinfo->cli_section_count = top;
360 iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
361 iinfo->cli_sections = g_new0 (void *, top);
363 for (i = 0; i < top; i++){
364 MonoSectionTable *t = &iinfo->cli_section_tables [i];
366 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
367 return FALSE;
368 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
369 offset += sizeof (MonoSectionTable);
371 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
372 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
373 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
374 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
375 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
376 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
377 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
378 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
379 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
380 t->st_flags = GUINT32_FROM_LE (t->st_flags);
381 #endif
382 /* consistency checks here */
385 return TRUE;
388 gboolean
389 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
391 guint32 offset;
393 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
394 if (offset == INVALID_ADDRESS)
395 return FALSE;
397 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
398 return FALSE;
399 memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
401 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
402 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
403 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
404 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
405 SWAP32 (iinfo->cli_cli_header.ch_size);
406 SWAP32 (iinfo->cli_cli_header.ch_flags);
407 SWAP32 (iinfo->cli_cli_header.ch_entry_point);
408 SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
409 SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
410 SWAPPDE (iinfo->cli_cli_header.ch_metadata);
411 SWAPPDE (iinfo->cli_cli_header.ch_resources);
412 SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
413 SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
414 SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
415 SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
416 SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
417 SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
418 SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
419 SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
420 SWAPPDE (iinfo->cli_cli_header.ch_module_image);
421 SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
422 SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
423 SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
424 SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
425 #undef SWAP32
426 #undef SWAP16
427 #undef SWAPPDE
428 #endif
429 /* Catch new uses of the fields that are supposed to be zero */
431 if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
432 (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
433 (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
434 (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
435 (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
436 (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
437 (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
438 (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
439 (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
442 * No need to scare people who are testing this, I am just
443 * labelling this as a LAMESPEC
445 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
449 return TRUE;
452 static gboolean
453 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
455 guint32 offset, size;
456 guint16 streams;
457 int i;
458 guint32 pad;
459 char *ptr;
461 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
462 if (offset == INVALID_ADDRESS)
463 return FALSE;
465 size = iinfo->cli_cli_header.ch_metadata.size;
467 if (offset + size > image->raw_data_len)
468 return FALSE;
469 image->raw_metadata = image->raw_data + offset;
471 /* 24.2.1: Metadata root starts here */
472 ptr = image->raw_metadata;
474 if (strncmp (ptr, "BSJB", 4) == 0){
475 guint32 version_string_len;
477 ptr += 4;
478 image->md_version_major = read16 (ptr);
479 ptr += 2;
480 image->md_version_minor = read16 (ptr);
481 ptr += 6;
483 version_string_len = read32 (ptr);
484 ptr += 4;
485 image->version = g_strndup (ptr, version_string_len);
486 ptr += version_string_len;
487 pad = ptr - image->raw_metadata;
488 if (pad % 4)
489 ptr += 4 - (pad % 4);
490 } else
491 return FALSE;
493 /* skip over flags */
494 ptr += 2;
496 streams = read16 (ptr);
497 ptr += 2;
499 for (i = 0; i < streams; i++){
500 if (strncmp (ptr + 8, "#~", 3) == 0){
501 image->heap_tables.data = image->raw_metadata + read32 (ptr);
502 image->heap_tables.size = read32 (ptr + 4);
503 ptr += 8 + 3;
504 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
505 image->heap_strings.data = image->raw_metadata + read32 (ptr);
506 image->heap_strings.size = read32 (ptr + 4);
507 ptr += 8 + 9;
508 } else if (strncmp (ptr + 8, "#US", 4) == 0){
509 image->heap_us.data = image->raw_metadata + read32 (ptr);
510 image->heap_us.size = read32 (ptr + 4);
511 ptr += 8 + 4;
512 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
513 image->heap_blob.data = image->raw_metadata + read32 (ptr);
514 image->heap_blob.size = read32 (ptr + 4);
515 ptr += 8 + 6;
516 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
517 image->heap_guid.data = image->raw_metadata + read32 (ptr);
518 image->heap_guid.size = read32 (ptr + 4);
519 ptr += 8 + 6;
520 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
521 image->heap_tables.data = image->raw_metadata + read32 (ptr);
522 image->heap_tables.size = read32 (ptr + 4);
523 ptr += 8 + 3;
524 image->uncompressed_metadata = TRUE;
525 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);
526 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
527 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
528 image->heap_pdb.size = read32 (ptr + 4);
529 ptr += 8 + 5;
530 } else {
531 g_message ("Unknown heap type: %s\n", ptr + 8);
532 ptr += 8 + strlen (ptr + 8) + 1;
534 pad = ptr - image->raw_metadata;
535 if (pad % 4)
536 ptr += 4 - (pad % 4);
539 i = ((MonoImageLoader*)image->loader)->load_tables (image);
541 if (!image->metadata_only) {
542 g_assert (image->heap_guid.data);
543 g_assert (image->heap_guid.size >= 16);
545 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
546 } else {
547 /* PPDB files have no guid */
548 guint8 empty_guid [16];
550 memset (empty_guid, 0, sizeof (empty_guid));
552 image->guid = mono_guid_to_string (empty_guid);
555 return i;
559 * Load representation of logical metadata tables, from the "#~" stream
561 static gboolean
562 load_tables (MonoImage *image)
564 const char *heap_tables = image->heap_tables.data;
565 const guint32 *rows;
566 guint64 valid_mask;
567 int valid = 0, table;
568 int heap_sizes;
570 heap_sizes = heap_tables [6];
571 image->idx_string_wide = ((heap_sizes & 0x01) == 1);
572 image->idx_guid_wide = ((heap_sizes & 0x02) == 2);
573 image->idx_blob_wide = ((heap_sizes & 0x04) == 4);
575 valid_mask = read64 (heap_tables + 8);
576 rows = (const guint32 *) (heap_tables + 24);
578 for (table = 0; table < 64; table++){
579 if ((valid_mask & ((guint64) 1 << table)) == 0){
580 if (table > MONO_TABLE_LAST)
581 continue;
582 image->tables [table].rows = 0;
583 continue;
585 if (table > MONO_TABLE_LAST) {
586 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
587 } else {
588 image->tables [table].rows = read32 (rows);
590 rows++;
591 valid++;
594 image->tables_base = (heap_tables + 24) + (4 * valid);
596 /* They must be the same */
597 g_assert ((const void *) image->tables_base == (const void *) rows);
599 if (image->heap_pdb.size) {
601 * Obtain token sizes from the pdb stream.
603 /* 24 = guid + entry point */
604 int pos = 24;
605 image->referenced_tables = read64 (image->heap_pdb.data + pos);
606 pos += 8;
607 image->referenced_table_rows = g_new0 (int, 64);
608 for (int i = 0; i < 64; ++i) {
609 if (image->referenced_tables & ((guint64)1 << i)) {
610 image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
611 pos += 4;
616 mono_metadata_compute_table_bases (image);
617 return TRUE;
620 gboolean
621 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
623 if (!load_metadata_ptrs (image, iinfo))
624 return FALSE;
626 return load_tables (image);
629 void
630 mono_image_check_for_module_cctor (MonoImage *image)
632 MonoTableInfo *t, *mt;
633 t = &image->tables [MONO_TABLE_TYPEDEF];
634 mt = &image->tables [MONO_TABLE_METHOD];
635 if (image_is_dynamic (image)) {
636 /* FIXME: */
637 image->checked_module_cctor = TRUE;
638 return;
640 if (t->rows >= 1) {
641 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
642 const char *name = mono_metadata_string_heap (image, nameidx);
643 if (strcmp (name, "<Module>") == 0) {
644 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
645 guint32 last_method;
646 if (t->rows > 1)
647 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
648 else
649 last_method = mt->rows;
650 for (; first_method < last_method; first_method++) {
651 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
652 name = mono_metadata_string_heap (image, nameidx);
653 if (strcmp (name, ".cctor") == 0) {
654 image->has_module_cctor = TRUE;
655 image->checked_module_cctor = TRUE;
656 return;
661 image->has_module_cctor = FALSE;
662 image->checked_module_cctor = TRUE;
665 static void
666 load_modules (MonoImage *image)
668 MonoTableInfo *t;
670 if (image->modules)
671 return;
673 t = &image->tables [MONO_TABLE_MODULEREF];
674 image->modules = g_new0 (MonoImage *, t->rows);
675 image->modules_loaded = g_new0 (gboolean, t->rows);
676 image->module_count = t->rows;
680 * mono_image_load_module_checked:
682 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
683 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
685 MonoImage*
686 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
688 MonoTableInfo *t;
689 MonoTableInfo *file_table;
690 int i;
691 char *base_dir;
692 gboolean refonly = image->ref_only;
693 GList *list_iter, *valid_modules = NULL;
694 MonoImageOpenStatus status;
696 error_init (error);
698 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
699 return NULL;
700 if (image->modules_loaded [idx - 1])
701 return image->modules [idx - 1];
703 file_table = &image->tables [MONO_TABLE_FILE];
704 for (i = 0; i < file_table->rows; i++) {
705 guint32 cols [MONO_FILE_SIZE];
706 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
707 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
708 continue;
709 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
712 t = &image->tables [MONO_TABLE_MODULEREF];
713 base_dir = g_path_get_dirname (image->name);
716 char *module_ref;
717 const char *name;
718 guint32 cols [MONO_MODULEREF_SIZE];
719 /* if there is no file table, we try to load the module... */
720 int valid = file_table->rows == 0;
722 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
723 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
724 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
725 /* be safe with string dups, but we could just compare string indexes */
726 if (strcmp (list_iter->data, name) == 0) {
727 valid = TRUE;
728 break;
731 if (valid) {
732 module_ref = g_build_filename (base_dir, name, NULL);
733 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
734 if (moduleImage) {
735 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
736 mono_image_close (moduleImage);
737 g_free (module_ref);
738 g_free (base_dir);
739 g_list_free (valid_modules);
740 return NULL;
743 image->modules [idx - 1] = moduleImage;
745 #ifdef HOST_WIN32
746 if (image->modules [idx - 1]->is_module_handle)
747 mono_image_fixup_vtable (image->modules [idx - 1]);
748 #endif
749 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
751 g_free (module_ref);
755 image->modules_loaded [idx - 1] = TRUE;
757 g_free (base_dir);
758 g_list_free (valid_modules);
760 return image->modules [idx - 1];
764 * mono_image_load_module:
766 MonoImage*
767 mono_image_load_module (MonoImage *image, int idx)
769 ERROR_DECL (error);
770 MonoImage *result = mono_image_load_module_checked (image, idx, error);
771 mono_error_assert_ok (error);
772 return result;
775 static gpointer
776 class_key_extract (gpointer value)
778 MonoClass *klass = (MonoClass *)value;
780 return GUINT_TO_POINTER (m_class_get_type_token (klass));
783 static gpointer*
784 class_next_value (gpointer value)
786 MonoClassDef *klass = (MonoClassDef *)value;
788 return (gpointer*)m_classdef_get_next_class_cache (klass);
792 * mono_image_init:
794 void
795 mono_image_init (MonoImage *image)
797 mono_os_mutex_init_recursive (&image->lock);
798 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
800 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
801 mono_internal_hash_table_init (&image->class_cache,
802 g_direct_hash,
803 class_key_extract,
804 class_next_value);
805 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
807 image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
808 image->memberref_signatures = g_hash_table_new (NULL, NULL);
809 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
810 image->method_signatures = g_hash_table_new (NULL, NULL);
812 image->property_hash = mono_property_hash_new ();
815 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
816 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
817 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
818 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
819 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
820 #else
821 #define SWAP64(x)
822 #define SWAP32(x)
823 #define SWAP16(x)
824 #define SWAPPDE(x)
825 #endif
828 * Returns < 0 to indicate an error.
830 static int
831 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
833 MonoDotNetHeader64 header64;
835 #ifdef HOST_WIN32
836 if (!image->is_module_handle)
837 #endif
838 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
839 return -1;
841 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
843 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
844 return -1;
846 /* endian swap the fields common between PE and PE+ */
847 SWAP32 (header->coff.coff_time);
848 SWAP32 (header->coff.coff_symptr);
849 SWAP32 (header->coff.coff_symcount);
850 SWAP16 (header->coff.coff_machine);
851 SWAP16 (header->coff.coff_sections);
852 SWAP16 (header->coff.coff_opt_header_size);
853 SWAP16 (header->coff.coff_attributes);
854 /* MonoPEHeader */
855 SWAP32 (header->pe.pe_code_size);
856 SWAP32 (header->pe.pe_uninit_data_size);
857 SWAP32 (header->pe.pe_rva_entry_point);
858 SWAP32 (header->pe.pe_rva_code_base);
859 SWAP32 (header->pe.pe_rva_data_base);
860 SWAP16 (header->pe.pe_magic);
862 /* now we are ready for the basic tests */
864 if (header->pe.pe_magic == 0x10B) {
865 offset += sizeof (MonoDotNetHeader);
866 SWAP32 (header->pe.pe_data_size);
867 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
868 return -1;
870 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
871 SWAP32 (header->nt.pe_stack_reserve);
872 SWAP32 (header->nt.pe_stack_commit);
873 SWAP32 (header->nt.pe_heap_reserve);
874 SWAP32 (header->nt.pe_heap_commit);
875 } else if (header->pe.pe_magic == 0x20B) {
876 /* PE32+ file format */
877 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
878 return -1;
879 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
880 offset += sizeof (MonoDotNetHeader64);
881 /* copy the fields already swapped. the last field, pe_data_size, is missing */
882 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
883 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
884 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
886 SWAP64 (header64.nt.pe_image_base);
887 header->nt.pe_image_base = header64.nt.pe_image_base;
888 SWAP64 (header64.nt.pe_stack_reserve);
889 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
890 SWAP64 (header64.nt.pe_stack_commit);
891 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
892 SWAP64 (header64.nt.pe_heap_reserve);
893 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
894 SWAP64 (header64.nt.pe_heap_commit);
895 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
897 header->nt.pe_section_align = header64.nt.pe_section_align;
898 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
899 header->nt.pe_os_major = header64.nt.pe_os_major;
900 header->nt.pe_os_minor = header64.nt.pe_os_minor;
901 header->nt.pe_user_major = header64.nt.pe_user_major;
902 header->nt.pe_user_minor = header64.nt.pe_user_minor;
903 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
904 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
905 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
906 header->nt.pe_image_size = header64.nt.pe_image_size;
907 header->nt.pe_header_size = header64.nt.pe_header_size;
908 header->nt.pe_checksum = header64.nt.pe_checksum;
909 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
910 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
911 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
912 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
914 /* copy the datadir */
915 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
916 } else {
917 return -1;
920 /* MonoPEHeaderNT: not used yet */
921 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
922 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
923 SWAP16 (header->nt.pe_os_major); /* must be 4 */
924 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
925 SWAP16 (header->nt.pe_user_major);
926 SWAP16 (header->nt.pe_user_minor);
927 SWAP16 (header->nt.pe_subsys_major);
928 SWAP16 (header->nt.pe_subsys_minor);
929 SWAP32 (header->nt.pe_reserved_1);
930 SWAP32 (header->nt.pe_image_size);
931 SWAP32 (header->nt.pe_header_size);
932 SWAP32 (header->nt.pe_checksum);
933 SWAP16 (header->nt.pe_subsys_required);
934 SWAP16 (header->nt.pe_dll_flags);
935 SWAP32 (header->nt.pe_loader_flags);
936 SWAP32 (header->nt.pe_data_dir_count);
938 /* MonoDotNetHeader: mostly unused */
939 SWAPPDE (header->datadir.pe_export_table);
940 SWAPPDE (header->datadir.pe_import_table);
941 SWAPPDE (header->datadir.pe_resource_table);
942 SWAPPDE (header->datadir.pe_exception_table);
943 SWAPPDE (header->datadir.pe_certificate_table);
944 SWAPPDE (header->datadir.pe_reloc_table);
945 SWAPPDE (header->datadir.pe_debug);
946 SWAPPDE (header->datadir.pe_copyright);
947 SWAPPDE (header->datadir.pe_global_ptr);
948 SWAPPDE (header->datadir.pe_tls_table);
949 SWAPPDE (header->datadir.pe_load_config_table);
950 SWAPPDE (header->datadir.pe_bound_import);
951 SWAPPDE (header->datadir.pe_iat);
952 SWAPPDE (header->datadir.pe_delay_import_desc);
953 SWAPPDE (header->datadir.pe_cli_header);
954 SWAPPDE (header->datadir.pe_reserved);
956 #ifdef HOST_WIN32
957 if (image->is_module_handle)
958 image->raw_data_len = header->nt.pe_image_size;
959 #endif
961 return offset;
964 gboolean
965 mono_image_load_pe_data (MonoImage *image)
967 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
970 static gboolean
971 pe_image_load_pe_data (MonoImage *image)
973 MonoCLIImageInfo *iinfo;
974 MonoDotNetHeader *header;
975 MonoMSDOSHeader msdos;
976 gint32 offset = 0;
978 iinfo = (MonoCLIImageInfo *)image->image_info;
979 header = &iinfo->cli_header;
981 #ifdef HOST_WIN32
982 if (!image->is_module_handle)
983 #endif
984 if (offset + sizeof (msdos) > image->raw_data_len)
985 goto invalid_image;
986 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
988 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
989 goto invalid_image;
991 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
993 offset = msdos.pe_offset;
995 offset = do_load_header (image, header, offset);
996 if (offset < 0)
997 goto invalid_image;
1000 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1001 * we skip this test.
1002 if (header->coff.coff_machine != 0x14c)
1003 goto invalid_image;
1006 #if 0
1008 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1009 * which produces binaries with 7.0. From Sergey:
1011 * The reason is that MSVC7 uses traditional compile/link
1012 * sequence for CIL executables, and VS.NET (and Framework
1013 * SDK) includes linker version 7, that puts 7.0 in this
1014 * field. That's why it's currently not possible to load VC
1015 * binaries with Mono. This field is pretty much meaningless
1016 * anyway (what linker?).
1018 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1019 goto invalid_image;
1020 #endif
1023 * FIXME: byte swap all addresses here for header.
1026 if (!load_section_tables (image, iinfo, offset))
1027 goto invalid_image;
1029 return TRUE;
1031 invalid_image:
1032 return FALSE;
1035 gboolean
1036 mono_image_load_cli_data (MonoImage *image)
1038 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1041 static gboolean
1042 pe_image_load_cli_data (MonoImage *image)
1044 MonoCLIImageInfo *iinfo;
1045 MonoDotNetHeader *header;
1047 iinfo = (MonoCLIImageInfo *)image->image_info;
1048 header = &iinfo->cli_header;
1050 /* Load the CLI header */
1051 if (!mono_image_load_cli_header (image, iinfo))
1052 return FALSE;
1054 if (!mono_image_load_metadata (image, iinfo))
1055 return FALSE;
1057 return TRUE;
1060 void
1061 mono_image_load_names (MonoImage *image)
1063 /* modules don't have an assembly table row */
1064 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1065 image->assembly_name = mono_metadata_string_heap (image,
1066 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1067 0, MONO_ASSEMBLY_NAME));
1070 /* Portable pdb images don't have a MODULE row */
1071 if (image->tables [MONO_TABLE_MODULE].rows) {
1072 image->module_name = mono_metadata_string_heap (image,
1073 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1074 0, MONO_MODULE_NAME));
1078 static gboolean
1079 pe_image_load_tables (MonoImage *image)
1081 return TRUE;
1084 static gboolean
1085 pe_image_match (MonoImage *image)
1087 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1088 return TRUE;
1089 return FALSE;
1092 static const MonoImageLoader pe_loader = {
1093 pe_image_match,
1094 pe_image_load_pe_data,
1095 pe_image_load_cli_data,
1096 pe_image_load_tables,
1099 static void
1100 install_pe_loader (void)
1102 mono_install_image_loader (&pe_loader);
1106 Ignored assemblies.
1108 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1109 Mono provides its own implementation of those assemblies so it's safe to do so.
1111 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1113 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1115 This is to be removed once a proper fix is shipped through nuget.
1117 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1118 If any assemblies are added/removed, then this should be regenerated with:
1120 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1124 typedef enum {
1125 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1126 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1127 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1128 SYS_NET_HTTP = 3, //System.Net.Http
1129 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1130 SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1131 } IgnoredAssemblyNames;
1133 typedef struct {
1134 int hash;
1135 int assembly_name;
1136 const char guid [40];
1137 } IgnoredAssembly;
1139 typedef struct {
1140 int assembly_name;
1141 guint16 major, minor, build, revision;
1142 } IgnoredAssemblyVersion;
1144 static const char *ignored_assemblies_file_names[] = {
1145 "System.Runtime.InteropServices.RuntimeInformation.dll",
1146 "System.Globalization.Extensions.dll",
1147 "System.IO.Compression.dll",
1148 "System.Net.Http.dll",
1149 "System.Text.Encoding.CodePages.dll",
1150 "System.Threading.Overlapped.dll"
1153 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1155 static const IgnoredAssembly ignored_assemblies [] = {
1156 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1157 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1158 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1159 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1160 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1161 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1162 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1163 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1164 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1165 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1166 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1167 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1168 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1169 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1170 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1171 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1172 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1173 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1174 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1175 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1176 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1177 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1178 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1179 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1180 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1181 IGNORED_ASSEMBLY (0x1FB3F8E8, SYS_GLOBALIZATION_EXT, "B9BA8638-25D2-4A3B-B91F-16B3D3799861", "2.1.100-preview-62617-01 net461"),
1182 IGNORED_ASSEMBLY (0x6AE7C015, SYS_IO_COMPRESSION, "35DD20B5-8766-476B-B5D2-0EA16EF0A946", "2.1.100-preview-62617-01 net461"),
1183 IGNORED_ASSEMBLY (0x4E906129, SYS_NET_HTTP, "27BBDD4C-EAF0-4A95-B172-EE502D76A725", "2.1.100-preview-62617-01 net461"),
1184 IGNORED_ASSEMBLY (0x765A8E04, SYS_RT_INTEROP_RUNTIME_INFO, "E46BA45E-6A63-47CD-AF70-2C3016AFF75A", "2.1.100-preview-62617-01 net461"),
1185 IGNORED_ASSEMBLY (0x66CEDA9, SYS_THREADING_OVERLAPPED, "A0439CB6-A5E6-4813-A76C-13F92ADDDED5", "2.1.100-preview-62617-01 net461"),
1186 IGNORED_ASSEMBLY (0xD3ABE53A, SYS_RT_INTEROP_RUNTIME_INFO, "488CE209-4E5D-40E7-BE8C-F81F2B99F13A", "2.1.100-preview-62617-01 net462"),
1187 IGNORED_ASSEMBLY (0xE16ECCCD, SYS_GLOBALIZATION_EXT, "1A2B9B2A-02F5-4C78-AB0C-7C6D2795CE2B", "2.1.100-preview-62617-01 net471"),
1188 IGNORED_ASSEMBLY (0xE758DAD4, SYS_IO_COMPRESSION, "8DBD1669-97BC-4190-9BD8-738561193741", "2.1.100-preview-62617-01 net471"),
1189 IGNORED_ASSEMBLY (0xA99E866F, SYS_NET_HTTP, "41ACE450-8F44-455A-97AC-0679E5462071", "2.1.100-preview-62617-01 net471"),
1190 IGNORED_ASSEMBLY (0x8BFCB05D, SYS_THREADING_OVERLAPPED, "82D565AC-E41C-4E29-9939-C031C88EDBDD", "2.1.100-preview-62617-01 net471"),
1191 IGNORED_ASSEMBLY (0xFC67D3A7, SYS_RT_INTEROP_RUNTIME_INFO, "FD6C8616-C1D8-43F9-AC17-A1C48A45FDA2", "2.1.100-preview-62617-01 net47"),
1192 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1193 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1194 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1195 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1196 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1197 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1198 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1199 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1200 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1201 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1202 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1203 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1204 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1205 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1206 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1207 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.4.0 net46"),
1208 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1209 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1210 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1211 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46")
1215 static const char *ignored_assemblies_names[] = {
1216 "System.Runtime.InteropServices.RuntimeInformation",
1217 "System.Globalization.Extensions",
1218 "System.IO.Compression",
1219 "System.Net.Http",
1220 "System.Text.Encoding.CodePages",
1221 "System.Threading.Overlapped"
1224 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1226 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1227 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1228 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1229 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1230 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 1, 0, 0),
1231 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1232 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1233 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 2, 0, 0),
1234 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1235 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1236 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1237 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1238 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 2),
1239 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 2, 0, 0),
1240 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1241 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1242 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 2, 0),
1243 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1244 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1245 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1246 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1247 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1248 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1249 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 1, 0, 0)
1252 gboolean
1253 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1255 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1256 if (ignored_assembly_versions [i].major != major ||
1257 ignored_assembly_versions [i].minor != minor ||
1258 ignored_assembly_versions [i].build != build ||
1259 ignored_assembly_versions [i].revision != revision)
1260 continue;
1261 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1262 return TRUE;
1264 return FALSE;
1268 Equivalent C# code:
1269 static void Main () {
1270 string str = "...";
1271 int h = 5381;
1272 for (int i = 0; i < str.Length; ++i)
1273 h = ((h << 5) + h) ^ str[i];
1275 Console.WriteLine ("{0:X}", h);
1278 static int
1279 hash_guid (const char *str)
1281 int h = 5381;
1282 while (*str) {
1283 h = ((h << 5) + h) ^ *str;
1284 ++str;
1287 return h;
1290 static gboolean
1291 is_problematic_image (MonoImage *image)
1293 int h = hash_guid (image->guid);
1295 //TODO make this more cache effiecient.
1296 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1297 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1298 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1299 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1300 size_t needle_len = strlen (needle);
1301 size_t asm_len = strlen (image->name);
1302 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1303 return TRUE;
1306 return FALSE;
1309 static MonoImage *
1310 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1311 gboolean care_about_cli, gboolean care_about_pecoff)
1313 MonoCLIImageInfo *iinfo;
1314 MonoDotNetHeader *header;
1315 GSList *errors = NULL;
1316 GSList *l;
1318 MONO_PROFILER_RAISE (image_loading, (image));
1320 mono_image_init (image);
1322 iinfo = (MonoCLIImageInfo *)image->image_info;
1323 header = &iinfo->cli_header;
1325 if (!image->metadata_only) {
1326 for (l = image_loaders; l; l = l->next) {
1327 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1328 if (loader->match (image)) {
1329 image->loader = loader;
1330 break;
1333 if (!image->loader) {
1334 if (status)
1335 *status = MONO_IMAGE_IMAGE_INVALID;
1336 goto invalid_image;
1339 if (status)
1340 *status = MONO_IMAGE_IMAGE_INVALID;
1342 if (care_about_pecoff == FALSE)
1343 goto done;
1345 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1346 goto invalid_image;
1348 if (!mono_image_load_pe_data (image))
1349 goto invalid_image;
1350 } else {
1351 image->loader = (MonoImageLoader*)&pe_loader;
1354 if (care_about_cli == FALSE) {
1355 goto done;
1358 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1359 goto invalid_image;
1361 if (!mono_image_load_cli_data (image))
1362 goto invalid_image;
1364 if (!image->ref_only && is_problematic_image (image)) {
1365 if (image->load_from_context) {
1366 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1367 } else {
1368 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1369 *status = MONO_IMAGE_IMAGE_INVALID;
1370 goto invalid_image;
1374 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1375 goto invalid_image;
1377 mono_image_load_names (image);
1379 load_modules (image);
1381 done:
1382 MONO_PROFILER_RAISE (image_loaded, (image));
1383 if (status)
1384 *status = MONO_IMAGE_OK;
1386 return image;
1388 invalid_image:
1389 if (errors) {
1390 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1391 g_warning ("Could not load image %s due to %s", image->name, info->message);
1392 mono_free_verify_list (errors);
1394 MONO_PROFILER_RAISE (image_failed, (image));
1395 mono_image_close (image);
1396 return NULL;
1399 static MonoImage *
1400 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1401 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1403 MonoCLIImageInfo *iinfo;
1404 MonoImage *image;
1405 MonoFileMap *filed;
1407 if ((filed = mono_file_map_open (fname)) == NULL){
1408 if (IS_PORTABILITY_SET) {
1409 gchar *ffname = mono_portability_find_file (fname, TRUE);
1410 if (ffname) {
1411 filed = mono_file_map_open (ffname);
1412 g_free (ffname);
1416 if (filed == NULL) {
1417 if (status)
1418 *status = MONO_IMAGE_ERROR_ERRNO;
1419 return NULL;
1423 image = g_new0 (MonoImage, 1);
1424 image->raw_buffer_used = TRUE;
1425 image->raw_data_len = mono_file_map_size (filed);
1426 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);
1427 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1428 if (!image->raw_data) {
1429 image->fileio_used = TRUE;
1430 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);
1432 #endif
1433 if (!image->raw_data) {
1434 mono_file_map_close (filed);
1435 g_free (image);
1436 if (status)
1437 *status = MONO_IMAGE_IMAGE_INVALID;
1438 return NULL;
1440 iinfo = g_new0 (MonoCLIImageInfo, 1);
1441 image->image_info = iinfo;
1442 image->name = mono_path_resolve_symlinks (fname);
1443 image->ref_only = refonly;
1444 image->metadata_only = metadata_only;
1445 image->load_from_context = load_from_context;
1446 image->ref_count = 1;
1447 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1448 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1450 mono_file_map_close (filed);
1451 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1455 * mono_image_loaded_full:
1456 * \param name path or assembly name of the image to load
1457 * \param refonly Check with respect to reflection-only loads?
1459 * This routine verifies that the given image is loaded.
1460 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1462 * \returns the loaded \c MonoImage, or NULL on failure.
1464 MonoImage *
1465 mono_image_loaded_full (const char *name, gboolean refonly)
1467 MonoImage *res;
1469 mono_images_lock ();
1470 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1471 if (!res)
1472 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1473 mono_images_unlock ();
1475 return res;
1479 * mono_image_loaded:
1480 * \param name path or assembly name of the image to load
1481 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1482 * \returns the loaded \c MonoImage, or NULL on failure.
1484 MonoImage *
1485 mono_image_loaded (const char *name)
1487 return mono_image_loaded_full (name, FALSE);
1490 typedef struct {
1491 MonoImage *res;
1492 const char* guid;
1493 } GuidData;
1495 static void
1496 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1498 GuidData *data = (GuidData *)user_data;
1499 MonoImage *image;
1501 if (data->res)
1502 return;
1503 image = (MonoImage *)val;
1504 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1505 data->res = image;
1509 * mono_image_loaded_by_guid_full:
1511 MonoImage *
1512 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1514 GuidData data;
1515 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1516 data.res = NULL;
1517 data.guid = guid;
1519 mono_images_lock ();
1520 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1521 mono_images_unlock ();
1522 return data.res;
1526 * mono_image_loaded_by_guid:
1528 MonoImage *
1529 mono_image_loaded_by_guid (const char *guid)
1531 return mono_image_loaded_by_guid_full (guid, FALSE);
1534 static MonoImage *
1535 register_image (MonoImage *image)
1537 MonoImage *image2;
1538 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1540 mono_images_lock ();
1541 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1543 if (image2) {
1544 /* Somebody else beat us to it */
1545 mono_image_addref (image2);
1546 mono_images_unlock ();
1547 mono_image_close (image);
1548 return image2;
1551 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1552 g_hash_table_insert (loaded_images, image->name, image);
1553 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1554 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1555 mono_images_unlock ();
1557 return image;
1560 MonoImage *
1561 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1563 MonoCLIImageInfo *iinfo;
1564 MonoImage *image;
1565 char *datac;
1567 if (!data || !data_len) {
1568 if (status)
1569 *status = MONO_IMAGE_IMAGE_INVALID;
1570 return NULL;
1572 datac = data;
1573 if (need_copy) {
1574 datac = (char *)g_try_malloc (data_len);
1575 if (!datac) {
1576 if (status)
1577 *status = MONO_IMAGE_ERROR_ERRNO;
1578 return NULL;
1580 memcpy (datac, data, data_len);
1583 image = g_new0 (MonoImage, 1);
1584 image->raw_data = datac;
1585 image->raw_data_len = data_len;
1586 image->raw_data_allocated = need_copy;
1587 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1588 iinfo = g_new0 (MonoCLIImageInfo, 1);
1589 image->image_info = iinfo;
1590 image->ref_only = refonly;
1591 image->metadata_only = metadata_only;
1592 image->ref_count = 1;
1594 image = do_mono_image_load (image, status, TRUE, TRUE);
1595 if (image == NULL)
1596 return NULL;
1598 return register_image (image);
1602 * mono_image_open_from_data_with_name:
1604 MonoImage *
1605 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1607 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1611 * mono_image_open_from_data_full:
1613 MonoImage *
1614 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1616 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1620 * mono_image_open_from_data:
1622 MonoImage *
1623 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1625 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1628 #ifdef HOST_WIN32
1629 /* fname is not duplicated. */
1630 MonoImage*
1631 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1633 MonoImage* image;
1634 MonoCLIImageInfo* iinfo;
1636 image = g_new0 (MonoImage, 1);
1637 image->raw_data = (char*) module_handle;
1638 image->is_module_handle = TRUE;
1639 iinfo = g_new0 (MonoCLIImageInfo, 1);
1640 image->image_info = iinfo;
1641 image->name = fname;
1642 image->ref_count = has_entry_point ? 0 : 1;
1643 image->has_entry_point = has_entry_point;
1645 image = do_mono_image_load (image, status, TRUE, TRUE);
1646 if (image == NULL)
1647 return NULL;
1649 return register_image (image);
1651 #endif
1654 * mono_image_open_full:
1656 MonoImage *
1657 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1659 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1662 MonoImage *
1663 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1665 MonoImage *image;
1666 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1667 char *absfname;
1669 g_return_val_if_fail (fname != NULL, NULL);
1671 #ifdef HOST_WIN32
1672 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1673 // then assemblies need to be loaded with LoadLibrary:
1674 if (!refonly && coree_module_handle) {
1675 HMODULE module_handle;
1676 guint16 *fname_utf16;
1677 DWORD last_error;
1679 absfname = mono_path_resolve_symlinks (fname);
1680 fname_utf16 = NULL;
1682 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1683 mono_images_lock ();
1684 image = g_hash_table_lookup (loaded_images, absfname);
1685 if (image) { // Image already loaded
1686 g_assert (image->is_module_handle);
1687 if (image->has_entry_point && image->ref_count == 0) {
1688 /* Increment reference count on images loaded outside of the runtime. */
1689 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1690 /* The image is already loaded because _CorDllMain removes images from the hash. */
1691 module_handle = LoadLibrary (fname_utf16);
1692 g_assert (module_handle == (HMODULE) image->raw_data);
1694 mono_image_addref (image);
1695 mono_images_unlock ();
1696 if (fname_utf16)
1697 g_free (fname_utf16);
1698 g_free (absfname);
1699 return image;
1702 // Image not loaded, load it now
1703 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1704 module_handle = MonoLoadImage (fname_utf16);
1705 if (status && module_handle == NULL)
1706 last_error = mono_w32error_get_last ();
1708 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1709 image = g_hash_table_lookup (loaded_images, absfname);
1710 if (image)
1711 mono_image_addref (image);
1712 mono_images_unlock ();
1714 g_free (fname_utf16);
1716 if (module_handle == NULL) {
1717 g_assert (!image);
1718 g_free (absfname);
1719 if (status) {
1720 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1721 *status = MONO_IMAGE_IMAGE_INVALID;
1722 else {
1723 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1724 errno = ENOENT;
1725 else
1726 errno = 0;
1729 return NULL;
1732 if (image) {
1733 g_assert (image->is_module_handle);
1734 g_assert (image->has_entry_point);
1735 g_free (absfname);
1736 return image;
1739 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1741 #endif
1743 absfname = mono_path_resolve_symlinks (fname);
1746 * The easiest solution would be to do all the loading inside the mutex,
1747 * but that would lead to scalability problems. So we let the loading
1748 * happen outside the mutex, and if multiple threads happen to load
1749 * the same image, we discard all but the first copy.
1751 mono_images_lock ();
1752 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1753 g_free (absfname);
1755 if (image) { // Image already loaded
1756 mono_image_addref (image);
1757 mono_images_unlock ();
1758 return image;
1760 mono_images_unlock ();
1762 // Image not loaded, load it now
1763 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1764 if (image == NULL)
1765 return NULL;
1767 return register_image (image);
1771 * mono_image_open:
1772 * \param fname filename that points to the module we want to open
1773 * \param status An error condition is returned in this field
1774 * \returns An open image of type \c MonoImage or NULL on error.
1775 * The caller holds a temporary reference to the returned image which should be cleared
1776 * when no longer needed by calling \c mono_image_close.
1777 * if NULL, then check the value of \p status for details on the error
1779 MonoImage *
1780 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1782 return mono_image_open_full (fname, status, FALSE);
1786 * mono_pe_file_open:
1787 * \param fname filename that points to the module we want to open
1788 * \param status An error condition is returned in this field
1789 * \returns An open image of type \c MonoImage or NULL on error. if
1790 * NULL, then check the value of \p status for details on the error.
1791 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
1792 * It's just a PE file loader, used for \c FileVersionInfo. It also does
1793 * not use the image cache.
1795 MonoImage *
1796 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1798 g_return_val_if_fail (fname != NULL, NULL);
1800 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1804 * mono_image_open_raw
1805 * \param fname filename that points to the module we want to open
1806 * \param status An error condition is returned in this field
1807 * \returns an image without loading neither pe or cli data.
1808 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1810 MonoImage *
1811 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1813 g_return_val_if_fail (fname != NULL, NULL);
1815 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1819 * mono_image_open_metadata_only:
1821 * Open an image which contains metadata only without a PE header.
1823 MonoImage *
1824 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1826 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1830 * mono_image_fixup_vtable:
1832 void
1833 mono_image_fixup_vtable (MonoImage *image)
1835 #ifdef HOST_WIN32
1836 MonoCLIImageInfo *iinfo;
1837 MonoPEDirEntry *de;
1838 MonoVTableFixup *vtfixup;
1839 int count;
1840 gpointer slot;
1841 guint16 slot_type;
1842 int slot_count;
1844 g_assert (image->is_module_handle);
1846 iinfo = image->image_info;
1847 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1848 if (!de->rva || !de->size)
1849 return;
1850 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1851 if (!vtfixup)
1852 return;
1854 count = de->size / sizeof (MonoVTableFixup);
1855 while (count--) {
1856 if (!vtfixup->rva || !vtfixup->count)
1857 continue;
1859 slot = mono_image_rva_map (image, vtfixup->rva);
1860 g_assert (slot);
1861 slot_type = vtfixup->type;
1862 slot_count = vtfixup->count;
1863 if (slot_type & VTFIXUP_TYPE_32BIT)
1864 while (slot_count--) {
1865 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1866 slot = ((guint32*) slot) + 1;
1868 else if (slot_type & VTFIXUP_TYPE_64BIT)
1869 while (slot_count--) {
1870 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1871 slot = ((guint32*) slot) + 1;
1873 else
1874 g_assert_not_reached();
1876 vtfixup++;
1878 #else
1879 g_assert_not_reached();
1880 #endif
1883 static void
1884 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1886 g_hash_table_destroy ((GHashTable*)val);
1890 static void
1891 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1893 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1897 static void
1898 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1900 g_slist_free ((GSList*)val);
1904 * mono_image_addref:
1905 * \param image The image file we wish to add a reference to
1906 * Increases the reference count of an image.
1908 void
1909 mono_image_addref (MonoImage *image)
1911 mono_atomic_inc_i32 (&image->ref_count);
1914 void
1915 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1917 stream->alloc_size = stream->index = stream->offset = 0;
1918 g_free (stream->data);
1919 stream->data = NULL;
1920 if (stream->hash) {
1921 g_hash_table_destroy (stream->hash);
1922 stream->hash = NULL;
1926 static inline void
1927 free_hash (GHashTable *hash)
1929 if (hash)
1930 g_hash_table_destroy (hash);
1933 void
1934 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1936 free_hash (cache->delegate_invoke_cache);
1937 free_hash (cache->delegate_begin_invoke_cache);
1938 free_hash (cache->delegate_end_invoke_cache);
1939 free_hash (cache->runtime_invoke_cache);
1940 free_hash (cache->runtime_invoke_vtype_cache);
1942 free_hash (cache->delegate_abstract_invoke_cache);
1944 free_hash (cache->runtime_invoke_direct_cache);
1945 free_hash (cache->managed_wrapper_cache);
1947 free_hash (cache->native_wrapper_cache);
1948 free_hash (cache->native_wrapper_aot_cache);
1949 free_hash (cache->native_wrapper_check_cache);
1950 free_hash (cache->native_wrapper_aot_check_cache);
1952 free_hash (cache->native_func_wrapper_aot_cache);
1953 free_hash (cache->remoting_invoke_cache);
1954 free_hash (cache->synchronized_cache);
1955 free_hash (cache->unbox_wrapper_cache);
1956 free_hash (cache->cominterop_invoke_cache);
1957 free_hash (cache->cominterop_wrapper_cache);
1958 free_hash (cache->thunk_invoke_cache);
1961 static void
1962 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1964 for (int i = 0; i < image_count; ++i) {
1965 if (images [i]) {
1966 if (!mono_image_close_except_pools (images [i]))
1967 images [i] = NULL;
1973 * Returns whether mono_image_close_finish() must be called as well.
1974 * We must unload images in two steps because clearing the domain in
1975 * SGen requires the class metadata to be intact, but we need to free
1976 * the mono_g_hash_tables in case a collection occurs during domain
1977 * unloading and the roots would trip up the GC.
1979 gboolean
1980 mono_image_close_except_pools (MonoImage *image)
1982 MonoImage *image2;
1983 GHashTable *loaded_images, *loaded_images_by_name;
1984 int i;
1986 g_return_val_if_fail (image != NULL, FALSE);
1989 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1990 * register_image () can't grab an image which is being closed.
1992 mono_images_lock ();
1994 if (mono_atomic_dec_i32 (&image->ref_count) > 0) {
1995 mono_images_unlock ();
1996 return FALSE;
1999 loaded_images = get_loaded_images_hash (image->ref_only);
2000 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
2001 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
2002 if (image == image2) {
2003 /* This is not true if we are called from mono_image_open () */
2004 g_hash_table_remove (loaded_images, image->name);
2006 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
2007 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
2009 mono_images_unlock ();
2011 #ifdef HOST_WIN32
2012 if (image->is_module_handle && image->has_entry_point) {
2013 mono_images_lock ();
2014 if (image->ref_count == 0) {
2015 /* Image will be closed by _CorDllMain. */
2016 FreeLibrary ((HMODULE) image->raw_data);
2017 mono_images_unlock ();
2018 return FALSE;
2020 mono_images_unlock ();
2022 #endif
2024 MONO_PROFILER_RAISE (image_unloading, (image));
2026 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
2028 mono_image_invoke_unload_hook (image);
2030 mono_metadata_clean_for_image (image);
2033 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2034 * assemblies, so we can't release these references in mono_assembly_close () since the
2035 * MonoImage might outlive its associated MonoAssembly.
2037 if (image->references && !image_is_dynamic (image)) {
2038 for (i = 0; i < image->nreferences; i++) {
2039 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2040 if (!mono_assembly_close_except_image_pools (image->references [i]))
2041 image->references [i] = NULL;
2044 } else {
2045 if (image->references) {
2046 g_free (image->references);
2047 image->references = NULL;
2051 #ifdef HOST_WIN32
2052 mono_images_lock ();
2053 if (image->is_module_handle && !image->has_entry_point)
2054 FreeLibrary ((HMODULE) image->raw_data);
2055 mono_images_unlock ();
2056 #endif
2058 if (image->raw_buffer_used) {
2059 if (image->raw_data != NULL) {
2060 #ifndef HOST_WIN32
2061 if (image->fileio_used)
2062 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
2063 else
2064 #endif
2065 mono_file_unmap (image->raw_data, image->raw_data_handle);
2069 if (image->raw_data_allocated) {
2070 /* FIXME: do we need this? (image is disposed anyway) */
2071 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2072 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2074 if ((image->raw_metadata > image->raw_data) &&
2075 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2076 image->raw_metadata = NULL;
2078 for (i = 0; i < ii->cli_section_count; i++)
2079 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2080 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2081 ii->cli_sections [i] = NULL;
2083 g_free (image->raw_data);
2086 if (debug_assembly_unload) {
2087 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2088 } else {
2089 g_free (image->name);
2090 g_free (image->guid);
2091 g_free (image->version);
2094 if (image->method_cache)
2095 g_hash_table_destroy (image->method_cache);
2096 if (image->methodref_cache)
2097 g_hash_table_destroy (image->methodref_cache);
2098 mono_internal_hash_table_destroy (&image->class_cache);
2099 mono_conc_hashtable_destroy (image->field_cache);
2100 if (image->array_cache) {
2101 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2102 g_hash_table_destroy (image->array_cache);
2104 if (image->szarray_cache)
2105 g_hash_table_destroy (image->szarray_cache);
2106 if (image->ptr_cache)
2107 g_hash_table_destroy (image->ptr_cache);
2108 if (image->name_cache) {
2109 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2110 g_hash_table_destroy (image->name_cache);
2113 free_hash (image->delegate_bound_static_invoke_cache);
2114 free_hash (image->runtime_invoke_vcall_cache);
2115 free_hash (image->ldfld_wrapper_cache);
2116 free_hash (image->ldflda_wrapper_cache);
2117 free_hash (image->stfld_wrapper_cache);
2118 free_hash (image->isinst_cache);
2119 free_hash (image->castclass_cache);
2120 free_hash (image->icall_wrapper_cache);
2121 free_hash (image->proxy_isinst_cache);
2122 if (image->var_gparam_cache)
2123 mono_conc_hashtable_destroy (image->var_gparam_cache);
2124 if (image->mvar_gparam_cache)
2125 mono_conc_hashtable_destroy (image->mvar_gparam_cache);
2126 free_hash (image->wrapper_param_names);
2127 free_hash (image->pinvoke_scopes);
2128 free_hash (image->pinvoke_scope_filenames);
2129 free_hash (image->native_func_wrapper_cache);
2130 mono_conc_hashtable_destroy (image->typespec_cache);
2131 free_hash (image->weak_field_indexes);
2133 mono_wrapper_caches_free (&image->wrapper_caches);
2135 for (i = 0; i < image->gshared_types_len; ++i)
2136 free_hash (image->gshared_types [i]);
2137 g_free (image->gshared_types);
2139 /* The ownership of signatures is not well defined */
2140 g_hash_table_destroy (image->memberref_signatures);
2141 g_hash_table_destroy (image->helper_signatures);
2142 g_hash_table_destroy (image->method_signatures);
2144 if (image->rgctx_template_hash)
2145 g_hash_table_destroy (image->rgctx_template_hash);
2147 if (image->property_hash)
2148 mono_property_hash_destroy (image->property_hash);
2151 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2152 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2154 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2155 image->reflection_info_unregister_classes = NULL;
2157 if (image->interface_bitset) {
2158 mono_unload_interface_ids (image->interface_bitset);
2159 mono_bitset_free (image->interface_bitset);
2161 if (image->image_info){
2162 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2164 if (ii->cli_section_tables)
2165 g_free (ii->cli_section_tables);
2166 if (ii->cli_sections)
2167 g_free (ii->cli_sections);
2168 g_free (image->image_info);
2171 mono_image_close_except_pools_all (image->files, image->file_count);
2172 mono_image_close_except_pools_all (image->modules, image->module_count);
2173 if (image->modules_loaded)
2174 g_free (image->modules_loaded);
2176 mono_os_mutex_destroy (&image->szarray_cache_lock);
2177 mono_os_mutex_destroy (&image->lock);
2179 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2180 if (image_is_dynamic (image)) {
2181 /* Dynamic images are GC_MALLOCed */
2182 g_free ((char*)image->module_name);
2183 mono_dynamic_image_free ((MonoDynamicImage*)image);
2186 MONO_PROFILER_RAISE (image_unloaded, (image));
2188 return TRUE;
2191 static void
2192 mono_image_close_all (MonoImage**images, int image_count)
2194 for (int i = 0; i < image_count; ++i) {
2195 if (images [i])
2196 mono_image_close_finish (images [i]);
2198 if (images)
2199 g_free (images);
2202 void
2203 mono_image_close_finish (MonoImage *image)
2205 int i;
2207 if (image->references && !image_is_dynamic (image)) {
2208 for (i = 0; i < image->nreferences; i++) {
2209 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2210 mono_assembly_close_finish (image->references [i]);
2213 g_free (image->references);
2214 image->references = NULL;
2217 mono_image_close_all (image->files, image->file_count);
2218 mono_image_close_all (image->modules, image->module_count);
2220 #ifndef DISABLE_PERFCOUNTERS
2221 /* FIXME: use an explicit subtraction method as soon as it's available */
2222 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2223 #endif
2225 if (!image_is_dynamic (image)) {
2226 if (debug_assembly_unload)
2227 mono_mempool_invalidate (image->mempool);
2228 else {
2229 mono_mempool_destroy (image->mempool);
2230 g_free (image);
2232 } else {
2233 if (debug_assembly_unload)
2234 mono_mempool_invalidate (image->mempool);
2235 else {
2236 mono_mempool_destroy (image->mempool);
2237 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2243 * mono_image_close:
2244 * \param image The image file we wish to close
2245 * Closes an image file, deallocates all memory consumed and
2246 * unmaps all possible sections of the file
2248 void
2249 mono_image_close (MonoImage *image)
2251 if (mono_image_close_except_pools (image))
2252 mono_image_close_finish (image);
2255 /**
2256 * mono_image_strerror:
2257 * \param status an code indicating the result from a recent operation
2258 * \returns a string describing the error
2260 const char *
2261 mono_image_strerror (MonoImageOpenStatus status)
2263 switch (status){
2264 case MONO_IMAGE_OK:
2265 return "success";
2266 case MONO_IMAGE_ERROR_ERRNO:
2267 return strerror (errno);
2268 case MONO_IMAGE_IMAGE_INVALID:
2269 return "File does not contain a valid CIL image";
2270 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2271 return "An assembly was referenced, but could not be found";
2273 return "Internal error";
2276 static gpointer
2277 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2278 guint32 lang_id, gunichar2 *name,
2279 MonoPEResourceDirEntry *entry,
2280 MonoPEResourceDir *root, guint32 level)
2282 gboolean is_string, is_dir;
2283 guint32 name_offset, dir_offset;
2285 /* Level 0 holds a directory entry for each type of resource
2286 * (identified by ID or name).
2288 * Level 1 holds a directory entry for each named resource
2289 * item, and each "anonymous" item of a particular type of
2290 * resource.
2292 * Level 2 holds a directory entry for each language pointing to
2293 * the actual data.
2295 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2296 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2298 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2299 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2301 if(level==0) {
2302 if (is_string)
2303 return NULL;
2304 } else if (level==1) {
2305 if (res_id != name_offset)
2306 return NULL;
2307 #if 0
2308 if(name!=NULL &&
2309 is_string==TRUE && name!=lookup (name_offset)) {
2310 return(NULL);
2312 #endif
2313 } else if (level==2) {
2314 if (is_string || (lang_id != 0 && name_offset != lang_id))
2315 return NULL;
2316 } else {
2317 g_assert_not_reached ();
2320 if (is_dir) {
2321 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2322 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2323 guint32 entries, i;
2325 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2327 for(i=0; i<entries; i++) {
2328 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2329 gpointer ret;
2331 ret=mono_image_walk_resource_tree (info, res_id,
2332 lang_id, name,
2333 sub_entry, root,
2334 level+1);
2335 if(ret!=NULL) {
2336 return(ret);
2340 return(NULL);
2341 } else {
2342 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2343 MonoPEResourceDataEntry *res;
2345 res = g_new0 (MonoPEResourceDataEntry, 1);
2347 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2348 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2349 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2350 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2352 return (res);
2357 * mono_image_lookup_resource:
2358 * \param image the image to look up the resource in
2359 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2360 * \param lang_id The language id.
2361 * \param name the resource name to lookup.
2362 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2363 * of the given resource. The caller should free it using \c g_free when no longer
2364 * needed.
2366 gpointer
2367 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2369 MonoCLIImageInfo *info;
2370 MonoDotNetHeader *header;
2371 MonoPEDatadir *datadir;
2372 MonoPEDirEntry *rsrc;
2373 MonoPEResourceDir *resource_dir;
2374 MonoPEResourceDirEntry *res_entries;
2375 guint32 entries, i;
2377 if(image==NULL) {
2378 return(NULL);
2381 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2383 info = (MonoCLIImageInfo *)image->image_info;
2384 if(info==NULL) {
2385 return(NULL);
2388 header=&info->cli_header;
2389 if(header==NULL) {
2390 return(NULL);
2393 datadir=&header->datadir;
2394 if(datadir==NULL) {
2395 return(NULL);
2398 rsrc=&datadir->pe_resource_table;
2399 if(rsrc==NULL) {
2400 return(NULL);
2403 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2404 if(resource_dir==NULL) {
2405 return(NULL);
2408 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2409 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2411 for(i=0; i<entries; i++) {
2412 MonoPEResourceDirEntry *entry=&res_entries[i];
2413 gpointer ret;
2415 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2416 name, entry, resource_dir,
2418 if(ret!=NULL) {
2419 return(ret);
2423 return(NULL);
2426 /**
2427 * mono_image_get_entry_point:
2428 * \param image the image where the entry point will be looked up.
2429 * Use this routine to determine the metadata token for method that
2430 * has been flagged as the entry point.
2431 * \returns the token for the entry point method in the image
2433 guint32
2434 mono_image_get_entry_point (MonoImage *image)
2436 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2440 * mono_image_get_resource:
2441 * \param image the image where the resource will be looked up.
2442 * \param offset The offset to add to the resource
2443 * \param size a pointer to an int where the size of the resource will be stored
2445 * This is a low-level routine that fetches a resource from the
2446 * metadata that starts at a given \p offset. The \p size parameter is
2447 * filled with the data field as encoded in the metadata.
2449 * \returns the pointer to the resource whose offset is \p offset.
2451 const char*
2452 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2454 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2455 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2456 const char* data;
2458 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2459 return NULL;
2461 data = mono_image_rva_map (image, ch->ch_resources.rva);
2462 if (!data)
2463 return NULL;
2464 data += offset;
2465 if (size)
2466 *size = read32 (data);
2467 data += 4;
2468 return data;
2471 // Returning NULL with no error set will be interpeted as "not found"
2472 MonoImage*
2473 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2475 char *base_dir, *name;
2476 MonoImage *res;
2477 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2478 const char *fname;
2479 guint32 fname_id;
2481 error_init (error);
2483 if (fileidx < 1 || fileidx > t->rows)
2484 return NULL;
2486 mono_image_lock (image);
2487 if (image->files && image->files [fileidx - 1]) {
2488 mono_image_unlock (image);
2489 return image->files [fileidx - 1];
2491 mono_image_unlock (image);
2493 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2494 fname = mono_metadata_string_heap (image, fname_id);
2495 base_dir = g_path_get_dirname (image->name);
2496 name = g_build_filename (base_dir, fname, NULL);
2497 res = mono_image_open (name, NULL);
2498 if (!res)
2499 goto done;
2501 mono_image_lock (image);
2502 if (image->files && image->files [fileidx - 1]) {
2503 MonoImage *old = res;
2504 res = image->files [fileidx - 1];
2505 mono_image_unlock (image);
2506 mono_image_close (old);
2507 } else {
2508 int i;
2509 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2510 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2511 mono_image_unlock (image);
2512 mono_image_close (res);
2513 return NULL;
2516 for (i = 0; i < res->module_count; ++i) {
2517 if (res->modules [i] && !res->modules [i]->assembly)
2518 res->modules [i]->assembly = image->assembly;
2521 if (!image->files) {
2522 image->files = g_new0 (MonoImage*, t->rows);
2523 image->file_count = t->rows;
2525 image->files [fileidx - 1] = res;
2526 mono_image_unlock (image);
2527 /* vtable fixup can't happen with the image lock held */
2528 #ifdef HOST_WIN32
2529 if (res->is_module_handle)
2530 mono_image_fixup_vtable (res);
2531 #endif
2534 done:
2535 g_free (name);
2536 g_free (base_dir);
2537 return res;
2541 * mono_image_load_file_for_image:
2543 MonoImage*
2544 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2546 ERROR_DECL (error);
2547 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, error);
2548 mono_error_assert_ok (error);
2549 return result;
2553 * mono_image_get_strong_name:
2554 * \param image a MonoImage
2555 * \param size a \c guint32 pointer, or NULL.
2557 * If the image has a strong name, and \p size is not NULL, the value
2558 * pointed to by size will have the size of the strong name.
2560 * \returns NULL if the image does not have a strong name, or a
2561 * pointer to the public key.
2563 const char*
2564 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2566 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2567 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2568 const char* data;
2570 if (!de->size || !de->rva)
2571 return NULL;
2572 data = mono_image_rva_map (image, de->rva);
2573 if (!data)
2574 return NULL;
2575 if (size)
2576 *size = de->size;
2577 return data;
2581 * mono_image_strong_name_position:
2582 * \param image a \c MonoImage
2583 * \param size a \c guint32 pointer, or NULL.
2585 * If the image has a strong name, and \p size is not NULL, the value
2586 * pointed to by size will have the size of the strong name.
2588 * \returns the position within the image file where the strong name
2589 * is stored.
2591 guint32
2592 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2594 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2595 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2596 guint32 pos;
2598 if (size)
2599 *size = de->size;
2600 if (!de->size || !de->rva)
2601 return 0;
2602 pos = mono_cli_rva_image_map (image, de->rva);
2603 return pos == INVALID_ADDRESS ? 0 : pos;
2607 * mono_image_get_public_key:
2608 * \param image a \c MonoImage
2609 * \param size a \c guint32 pointer, or NULL.
2611 * This is used to obtain the public key in the \p image.
2613 * If the image has a public key, and \p size is not NULL, the value
2614 * pointed to by size will have the size of the public key.
2616 * \returns NULL if the image does not have a public key, or a pointer
2617 * to the public key.
2619 const char*
2620 mono_image_get_public_key (MonoImage *image, guint32 *size)
2622 const char *pubkey;
2623 guint32 len, tok;
2625 if (image_is_dynamic (image)) {
2626 if (size)
2627 *size = ((MonoDynamicImage*)image)->public_key_len;
2628 return (char*)((MonoDynamicImage*)image)->public_key;
2630 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2631 return NULL;
2632 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2633 if (!tok)
2634 return NULL;
2635 pubkey = mono_metadata_blob_heap (image, tok);
2636 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2637 if (size)
2638 *size = len;
2639 return pubkey;
2643 * mono_image_get_name:
2644 * \param name a \c MonoImage
2645 * \returns the name of the assembly.
2647 const char*
2648 mono_image_get_name (MonoImage *image)
2650 return image->assembly_name;
2654 * mono_image_get_filename:
2655 * \param image a \c MonoImage
2656 * Used to get the filename that hold the actual \c MonoImage
2657 * \returns the filename.
2659 const char*
2660 mono_image_get_filename (MonoImage *image)
2662 return image->name;
2666 * mono_image_get_guid:
2668 const char*
2669 mono_image_get_guid (MonoImage *image)
2671 return image->guid;
2675 * mono_image_get_table_info:
2677 const MonoTableInfo*
2678 mono_image_get_table_info (MonoImage *image, int table_id)
2680 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2681 return NULL;
2682 return &image->tables [table_id];
2686 * mono_image_get_table_rows:
2689 mono_image_get_table_rows (MonoImage *image, int table_id)
2691 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2692 return 0;
2693 return image->tables [table_id].rows;
2697 * mono_table_info_get_rows:
2700 mono_table_info_get_rows (const MonoTableInfo *table)
2702 return table->rows;
2706 * mono_image_get_assembly:
2707 * \param image the \c MonoImage .
2708 * Use this routine to get the assembly that owns this image.
2709 * \returns the assembly that holds this image.
2711 MonoAssembly*
2712 mono_image_get_assembly (MonoImage *image)
2714 return image->assembly;
2718 * mono_image_is_dynamic:
2719 * \param image the \c MonoImage
2721 * Determines if the given image was created dynamically through the
2722 * \c System.Reflection.Emit API
2723 * \returns TRUE if the image was created dynamically, FALSE if not.
2725 gboolean
2726 mono_image_is_dynamic (MonoImage *image)
2728 return image_is_dynamic (image);
2732 * mono_image_has_authenticode_entry:
2733 * \param image the \c MonoImage
2734 * Use this routine to determine if the image has a Authenticode
2735 * Certificate Table.
2736 * \returns TRUE if the image contains an authenticode entry in the PE
2737 * directory.
2739 gboolean
2740 mono_image_has_authenticode_entry (MonoImage *image)
2742 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2743 MonoDotNetHeader *header = &iinfo->cli_header;
2744 if (!header)
2745 return FALSE;
2746 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2747 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2748 return ((de->rva != 0) && (de->size > 8));
2751 gpointer
2752 mono_image_alloc (MonoImage *image, guint size)
2754 gpointer res;
2756 #ifndef DISABLE_PERFCOUNTERS
2757 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
2758 #endif
2759 mono_image_lock (image);
2760 res = mono_mempool_alloc (image->mempool, size);
2761 mono_image_unlock (image);
2763 return res;
2766 gpointer
2767 mono_image_alloc0 (MonoImage *image, guint size)
2769 gpointer res;
2771 #ifndef DISABLE_PERFCOUNTERS
2772 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
2773 #endif
2774 mono_image_lock (image);
2775 res = mono_mempool_alloc0 (image->mempool, size);
2776 mono_image_unlock (image);
2778 return res;
2781 char*
2782 mono_image_strdup (MonoImage *image, const char *s)
2784 char *res;
2786 #ifndef DISABLE_PERFCOUNTERS
2787 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (s));
2788 #endif
2789 mono_image_lock (image);
2790 res = mono_mempool_strdup (image->mempool, s);
2791 mono_image_unlock (image);
2793 return res;
2796 char*
2797 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2799 char *buf;
2800 mono_image_lock (image);
2801 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2802 mono_image_unlock (image);
2803 #ifndef DISABLE_PERFCOUNTERS
2804 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (buf));
2805 #endif
2806 return buf;
2809 char*
2810 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2812 char *buf;
2813 va_list args;
2815 va_start (args, format);
2816 buf = mono_image_strdup_vprintf (image, format, args);
2817 va_end (args);
2818 return buf;
2821 GList*
2822 mono_g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2824 GList *new_list;
2826 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2827 new_list->data = data;
2828 new_list->prev = list ? list->prev : NULL;
2829 new_list->next = list;
2831 if (new_list->prev)
2832 new_list->prev->next = new_list;
2833 if (list)
2834 list->prev = new_list;
2836 return new_list;
2839 GSList*
2840 mono_g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2842 GSList *new_list;
2844 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2845 new_list->data = data;
2846 new_list->next = NULL;
2848 return g_slist_concat (list, new_list);
2851 void
2852 mono_image_lock (MonoImage *image)
2854 mono_locks_os_acquire (&image->lock, ImageDataLock);
2857 void
2858 mono_image_unlock (MonoImage *image)
2860 mono_locks_os_release (&image->lock, ImageDataLock);
2865 * mono_image_property_lookup:
2866 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2868 * LOCKING: Takes the image lock
2870 gpointer
2871 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2873 gpointer res;
2875 mono_image_lock (image);
2876 res = mono_property_hash_lookup (image->property_hash, subject, property);
2877 mono_image_unlock (image);
2879 return res;
2883 * mono_image_property_insert:
2884 * Insert a new property \p property with value \p value on \p subject in \p
2885 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2887 * LOCKING: Takes the image lock
2889 void
2890 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2892 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2893 mono_image_lock (image);
2894 mono_property_hash_insert (image->property_hash, subject, property, value);
2895 mono_image_unlock (image);
2899 * mono_image_property_remove:
2900 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2902 * LOCKING: Takes the image lock
2904 void
2905 mono_image_property_remove (MonoImage *image, gpointer subject)
2907 mono_image_lock (image);
2908 mono_property_hash_remove_object (image->property_hash, subject);
2909 mono_image_unlock (image);
2912 void
2913 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2915 MonoImage *image = m_class_get_image (klass);
2916 g_assert (image_is_dynamic (image));
2917 mono_image_lock (image);
2918 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2919 mono_image_unlock (image);
2922 // 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.
2925 * mono_find_image_owner:
2927 * Find the image, if any, which a given pointer is located in the memory of.
2929 MonoImage *
2930 mono_find_image_owner (void *ptr)
2932 mono_images_lock ();
2934 MonoImage *owner = NULL;
2936 // Iterate over both by-path image hashes
2937 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2938 int hash_idx;
2939 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2941 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2942 GHashTableIter iter;
2943 MonoImage *image;
2945 // Iterate over images within a hash
2946 g_hash_table_iter_init (&iter, target);
2947 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2949 mono_image_lock (image);
2950 if (mono_mempool_contains_addr (image->mempool, ptr))
2951 owner = image;
2952 mono_image_unlock (image);
2956 mono_images_unlock ();
2958 return owner;