2 * image.c: Routines for manipulating an image stored in an
3 * extended PE/COFF file.
6 * Miguel de Icaza (miguel@ximian.com)
7 * Paolo Molaro (lupus@ximian.com)
9 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
22 #include "mono-endian.h"
23 #include "tabledefs.h"
24 #include "tokentype.h"
25 #include "metadata-internals.h"
26 #include "profiler-private.h"
30 #include <mono/io-layer/io-layer.h>
31 #include <mono/utils/checked-build.h>
32 #include <mono/utils/mono-logger-internals.h>
33 #include <mono/utils/mono-path.h>
34 #include <mono/utils/mono-mmap.h>
35 #include <mono/utils/mono-io-portability.h>
36 #include <mono/utils/atomic.h>
37 #include <mono/metadata/class-internals.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/object-internals.h>
40 #include <mono/metadata/security-core-clr.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/verify.h>
43 #include <mono/metadata/image-internals.h>
44 #include <sys/types.h>
50 #define INVALID_ADDRESS 0xffffffff
52 // Amount initially reserved in each image's mempool.
53 // FIXME: This number is arbitrary, a more practical number should be found
54 #define INITIAL_IMAGE_SIZE 512
57 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
58 * There are four, for all combinations of [look up by path or assembly name?]
59 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
63 IMAGES_HASH_PATH_REFONLY = 1,
65 IMAGES_HASH_NAME_REFONLY = 3,
68 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
71 get_loaded_images_hash (gboolean refonly)
73 int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
74 return loaded_images_hashes [idx];
78 get_loaded_images_by_name_hash (gboolean refonly)
80 int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
81 return loaded_images_hashes [idx];
84 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
85 // Can be used on modules loaded through either the "file" or "module" mechanism
87 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
90 MonoAssembly *assembly = assemblyImage->assembly;
93 // Assembly currently assigned
94 MonoAssembly *assemblyOld = image->assembly;
96 if (assemblyOld == assembly)
98 mono_error_set_bad_image (error, assemblyImage, "Attempted to load module %s which has already been loaded by assembly %s. This is not supported in Mono.", image->name, assemblyOld->image->name);
101 gpointer result = InterlockedExchangePointer((gpointer *)&image->assembly, assembly);
102 if (result == assembly)
107 static gboolean debug_assembly_unload = FALSE;
109 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
110 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
111 static gboolean mutex_inited;
112 static mono_mutex_t images_mutex;
114 static void install_pe_loader (void);
116 typedef struct ImageUnloadHook ImageUnloadHook;
117 struct ImageUnloadHook {
118 MonoImageUnloadFunc func;
122 static GSList *image_unload_hooks;
125 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
127 ImageUnloadHook *hook;
129 g_return_if_fail (func != NULL);
131 hook = g_new0 (ImageUnloadHook, 1);
133 hook->user_data = user_data;
134 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
138 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
141 ImageUnloadHook *hook;
143 for (l = image_unload_hooks; l; l = l->next) {
144 hook = (ImageUnloadHook *)l->data;
146 if (hook->func == func && hook->user_data == user_data) {
148 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
155 mono_image_invoke_unload_hook (MonoImage *image)
158 ImageUnloadHook *hook;
160 for (l = image_unload_hooks; l; l = l->next) {
161 hook = (ImageUnloadHook *)l->data;
163 hook->func (image, hook->user_data);
167 static GSList *image_loaders;
170 mono_install_image_loader (const MonoImageLoader *loader)
172 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
175 /* returns offset relative to image->raw_data */
177 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
179 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
180 const int top = iinfo->cli_section_count;
181 MonoSectionTable *tables = iinfo->cli_section_tables;
184 if (image->metadata_only)
187 for (i = 0; i < top; i++){
188 if ((addr >= tables->st_virtual_address) &&
189 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
191 if (image->is_module_handle)
194 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
198 return INVALID_ADDRESS;
202 * mono_images_rva_map:
203 * @image: a MonoImage
204 * @addr: relative virtual address (RVA)
206 * This is a low-level routine used by the runtime to map relative
207 * virtual address (RVA) into their location in memory.
209 * Returns: the address in memory for the given RVA, or NULL if the
210 * RVA is not valid for this image.
213 mono_image_rva_map (MonoImage *image, guint32 addr)
215 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
216 const int top = iinfo->cli_section_count;
217 MonoSectionTable *tables = iinfo->cli_section_tables;
221 if (image->is_module_handle) {
222 if (addr && addr < image->raw_data_len)
223 return image->raw_data + addr;
229 for (i = 0; i < top; i++){
230 if ((addr >= tables->st_virtual_address) &&
231 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
232 if (!iinfo->cli_sections [i]) {
233 if (!mono_image_ensure_section_idx (image, i))
236 return (char*)iinfo->cli_sections [i] +
237 (addr - tables->st_virtual_address);
247 * Initialize the global variables used by this module.
250 mono_images_init (void)
252 mono_os_mutex_init_recursive (&images_mutex);
255 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
256 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
258 debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
260 install_pe_loader ();
266 * mono_images_cleanup:
268 * Free all resources used by this module.
271 mono_images_cleanup (void)
276 mono_os_mutex_destroy (&images_mutex);
278 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
279 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
280 g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
281 while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
282 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
285 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
286 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
288 mutex_inited = FALSE;
292 * mono_image_ensure_section_idx:
293 * @image: The image we are operating on
294 * @section: section number that we will load/map into memory
296 * This routine makes sure that we have an in-memory copy of
297 * an image section (.text, .rsrc, .data).
299 * Returns: TRUE on success
302 mono_image_ensure_section_idx (MonoImage *image, int section)
304 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
305 MonoSectionTable *sect;
307 g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
309 if (iinfo->cli_sections [section] != NULL)
312 sect = &iinfo->cli_section_tables [section];
314 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
317 if (image->is_module_handle)
318 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
321 /* FIXME: we ignore the writable flag since we don't patch the binary */
322 iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
327 * mono_image_ensure_section:
328 * @image: The image we are operating on
329 * @section: section name that we will load/map into memory
331 * This routine makes sure that we have an in-memory copy of
332 * an image section (.text, .rsrc, .data).
334 * Returns: TRUE on success
337 mono_image_ensure_section (MonoImage *image, const char *section)
339 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
342 for (i = 0; i < ii->cli_section_count; i++){
343 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
346 return mono_image_ensure_section_idx (image, i);
352 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
354 const int top = iinfo->cli_header.coff.coff_sections;
357 iinfo->cli_section_count = top;
358 iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
359 iinfo->cli_sections = g_new0 (void *, top);
361 for (i = 0; i < top; i++){
362 MonoSectionTable *t = &iinfo->cli_section_tables [i];
364 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
366 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
367 offset += sizeof (MonoSectionTable);
369 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
370 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
371 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
372 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
373 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
374 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
375 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
376 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
377 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
378 t->st_flags = GUINT32_FROM_LE (t->st_flags);
380 /* consistency checks here */
387 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
391 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
392 if (offset == INVALID_ADDRESS)
395 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
397 memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
399 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
400 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
401 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
402 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
403 SWAP32 (iinfo->cli_cli_header.ch_size);
404 SWAP32 (iinfo->cli_cli_header.ch_flags);
405 SWAP32 (iinfo->cli_cli_header.ch_entry_point);
406 SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
407 SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
408 SWAPPDE (iinfo->cli_cli_header.ch_metadata);
409 SWAPPDE (iinfo->cli_cli_header.ch_resources);
410 SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
411 SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
412 SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
413 SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
414 SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
415 SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
416 SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
417 SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
418 SWAPPDE (iinfo->cli_cli_header.ch_module_image);
419 SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
420 SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
421 SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
422 SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
427 /* Catch new uses of the fields that are supposed to be zero */
429 if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
430 (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
431 (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
432 (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
433 (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
434 (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
435 (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
436 (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
437 (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
440 * No need to scare people who are testing this, I am just
441 * labelling this as a LAMESPEC
443 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
451 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
453 guint32 offset, size;
459 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
460 if (offset == INVALID_ADDRESS)
463 size = iinfo->cli_cli_header.ch_metadata.size;
465 if (offset + size > image->raw_data_len)
467 image->raw_metadata = image->raw_data + offset;
469 /* 24.2.1: Metadata root starts here */
470 ptr = image->raw_metadata;
472 if (strncmp (ptr, "BSJB", 4) == 0){
473 guint32 version_string_len;
476 image->md_version_major = read16 (ptr);
478 image->md_version_minor = read16 (ptr);
481 version_string_len = read32 (ptr);
483 image->version = g_strndup (ptr, version_string_len);
484 ptr += version_string_len;
485 pad = ptr - image->raw_metadata;
487 ptr += 4 - (pad % 4);
491 /* skip over flags */
494 streams = read16 (ptr);
497 for (i = 0; i < streams; i++){
498 if (strncmp (ptr + 8, "#~", 3) == 0){
499 image->heap_tables.data = image->raw_metadata + read32 (ptr);
500 image->heap_tables.size = read32 (ptr + 4);
502 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
503 image->heap_strings.data = image->raw_metadata + read32 (ptr);
504 image->heap_strings.size = read32 (ptr + 4);
506 } else if (strncmp (ptr + 8, "#US", 4) == 0){
507 image->heap_us.data = image->raw_metadata + read32 (ptr);
508 image->heap_us.size = read32 (ptr + 4);
510 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
511 image->heap_blob.data = image->raw_metadata + read32 (ptr);
512 image->heap_blob.size = read32 (ptr + 4);
514 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
515 image->heap_guid.data = image->raw_metadata + read32 (ptr);
516 image->heap_guid.size = read32 (ptr + 4);
518 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
519 image->heap_tables.data = image->raw_metadata + read32 (ptr);
520 image->heap_tables.size = read32 (ptr + 4);
522 image->uncompressed_metadata = TRUE;
523 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name);
524 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
525 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
526 image->heap_pdb.size = read32 (ptr + 4);
529 g_message ("Unknown heap type: %s\n", ptr + 8);
530 ptr += 8 + strlen (ptr + 8) + 1;
532 pad = ptr - image->raw_metadata;
534 ptr += 4 - (pad % 4);
537 i = ((MonoImageLoader*)image->loader)->load_tables (image);
538 g_assert (image->heap_guid.data);
540 if (!image->metadata_only) {
541 g_assert (image->heap_guid.size >= 16);
543 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
545 /* PPDB files have no guid */
546 guint8 empty_guid [16];
548 memset (empty_guid, 0, sizeof (empty_guid));
550 image->guid = mono_guid_to_string (empty_guid);
557 * Load representation of logical metadata tables, from the "#~" stream
560 load_tables (MonoImage *image)
562 const char *heap_tables = image->heap_tables.data;
565 int valid = 0, table;
568 heap_sizes = heap_tables [6];
569 image->idx_string_wide = ((heap_sizes & 0x01) == 1);
570 image->idx_guid_wide = ((heap_sizes & 0x02) == 2);
571 image->idx_blob_wide = ((heap_sizes & 0x04) == 4);
573 valid_mask = read64 (heap_tables + 8);
574 rows = (const guint32 *) (heap_tables + 24);
576 for (table = 0; table < 64; table++){
577 if ((valid_mask & ((guint64) 1 << table)) == 0){
578 if (table > MONO_TABLE_LAST)
580 image->tables [table].rows = 0;
583 if (table > MONO_TABLE_LAST) {
584 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
586 image->tables [table].rows = read32 (rows);
592 image->tables_base = (heap_tables + 24) + (4 * valid);
594 /* They must be the same */
595 g_assert ((const void *) image->tables_base == (const void *) rows);
597 mono_metadata_compute_table_bases (image);
602 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
604 if (!load_metadata_ptrs (image, iinfo))
607 return load_tables (image);
611 mono_image_check_for_module_cctor (MonoImage *image)
613 MonoTableInfo *t, *mt;
614 t = &image->tables [MONO_TABLE_TYPEDEF];
615 mt = &image->tables [MONO_TABLE_METHOD];
616 if (image_is_dynamic (image)) {
618 image->checked_module_cctor = TRUE;
622 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
623 const char *name = mono_metadata_string_heap (image, nameidx);
624 if (strcmp (name, "<Module>") == 0) {
625 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
628 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
630 last_method = mt->rows;
631 for (; first_method < last_method; first_method++) {
632 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
633 name = mono_metadata_string_heap (image, nameidx);
634 if (strcmp (name, ".cctor") == 0) {
635 image->has_module_cctor = TRUE;
636 image->checked_module_cctor = TRUE;
642 image->has_module_cctor = FALSE;
643 image->checked_module_cctor = TRUE;
647 load_modules (MonoImage *image)
654 t = &image->tables [MONO_TABLE_MODULEREF];
655 image->modules = g_new0 (MonoImage *, t->rows);
656 image->modules_loaded = g_new0 (gboolean, t->rows);
657 image->module_count = t->rows;
661 * mono_image_load_module_checked:
663 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
664 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
667 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
670 MonoTableInfo *file_table;
673 gboolean refonly = image->ref_only;
674 GList *list_iter, *valid_modules = NULL;
675 MonoImageOpenStatus status;
677 mono_error_init (error);
679 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
681 if (image->modules_loaded [idx - 1])
682 return image->modules [idx - 1];
684 file_table = &image->tables [MONO_TABLE_FILE];
685 for (i = 0; i < file_table->rows; i++) {
686 guint32 cols [MONO_FILE_SIZE];
687 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
688 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
690 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
693 t = &image->tables [MONO_TABLE_MODULEREF];
694 base_dir = g_path_get_dirname (image->name);
699 guint32 cols [MONO_MODULEREF_SIZE];
700 /* if there is no file table, we try to load the module... */
701 int valid = file_table->rows == 0;
703 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
704 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
705 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
706 /* be safe with string dups, but we could just compare string indexes */
707 if (strcmp (list_iter->data, name) == 0) {
713 module_ref = g_build_filename (base_dir, name, NULL);
714 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
716 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
717 mono_image_close (moduleImage);
720 g_list_free (valid_modules);
724 image->modules [idx - 1] = moduleImage;
727 if (image->modules [idx - 1]->is_module_handle)
728 mono_image_fixup_vtable (image->modules [idx - 1]);
730 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
736 image->modules_loaded [idx - 1] = TRUE;
739 g_list_free (valid_modules);
741 return image->modules [idx - 1];
745 mono_image_load_module (MonoImage *image, int idx)
748 MonoImage *result = mono_image_load_module_checked (image, idx, &error);
749 mono_error_assert_ok (&error);
754 class_key_extract (gpointer value)
756 MonoClass *klass = (MonoClass *)value;
758 return GUINT_TO_POINTER (klass->type_token);
762 class_next_value (gpointer value)
764 MonoClassDef *klass = (MonoClassDef *)value;
766 return (gpointer*)&klass->next_class_cache;
770 mono_image_init (MonoImage *image)
772 mono_os_mutex_init_recursive (&image->lock);
773 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
775 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
776 mono_internal_hash_table_init (&image->class_cache,
780 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
782 image->typespec_cache = g_hash_table_new (NULL, NULL);
783 image->memberref_signatures = g_hash_table_new (NULL, NULL);
784 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
785 image->method_signatures = g_hash_table_new (NULL, NULL);
787 image->property_hash = mono_property_hash_new ();
790 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
791 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
792 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
793 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
794 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
803 * Returns < 0 to indicate an error.
806 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
808 MonoDotNetHeader64 header64;
811 if (!image->is_module_handle)
813 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
816 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
818 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
821 /* endian swap the fields common between PE and PE+ */
822 SWAP32 (header->coff.coff_time);
823 SWAP32 (header->coff.coff_symptr);
824 SWAP32 (header->coff.coff_symcount);
825 SWAP16 (header->coff.coff_machine);
826 SWAP16 (header->coff.coff_sections);
827 SWAP16 (header->coff.coff_opt_header_size);
828 SWAP16 (header->coff.coff_attributes);
830 SWAP32 (header->pe.pe_code_size);
831 SWAP32 (header->pe.pe_uninit_data_size);
832 SWAP32 (header->pe.pe_rva_entry_point);
833 SWAP32 (header->pe.pe_rva_code_base);
834 SWAP32 (header->pe.pe_rva_data_base);
835 SWAP16 (header->pe.pe_magic);
837 /* now we are ready for the basic tests */
839 if (header->pe.pe_magic == 0x10B) {
840 offset += sizeof (MonoDotNetHeader);
841 SWAP32 (header->pe.pe_data_size);
842 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
845 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
846 SWAP32 (header->nt.pe_stack_reserve);
847 SWAP32 (header->nt.pe_stack_commit);
848 SWAP32 (header->nt.pe_heap_reserve);
849 SWAP32 (header->nt.pe_heap_commit);
850 } else if (header->pe.pe_magic == 0x20B) {
851 /* PE32+ file format */
852 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
854 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
855 offset += sizeof (MonoDotNetHeader64);
856 /* copy the fields already swapped. the last field, pe_data_size, is missing */
857 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
858 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
859 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
861 SWAP64 (header64.nt.pe_image_base);
862 header->nt.pe_image_base = header64.nt.pe_image_base;
863 SWAP64 (header64.nt.pe_stack_reserve);
864 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
865 SWAP64 (header64.nt.pe_stack_commit);
866 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
867 SWAP64 (header64.nt.pe_heap_reserve);
868 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
869 SWAP64 (header64.nt.pe_heap_commit);
870 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
872 header->nt.pe_section_align = header64.nt.pe_section_align;
873 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
874 header->nt.pe_os_major = header64.nt.pe_os_major;
875 header->nt.pe_os_minor = header64.nt.pe_os_minor;
876 header->nt.pe_user_major = header64.nt.pe_user_major;
877 header->nt.pe_user_minor = header64.nt.pe_user_minor;
878 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
879 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
880 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
881 header->nt.pe_image_size = header64.nt.pe_image_size;
882 header->nt.pe_header_size = header64.nt.pe_header_size;
883 header->nt.pe_checksum = header64.nt.pe_checksum;
884 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
885 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
886 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
887 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
889 /* copy the datadir */
890 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
895 /* MonoPEHeaderNT: not used yet */
896 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
897 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
898 SWAP16 (header->nt.pe_os_major); /* must be 4 */
899 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
900 SWAP16 (header->nt.pe_user_major);
901 SWAP16 (header->nt.pe_user_minor);
902 SWAP16 (header->nt.pe_subsys_major);
903 SWAP16 (header->nt.pe_subsys_minor);
904 SWAP32 (header->nt.pe_reserved_1);
905 SWAP32 (header->nt.pe_image_size);
906 SWAP32 (header->nt.pe_header_size);
907 SWAP32 (header->nt.pe_checksum);
908 SWAP16 (header->nt.pe_subsys_required);
909 SWAP16 (header->nt.pe_dll_flags);
910 SWAP32 (header->nt.pe_loader_flags);
911 SWAP32 (header->nt.pe_data_dir_count);
913 /* MonoDotNetHeader: mostly unused */
914 SWAPPDE (header->datadir.pe_export_table);
915 SWAPPDE (header->datadir.pe_import_table);
916 SWAPPDE (header->datadir.pe_resource_table);
917 SWAPPDE (header->datadir.pe_exception_table);
918 SWAPPDE (header->datadir.pe_certificate_table);
919 SWAPPDE (header->datadir.pe_reloc_table);
920 SWAPPDE (header->datadir.pe_debug);
921 SWAPPDE (header->datadir.pe_copyright);
922 SWAPPDE (header->datadir.pe_global_ptr);
923 SWAPPDE (header->datadir.pe_tls_table);
924 SWAPPDE (header->datadir.pe_load_config_table);
925 SWAPPDE (header->datadir.pe_bound_import);
926 SWAPPDE (header->datadir.pe_iat);
927 SWAPPDE (header->datadir.pe_delay_import_desc);
928 SWAPPDE (header->datadir.pe_cli_header);
929 SWAPPDE (header->datadir.pe_reserved);
932 if (image->is_module_handle)
933 image->raw_data_len = header->nt.pe_image_size;
940 mono_image_load_pe_data (MonoImage *image)
942 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
946 pe_image_load_pe_data (MonoImage *image)
948 MonoCLIImageInfo *iinfo;
949 MonoDotNetHeader *header;
950 MonoMSDOSHeader msdos;
953 iinfo = (MonoCLIImageInfo *)image->image_info;
954 header = &iinfo->cli_header;
957 if (!image->is_module_handle)
959 if (offset + sizeof (msdos) > image->raw_data_len)
961 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
963 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
966 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
968 offset = msdos.pe_offset;
970 offset = do_load_header (image, header, offset);
975 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
977 if (header->coff.coff_machine != 0x14c)
983 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
984 * which produces binaries with 7.0. From Sergey:
986 * The reason is that MSVC7 uses traditional compile/link
987 * sequence for CIL executables, and VS.NET (and Framework
988 * SDK) includes linker version 7, that puts 7.0 in this
989 * field. That's why it's currently not possible to load VC
990 * binaries with Mono. This field is pretty much meaningless
991 * anyway (what linker?).
993 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
998 * FIXME: byte swap all addresses here for header.
1001 if (!load_section_tables (image, iinfo, offset))
1011 mono_image_load_cli_data (MonoImage *image)
1013 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1017 pe_image_load_cli_data (MonoImage *image)
1019 MonoCLIImageInfo *iinfo;
1020 MonoDotNetHeader *header;
1022 iinfo = (MonoCLIImageInfo *)image->image_info;
1023 header = &iinfo->cli_header;
1025 /* Load the CLI header */
1026 if (!mono_image_load_cli_header (image, iinfo))
1029 if (!mono_image_load_metadata (image, iinfo))
1036 mono_image_load_names (MonoImage *image)
1038 /* modules don't have an assembly table row */
1039 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1040 image->assembly_name = mono_metadata_string_heap (image,
1041 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1042 0, MONO_ASSEMBLY_NAME));
1045 /* Portable pdb images don't have a MODULE row */
1046 if (image->tables [MONO_TABLE_MODULE].rows) {
1047 image->module_name = mono_metadata_string_heap (image,
1048 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1049 0, MONO_MODULE_NAME));
1054 pe_image_load_tables (MonoImage *image)
1060 pe_image_match (MonoImage *image)
1062 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1067 static const MonoImageLoader pe_loader = {
1069 pe_image_load_pe_data,
1070 pe_image_load_cli_data,
1071 pe_image_load_tables,
1075 install_pe_loader (void)
1077 mono_install_image_loader (&pe_loader);
1083 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1084 Mono provides its own implementation of those assemblies so it's safe to do so.
1086 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1088 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_names.
1090 This is to be removed once a proper fix is shipped through nuget.
1095 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1096 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1097 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1098 SYS_NET_HTTP = 3, //System.Net.Http
1099 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1100 } IgnoredAssemblyNames;
1105 const char guid [40];
1108 const char *ignored_assemblies_names[] = {
1109 "System.Runtime.InteropServices.RuntimeInformation.dll",
1110 "System.Globalization.Extensions.dll",
1111 "System.IO.Compression.dll",
1112 "System.Net.Http.dll",
1113 "System.Text.Encoding.CodePages.dll"
1116 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1118 static const IgnoredAssembly ignored_assemblies [] = {
1119 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1120 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1121 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1122 IGNORED_ASSEMBLY (0x7A39EA2D, SYS_IO_COMPRESSION, "C665DC9B-D9E5-4D00-98ED-E4F812F23545", "4.0.0 netcore50"),
1123 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1124 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1125 IGNORED_ASSEMBLY (0x726C7CC1, SYS_NET_HTTP, "7C0B577F-A4FD-47F1-ADF5-EE65B5A04BB5", "4.0.0 netcore50"),
1126 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1127 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1128 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1129 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1130 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1131 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1132 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1137 static void Main () {
1140 for (int i = 0; i < str.Length; ++i)
1141 h = ((h << 5) + h) ^ str[i];
1143 Console.WriteLine ("{0:X}", h);
1147 hash_guid (const char *str)
1151 h = ((h << 5) + h) ^ *str;
1159 is_problematic_image (MonoImage *image)
1161 int h = hash_guid (image->guid);
1163 //TODO make this more cache effiecient.
1164 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1165 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1166 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1167 const char *needle = ignored_assemblies_names [ignored_assemblies [i].assembly_name];
1168 char *p = strcasestr (image->name, needle);
1169 if (p && p [strlen (needle)] == 0)
1177 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1178 gboolean care_about_cli, gboolean care_about_pecoff)
1180 MonoCLIImageInfo *iinfo;
1181 MonoDotNetHeader *header;
1182 GSList *errors = NULL;
1185 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1187 mono_image_init (image);
1189 iinfo = (MonoCLIImageInfo *)image->image_info;
1190 header = &iinfo->cli_header;
1192 if (!image->metadata_only) {
1193 for (l = image_loaders; l; l = l->next) {
1194 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1195 if (loader->match (image)) {
1196 image->loader = loader;
1200 if (!image->loader) {
1202 *status = MONO_IMAGE_IMAGE_INVALID;
1207 *status = MONO_IMAGE_IMAGE_INVALID;
1209 if (care_about_pecoff == FALSE)
1212 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1215 if (!mono_image_load_pe_data (image))
1218 image->loader = (MonoImageLoader*)&pe_loader;
1221 if (care_about_cli == FALSE) {
1225 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1228 if (!mono_image_load_cli_data (image))
1231 if (is_problematic_image (image)) {
1232 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1233 *status = MONO_IMAGE_IMAGE_INVALID;
1237 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1240 mono_image_load_names (image);
1242 load_modules (image);
1245 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1247 *status = MONO_IMAGE_OK;
1253 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1254 g_warning ("Could not load image %s due to %s", image->name, info->message);
1255 mono_free_verify_list (errors);
1257 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1258 mono_image_close (image);
1263 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1264 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1266 MonoCLIImageInfo *iinfo;
1270 if ((filed = mono_file_map_open (fname)) == NULL){
1271 if (IS_PORTABILITY_SET) {
1272 gchar *ffname = mono_portability_find_file (fname, TRUE);
1274 filed = mono_file_map_open (ffname);
1279 if (filed == NULL) {
1281 *status = MONO_IMAGE_ERROR_ERRNO;
1286 image = g_new0 (MonoImage, 1);
1287 image->raw_buffer_used = TRUE;
1288 image->raw_data_len = mono_file_map_size (filed);
1289 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);
1290 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1291 if (!image->raw_data) {
1292 image->fileio_used = TRUE;
1293 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);
1296 if (!image->raw_data) {
1297 mono_file_map_close (filed);
1300 *status = MONO_IMAGE_IMAGE_INVALID;
1303 iinfo = g_new0 (MonoCLIImageInfo, 1);
1304 image->image_info = iinfo;
1305 image->name = mono_path_resolve_symlinks (fname);
1306 image->ref_only = refonly;
1307 image->metadata_only = metadata_only;
1308 image->ref_count = 1;
1309 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1310 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1312 mono_file_map_close (filed);
1313 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1317 * mono_image_loaded:
1318 * @name: path or assembly name of the image to load
1319 * @refonly: Check with respect to reflection-only loads?
1321 * This routine verifies that the given image is loaded.
1322 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1324 * Returns: the loaded MonoImage, or NULL on failure.
1327 mono_image_loaded_full (const char *name, gboolean refonly)
1331 mono_images_lock ();
1332 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1334 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1335 mono_images_unlock ();
1341 * mono_image_loaded:
1342 * @name: path or assembly name of the image to load
1344 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1346 * Returns: the loaded MonoImage, or NULL on failure.
1349 mono_image_loaded (const char *name)
1351 return mono_image_loaded_full (name, FALSE);
1360 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1362 GuidData *data = (GuidData *)user_data;
1367 image = (MonoImage *)val;
1368 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1373 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1376 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1380 mono_images_lock ();
1381 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1382 mono_images_unlock ();
1387 mono_image_loaded_by_guid (const char *guid)
1389 return mono_image_loaded_by_guid_full (guid, FALSE);
1393 register_image (MonoImage *image)
1396 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1398 mono_images_lock ();
1399 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1402 /* Somebody else beat us to it */
1403 mono_image_addref (image2);
1404 mono_images_unlock ();
1405 mono_image_close (image);
1409 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1410 g_hash_table_insert (loaded_images, image->name, image);
1411 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1412 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1413 mono_images_unlock ();
1419 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1421 MonoCLIImageInfo *iinfo;
1425 if (!data || !data_len) {
1427 *status = MONO_IMAGE_IMAGE_INVALID;
1432 datac = (char *)g_try_malloc (data_len);
1435 *status = MONO_IMAGE_ERROR_ERRNO;
1438 memcpy (datac, data, data_len);
1441 image = g_new0 (MonoImage, 1);
1442 image->raw_data = datac;
1443 image->raw_data_len = data_len;
1444 image->raw_data_allocated = need_copy;
1445 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1446 iinfo = g_new0 (MonoCLIImageInfo, 1);
1447 image->image_info = iinfo;
1448 image->ref_only = refonly;
1449 image->metadata_only = metadata_only;
1450 image->ref_count = 1;
1452 image = do_mono_image_load (image, status, TRUE, TRUE);
1456 return register_image (image);
1460 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1462 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1466 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1468 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1472 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1474 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1478 /* fname is not duplicated. */
1480 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1483 MonoCLIImageInfo* iinfo;
1485 image = g_new0 (MonoImage, 1);
1486 image->raw_data = (char*) module_handle;
1487 image->is_module_handle = TRUE;
1488 iinfo = g_new0 (MonoCLIImageInfo, 1);
1489 image->image_info = iinfo;
1490 image->name = fname;
1491 image->ref_count = has_entry_point ? 0 : 1;
1492 image->has_entry_point = has_entry_point;
1494 image = do_mono_image_load (image, status, TRUE, TRUE);
1498 return register_image (image);
1503 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1506 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1509 g_return_val_if_fail (fname != NULL, NULL);
1512 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1513 // then assemblies need to be loaded with LoadLibrary:
1514 if (!refonly && coree_module_handle) {
1515 HMODULE module_handle;
1516 guint16 *fname_utf16;
1519 absfname = mono_path_resolve_symlinks (fname);
1522 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1523 mono_images_lock ();
1524 image = g_hash_table_lookup (loaded_images, absfname);
1525 if (image) { // Image already loaded
1526 g_assert (image->is_module_handle);
1527 if (image->has_entry_point && image->ref_count == 0) {
1528 /* Increment reference count on images loaded outside of the runtime. */
1529 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1530 /* The image is already loaded because _CorDllMain removes images from the hash. */
1531 module_handle = LoadLibrary (fname_utf16);
1532 g_assert (module_handle == (HMODULE) image->raw_data);
1534 mono_image_addref (image);
1535 mono_images_unlock ();
1537 g_free (fname_utf16);
1542 // Image not loaded, load it now
1543 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1544 module_handle = MonoLoadImage (fname_utf16);
1545 if (status && module_handle == NULL)
1546 last_error = GetLastError ();
1548 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1549 image = g_hash_table_lookup (loaded_images, absfname);
1551 mono_image_addref (image);
1552 mono_images_unlock ();
1554 g_free (fname_utf16);
1556 if (module_handle == NULL) {
1560 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1561 *status = MONO_IMAGE_IMAGE_INVALID;
1563 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1573 g_assert (image->is_module_handle);
1574 g_assert (image->has_entry_point);
1579 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1583 absfname = mono_path_canonicalize (fname);
1586 * The easiest solution would be to do all the loading inside the mutex,
1587 * but that would lead to scalability problems. So we let the loading
1588 * happen outside the mutex, and if multiple threads happen to load
1589 * the same image, we discard all but the first copy.
1591 mono_images_lock ();
1592 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1595 if (image) { // Image already loaded
1596 mono_image_addref (image);
1597 mono_images_unlock ();
1600 mono_images_unlock ();
1602 // Image not loaded, load it now
1603 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1607 return register_image (image);
1612 * @fname: filename that points to the module we want to open
1613 * @status: An error condition is returned in this field
1615 * Returns: An open image of type %MonoImage or NULL on error.
1616 * The caller holds a temporary reference to the returned image which should be cleared
1617 * when no longer needed by calling mono_image_close ().
1618 * if NULL, then check the value of @status for details on the error
1621 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1623 return mono_image_open_full (fname, status, FALSE);
1627 * mono_pe_file_open:
1628 * @fname: filename that points to the module we want to open
1629 * @status: An error condition is returned in this field
1631 * Returns: An open image of type %MonoImage or NULL on error. if
1632 * NULL, then check the value of @status for details on the error.
1633 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1634 * It's just a PE file loader, used for FileVersionInfo. It also does
1635 * not use the image cache.
1638 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1640 g_return_val_if_fail (fname != NULL, NULL);
1642 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1646 * mono_image_open_raw
1647 * @fname: filename that points to the module we want to open
1648 * @status: An error condition is returned in this field
1650 * Returns an image without loading neither pe or cli data.
1652 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1655 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1657 g_return_val_if_fail (fname != NULL, NULL);
1659 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1663 * mono_image_open_metadata_only:
1665 * Open an image which contains metadata only without a PE header.
1668 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1670 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1674 mono_image_fixup_vtable (MonoImage *image)
1677 MonoCLIImageInfo *iinfo;
1679 MonoVTableFixup *vtfixup;
1685 g_assert (image->is_module_handle);
1687 iinfo = image->image_info;
1688 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1689 if (!de->rva || !de->size)
1691 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1695 count = de->size / sizeof (MonoVTableFixup);
1697 if (!vtfixup->rva || !vtfixup->count)
1700 slot = mono_image_rva_map (image, vtfixup->rva);
1702 slot_type = vtfixup->type;
1703 slot_count = vtfixup->count;
1704 if (slot_type & VTFIXUP_TYPE_32BIT)
1705 while (slot_count--) {
1706 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1707 slot = ((guint32*) slot) + 1;
1709 else if (slot_type & VTFIXUP_TYPE_64BIT)
1710 while (slot_count--) {
1711 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1712 slot = ((guint32*) slot) + 1;
1715 g_assert_not_reached();
1720 g_assert_not_reached();
1725 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1727 g_hash_table_destroy ((GHashTable*)val);
1732 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1734 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1739 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1741 g_slist_free ((GSList*)val);
1745 * mono_image_addref:
1746 * @image: The image file we wish to add a reference to
1748 * Increases the reference count of an image.
1751 mono_image_addref (MonoImage *image)
1753 InterlockedIncrement (&image->ref_count);
1757 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1759 stream->alloc_size = stream->index = stream->offset = 0;
1760 g_free (stream->data);
1761 stream->data = NULL;
1763 g_hash_table_destroy (stream->hash);
1764 stream->hash = NULL;
1769 free_hash (GHashTable *hash)
1772 g_hash_table_destroy (hash);
1776 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1778 free_hash (cache->delegate_invoke_cache);
1779 free_hash (cache->delegate_begin_invoke_cache);
1780 free_hash (cache->delegate_end_invoke_cache);
1781 free_hash (cache->runtime_invoke_cache);
1782 free_hash (cache->runtime_invoke_vtype_cache);
1784 free_hash (cache->delegate_abstract_invoke_cache);
1786 free_hash (cache->runtime_invoke_direct_cache);
1787 free_hash (cache->managed_wrapper_cache);
1789 free_hash (cache->native_wrapper_cache);
1790 free_hash (cache->native_wrapper_aot_cache);
1791 free_hash (cache->native_wrapper_check_cache);
1792 free_hash (cache->native_wrapper_aot_check_cache);
1794 free_hash (cache->native_func_wrapper_aot_cache);
1795 free_hash (cache->remoting_invoke_cache);
1796 free_hash (cache->synchronized_cache);
1797 free_hash (cache->unbox_wrapper_cache);
1798 free_hash (cache->cominterop_invoke_cache);
1799 free_hash (cache->cominterop_wrapper_cache);
1800 free_hash (cache->thunk_invoke_cache);
1804 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1806 for (int i = 0; i < image_count; ++i) {
1808 if (!mono_image_close_except_pools (images [i]))
1815 * Returns whether mono_image_close_finish() must be called as well.
1816 * We must unload images in two steps because clearing the domain in
1817 * SGen requires the class metadata to be intact, but we need to free
1818 * the mono_g_hash_tables in case a collection occurs during domain
1819 * unloading and the roots would trip up the GC.
1822 mono_image_close_except_pools (MonoImage *image)
1825 GHashTable *loaded_images, *loaded_images_by_name;
1828 g_return_val_if_fail (image != NULL, FALSE);
1831 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1832 * register_image () can't grab an image which is being closed.
1834 mono_images_lock ();
1836 if (InterlockedDecrement (&image->ref_count) > 0) {
1837 mono_images_unlock ();
1841 loaded_images = get_loaded_images_hash (image->ref_only);
1842 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1843 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1844 if (image == image2) {
1845 /* This is not true if we are called from mono_image_open () */
1846 g_hash_table_remove (loaded_images, image->name);
1848 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1849 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1851 mono_images_unlock ();
1854 if (image->is_module_handle && image->has_entry_point) {
1855 mono_images_lock ();
1856 if (image->ref_count == 0) {
1857 /* Image will be closed by _CorDllMain. */
1858 FreeLibrary ((HMODULE) image->raw_data);
1859 mono_images_unlock ();
1862 mono_images_unlock ();
1866 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1868 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1870 mono_image_invoke_unload_hook (image);
1872 mono_metadata_clean_for_image (image);
1875 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1876 * assemblies, so we can't release these references in mono_assembly_close () since the
1877 * MonoImage might outlive its associated MonoAssembly.
1879 if (image->references && !image_is_dynamic (image)) {
1880 for (i = 0; i < image->nreferences; i++) {
1881 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1882 if (!mono_assembly_close_except_image_pools (image->references [i]))
1883 image->references [i] = NULL;
1887 if (image->references) {
1888 g_free (image->references);
1889 image->references = NULL;
1894 mono_images_lock ();
1895 if (image->is_module_handle && !image->has_entry_point)
1896 FreeLibrary ((HMODULE) image->raw_data);
1897 mono_images_unlock ();
1900 if (image->raw_buffer_used) {
1901 if (image->raw_data != NULL) {
1903 if (image->fileio_used)
1904 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1907 mono_file_unmap (image->raw_data, image->raw_data_handle);
1911 if (image->raw_data_allocated) {
1912 /* FIXME: do we need this? (image is disposed anyway) */
1913 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1914 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1916 if ((image->raw_metadata > image->raw_data) &&
1917 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1918 image->raw_metadata = NULL;
1920 for (i = 0; i < ii->cli_section_count; i++)
1921 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1922 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1923 ii->cli_sections [i] = NULL;
1925 g_free (image->raw_data);
1928 if (debug_assembly_unload) {
1929 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1931 g_free (image->name);
1932 g_free (image->guid);
1933 g_free (image->version);
1936 if (image->method_cache)
1937 g_hash_table_destroy (image->method_cache);
1938 if (image->methodref_cache)
1939 g_hash_table_destroy (image->methodref_cache);
1940 mono_internal_hash_table_destroy (&image->class_cache);
1941 mono_conc_hashtable_destroy (image->field_cache);
1942 if (image->array_cache) {
1943 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1944 g_hash_table_destroy (image->array_cache);
1946 if (image->szarray_cache)
1947 g_hash_table_destroy (image->szarray_cache);
1948 if (image->ptr_cache)
1949 g_hash_table_destroy (image->ptr_cache);
1950 if (image->name_cache) {
1951 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1952 g_hash_table_destroy (image->name_cache);
1955 free_hash (image->delegate_bound_static_invoke_cache);
1956 free_hash (image->runtime_invoke_vcall_cache);
1957 free_hash (image->ldfld_wrapper_cache);
1958 free_hash (image->ldflda_wrapper_cache);
1959 free_hash (image->stfld_wrapper_cache);
1960 free_hash (image->isinst_cache);
1961 free_hash (image->castclass_cache);
1962 free_hash (image->icall_wrapper_cache);
1963 free_hash (image->proxy_isinst_cache);
1964 free_hash (image->var_cache_slow);
1965 free_hash (image->mvar_cache_slow);
1966 free_hash (image->var_cache_constrained);
1967 free_hash (image->mvar_cache_constrained);
1968 free_hash (image->wrapper_param_names);
1969 free_hash (image->pinvoke_scopes);
1970 free_hash (image->pinvoke_scope_filenames);
1971 free_hash (image->native_func_wrapper_cache);
1972 free_hash (image->typespec_cache);
1974 mono_wrapper_caches_free (&image->wrapper_caches);
1976 for (i = 0; i < image->gshared_types_len; ++i)
1977 free_hash (image->gshared_types [i]);
1978 g_free (image->gshared_types);
1980 /* The ownership of signatures is not well defined */
1981 g_hash_table_destroy (image->memberref_signatures);
1982 g_hash_table_destroy (image->helper_signatures);
1983 g_hash_table_destroy (image->method_signatures);
1985 if (image->rgctx_template_hash)
1986 g_hash_table_destroy (image->rgctx_template_hash);
1988 if (image->property_hash)
1989 mono_property_hash_destroy (image->property_hash);
1992 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
1993 cleared during shutdown as we don't perform regular appdomain unload for the root one.
1995 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
1996 image->reflection_info_unregister_classes = NULL;
1998 if (image->interface_bitset) {
1999 mono_unload_interface_ids (image->interface_bitset);
2000 mono_bitset_free (image->interface_bitset);
2002 if (image->image_info){
2003 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2005 if (ii->cli_section_tables)
2006 g_free (ii->cli_section_tables);
2007 if (ii->cli_sections)
2008 g_free (ii->cli_sections);
2009 g_free (image->image_info);
2012 mono_image_close_except_pools_all (image->files, image->file_count);
2013 mono_image_close_except_pools_all (image->modules, image->module_count);
2014 if (image->modules_loaded)
2015 g_free (image->modules_loaded);
2017 mono_os_mutex_destroy (&image->szarray_cache_lock);
2018 mono_os_mutex_destroy (&image->lock);
2020 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2021 if (image_is_dynamic (image)) {
2022 /* Dynamic images are GC_MALLOCed */
2023 g_free ((char*)image->module_name);
2024 mono_dynamic_image_free ((MonoDynamicImage*)image);
2027 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2033 mono_image_close_all (MonoImage**images, int image_count)
2035 for (int i = 0; i < image_count; ++i) {
2037 mono_image_close_finish (images [i]);
2044 mono_image_close_finish (MonoImage *image)
2048 if (image->references && !image_is_dynamic (image)) {
2049 for (i = 0; i < image->nreferences; i++) {
2050 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2051 mono_assembly_close_finish (image->references [i]);
2054 g_free (image->references);
2055 image->references = NULL;
2058 mono_image_close_all (image->files, image->file_count);
2059 mono_image_close_all (image->modules, image->module_count);
2061 #ifndef DISABLE_PERFCOUNTERS
2062 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2065 if (!image_is_dynamic (image)) {
2066 if (debug_assembly_unload)
2067 mono_mempool_invalidate (image->mempool);
2069 mono_mempool_destroy (image->mempool);
2073 if (debug_assembly_unload)
2074 mono_mempool_invalidate (image->mempool);
2076 mono_mempool_destroy (image->mempool);
2077 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2084 * @image: The image file we wish to close
2086 * Closes an image file, deallocates all memory consumed and
2087 * unmaps all possible sections of the file
2090 mono_image_close (MonoImage *image)
2092 if (mono_image_close_except_pools (image))
2093 mono_image_close_finish (image);
2097 * mono_image_strerror:
2098 * @status: an code indicating the result from a recent operation
2100 * Returns: a string describing the error
2103 mono_image_strerror (MonoImageOpenStatus status)
2108 case MONO_IMAGE_ERROR_ERRNO:
2109 return strerror (errno);
2110 case MONO_IMAGE_IMAGE_INVALID:
2111 return "File does not contain a valid CIL image";
2112 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2113 return "An assembly was referenced, but could not be found";
2115 return "Internal error";
2119 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2120 guint32 lang_id, gunichar2 *name,
2121 MonoPEResourceDirEntry *entry,
2122 MonoPEResourceDir *root, guint32 level)
2124 gboolean is_string, is_dir;
2125 guint32 name_offset, dir_offset;
2127 /* Level 0 holds a directory entry for each type of resource
2128 * (identified by ID or name).
2130 * Level 1 holds a directory entry for each named resource
2131 * item, and each "anonymous" item of a particular type of
2134 * Level 2 holds a directory entry for each language pointing to
2137 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2138 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2140 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2141 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2146 } else if (level==1) {
2147 if (res_id != name_offset)
2151 is_string==TRUE && name!=lookup (name_offset)) {
2155 } else if (level==2) {
2156 if (is_string || (lang_id != 0 && name_offset != lang_id))
2159 g_assert_not_reached ();
2163 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2164 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2167 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2169 for(i=0; i<entries; i++) {
2170 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2173 ret=mono_image_walk_resource_tree (info, res_id,
2184 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2185 MonoPEResourceDataEntry *res;
2187 res = g_new0 (MonoPEResourceDataEntry, 1);
2189 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2190 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2191 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2192 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2199 * mono_image_lookup_resource:
2200 * @image: the image to look up the resource in
2201 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2202 * @lang_id: The language id.
2203 * @name: the resource name to lookup.
2205 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2206 * of the given resource. The caller should free it using g_free () when no longer
2210 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2212 MonoCLIImageInfo *info;
2213 MonoDotNetHeader *header;
2214 MonoPEDatadir *datadir;
2215 MonoPEDirEntry *rsrc;
2216 MonoPEResourceDir *resource_dir;
2217 MonoPEResourceDirEntry *res_entries;
2224 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2226 info = (MonoCLIImageInfo *)image->image_info;
2231 header=&info->cli_header;
2236 datadir=&header->datadir;
2241 rsrc=&datadir->pe_resource_table;
2246 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2247 if(resource_dir==NULL) {
2251 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2252 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2254 for(i=0; i<entries; i++) {
2255 MonoPEResourceDirEntry *entry=&res_entries[i];
2258 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2259 name, entry, resource_dir,
2270 * mono_image_get_entry_point:
2271 * @image: the image where the entry point will be looked up.
2273 * Use this routine to determine the metadata token for method that
2274 * has been flagged as the entry point.
2276 * Returns: the token for the entry point method in the image
2279 mono_image_get_entry_point (MonoImage *image)
2281 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2285 * mono_image_get_resource:
2286 * @image: the image where the resource will be looked up.
2287 * @offset: The offset to add to the resource
2288 * @size: a pointer to an int where the size of the resource will be stored
2290 * This is a low-level routine that fetches a resource from the
2291 * metadata that starts at a given @offset. The @size parameter is
2292 * filled with the data field as encoded in the metadata.
2294 * Returns: the pointer to the resource whose offset is @offset.
2297 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2299 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2300 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2303 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2306 data = mono_image_rva_map (image, ch->ch_resources.rva);
2311 *size = read32 (data);
2316 // Returning NULL with no error set will be interpeted as "not found"
2318 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2320 char *base_dir, *name;
2322 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2326 mono_error_init (error);
2328 if (fileidx < 1 || fileidx > t->rows)
2331 mono_image_lock (image);
2332 if (image->files && image->files [fileidx - 1]) {
2333 mono_image_unlock (image);
2334 return image->files [fileidx - 1];
2336 mono_image_unlock (image);
2338 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2339 fname = mono_metadata_string_heap (image, fname_id);
2340 base_dir = g_path_get_dirname (image->name);
2341 name = g_build_filename (base_dir, fname, NULL);
2342 res = mono_image_open (name, NULL);
2346 mono_image_lock (image);
2347 if (image->files && image->files [fileidx - 1]) {
2348 MonoImage *old = res;
2349 res = image->files [fileidx - 1];
2350 mono_image_unlock (image);
2351 mono_image_close (old);
2354 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2355 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2356 mono_image_unlock (image);
2357 mono_image_close (res);
2361 for (i = 0; i < res->module_count; ++i) {
2362 if (res->modules [i] && !res->modules [i]->assembly)
2363 res->modules [i]->assembly = image->assembly;
2366 if (!image->files) {
2367 image->files = g_new0 (MonoImage*, t->rows);
2368 image->file_count = t->rows;
2370 image->files [fileidx - 1] = res;
2371 mono_image_unlock (image);
2372 /* vtable fixup can't happen with the image lock held */
2374 if (res->is_module_handle)
2375 mono_image_fixup_vtable (res);
2386 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2389 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2390 mono_error_assert_ok (&error);
2395 * mono_image_get_strong_name:
2396 * @image: a MonoImage
2397 * @size: a guint32 pointer, or NULL.
2399 * If the image has a strong name, and @size is not NULL, the value
2400 * pointed to by size will have the size of the strong name.
2402 * Returns: NULL if the image does not have a strong name, or a
2403 * pointer to the public key.
2406 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2408 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2409 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2412 if (!de->size || !de->rva)
2414 data = mono_image_rva_map (image, de->rva);
2423 * mono_image_strong_name_position:
2424 * @image: a MonoImage
2425 * @size: a guint32 pointer, or NULL.
2427 * If the image has a strong name, and @size is not NULL, the value
2428 * pointed to by size will have the size of the strong name.
2430 * Returns: the position within the image file where the strong name
2434 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2436 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2437 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2442 if (!de->size || !de->rva)
2444 pos = mono_cli_rva_image_map (image, de->rva);
2445 return pos == INVALID_ADDRESS ? 0 : pos;
2449 * mono_image_get_public_key:
2450 * @image: a MonoImage
2451 * @size: a guint32 pointer, or NULL.
2453 * This is used to obtain the public key in the @image.
2455 * If the image has a public key, and @size is not NULL, the value
2456 * pointed to by size will have the size of the public key.
2458 * Returns: NULL if the image does not have a public key, or a pointer
2459 * to the public key.
2462 mono_image_get_public_key (MonoImage *image, guint32 *size)
2467 if (image_is_dynamic (image)) {
2469 *size = ((MonoDynamicImage*)image)->public_key_len;
2470 return (char*)((MonoDynamicImage*)image)->public_key;
2472 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2474 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2477 pubkey = mono_metadata_blob_heap (image, tok);
2478 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2485 * mono_image_get_name:
2486 * @name: a MonoImage
2488 * Returns: the name of the assembly.
2491 mono_image_get_name (MonoImage *image)
2493 return image->assembly_name;
2497 * mono_image_get_filename:
2498 * @image: a MonoImage
2500 * Used to get the filename that hold the actual MonoImage
2502 * Returns: the filename.
2505 mono_image_get_filename (MonoImage *image)
2511 mono_image_get_guid (MonoImage *image)
2516 const MonoTableInfo*
2517 mono_image_get_table_info (MonoImage *image, int table_id)
2519 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2521 return &image->tables [table_id];
2525 mono_image_get_table_rows (MonoImage *image, int table_id)
2527 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2529 return image->tables [table_id].rows;
2533 mono_table_info_get_rows (const MonoTableInfo *table)
2539 * mono_image_get_assembly:
2540 * @image: the MonoImage.
2542 * Use this routine to get the assembly that owns this image.
2544 * Returns: the assembly that holds this image.
2547 mono_image_get_assembly (MonoImage *image)
2549 return image->assembly;
2553 * mono_image_is_dynamic:
2554 * @image: the MonoImage
2556 * Determines if the given image was created dynamically through the
2557 * System.Reflection.Emit API
2559 * Returns: TRUE if the image was created dynamically, FALSE if not.
2562 mono_image_is_dynamic (MonoImage *image)
2564 return image_is_dynamic (image);
2568 * mono_image_has_authenticode_entry:
2569 * @image: the MonoImage
2571 * Use this routine to determine if the image has a Authenticode
2572 * Certificate Table.
2574 * Returns: TRUE if the image contains an authenticode entry in the PE
2578 mono_image_has_authenticode_entry (MonoImage *image)
2580 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2581 MonoDotNetHeader *header = &iinfo->cli_header;
2584 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2585 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2586 return ((de->rva != 0) && (de->size > 8));
2590 mono_image_alloc (MonoImage *image, guint size)
2594 #ifndef DISABLE_PERFCOUNTERS
2595 mono_perfcounters->loader_bytes += size;
2597 mono_image_lock (image);
2598 res = mono_mempool_alloc (image->mempool, size);
2599 mono_image_unlock (image);
2605 mono_image_alloc0 (MonoImage *image, guint size)
2609 #ifndef DISABLE_PERFCOUNTERS
2610 mono_perfcounters->loader_bytes += size;
2612 mono_image_lock (image);
2613 res = mono_mempool_alloc0 (image->mempool, size);
2614 mono_image_unlock (image);
2620 mono_image_strdup (MonoImage *image, const char *s)
2624 #ifndef DISABLE_PERFCOUNTERS
2625 mono_perfcounters->loader_bytes += strlen (s);
2627 mono_image_lock (image);
2628 res = mono_mempool_strdup (image->mempool, s);
2629 mono_image_unlock (image);
2635 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2638 mono_image_lock (image);
2639 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2640 mono_image_unlock (image);
2641 #ifndef DISABLE_PERFCOUNTERS
2642 mono_perfcounters->loader_bytes += strlen (buf);
2648 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2653 va_start (args, format);
2654 buf = mono_image_strdup_vprintf (image, format, args);
2660 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2664 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2665 new_list->data = data;
2666 new_list->prev = list ? list->prev : NULL;
2667 new_list->next = list;
2670 new_list->prev->next = new_list;
2672 list->prev = new_list;
2678 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2682 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2683 new_list->data = data;
2684 new_list->next = NULL;
2686 return g_slist_concat (list, new_list);
2690 mono_image_lock (MonoImage *image)
2692 mono_locks_os_acquire (&image->lock, ImageDataLock);
2696 mono_image_unlock (MonoImage *image)
2698 mono_locks_os_release (&image->lock, ImageDataLock);
2703 * mono_image_property_lookup:
2705 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2707 * LOCKING: Takes the image lock
2710 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2714 mono_image_lock (image);
2715 res = mono_property_hash_lookup (image->property_hash, subject, property);
2716 mono_image_unlock (image);
2722 * mono_image_property_insert:
2724 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2726 * LOCKING: Takes the image lock
2729 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2731 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2732 mono_image_lock (image);
2733 mono_property_hash_insert (image->property_hash, subject, property, value);
2734 mono_image_unlock (image);
2738 * mono_image_property_remove:
2740 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2742 * LOCKING: Takes the image lock
2745 mono_image_property_remove (MonoImage *image, gpointer subject)
2747 mono_image_lock (image);
2748 mono_property_hash_remove_object (image->property_hash, subject);
2749 mono_image_unlock (image);
2753 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2755 MonoImage *image = klass->image;
2756 g_assert (image_is_dynamic (image));
2757 mono_image_lock (image);
2758 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2759 mono_image_unlock (image);
2762 // 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.
2765 * mono_find_image_owner:
2767 * Find the image, if any, which a given pointer is located in the memory of.
2770 mono_find_image_owner (void *ptr)
2772 mono_images_lock ();
2774 MonoImage *owner = NULL;
2776 // Iterate over both by-path image hashes
2777 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2779 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2781 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2782 GHashTableIter iter;
2785 // Iterate over images within a hash
2786 g_hash_table_iter_init (&iter, target);
2787 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2789 mono_image_lock (image);
2790 if (mono_mempool_contains_addr (image->mempool, ptr))
2792 mono_image_unlock (image);
2796 mono_images_unlock ();