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/utils/checked-build.h>
31 #include <mono/utils/mono-logger-internals.h>
32 #include <mono/utils/mono-path.h>
33 #include <mono/utils/mono-mmap.h>
34 #include <mono/utils/mono-io-portability.h>
35 #include <mono/utils/atomic.h>
36 #include <mono/metadata/class-internals.h>
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/object-internals.h>
39 #include <mono/metadata/security-core-clr.h>
40 #include <mono/metadata/verify-internals.h>
41 #include <mono/metadata/verify.h>
42 #include <mono/metadata/image-internals.h>
43 #include <sys/types.h>
48 #include <mono/metadata/w32error.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 size_t needle_len = strlen (needle);
1169 size_t asm_len = strlen (image->name);
1170 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1178 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1179 gboolean care_about_cli, gboolean care_about_pecoff)
1181 MonoCLIImageInfo *iinfo;
1182 MonoDotNetHeader *header;
1183 GSList *errors = NULL;
1186 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1188 mono_image_init (image);
1190 iinfo = (MonoCLIImageInfo *)image->image_info;
1191 header = &iinfo->cli_header;
1193 if (!image->metadata_only) {
1194 for (l = image_loaders; l; l = l->next) {
1195 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1196 if (loader->match (image)) {
1197 image->loader = loader;
1201 if (!image->loader) {
1203 *status = MONO_IMAGE_IMAGE_INVALID;
1208 *status = MONO_IMAGE_IMAGE_INVALID;
1210 if (care_about_pecoff == FALSE)
1213 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1216 if (!mono_image_load_pe_data (image))
1219 image->loader = (MonoImageLoader*)&pe_loader;
1222 if (care_about_cli == FALSE) {
1226 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1229 if (!mono_image_load_cli_data (image))
1232 if (!image->ref_only && is_problematic_image (image)) {
1233 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1234 *status = MONO_IMAGE_IMAGE_INVALID;
1238 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1241 mono_image_load_names (image);
1243 load_modules (image);
1246 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1248 *status = MONO_IMAGE_OK;
1254 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1255 g_warning ("Could not load image %s due to %s", image->name, info->message);
1256 mono_free_verify_list (errors);
1258 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1259 mono_image_close (image);
1264 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1265 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1267 MonoCLIImageInfo *iinfo;
1271 if ((filed = mono_file_map_open (fname)) == NULL){
1272 if (IS_PORTABILITY_SET) {
1273 gchar *ffname = mono_portability_find_file (fname, TRUE);
1275 filed = mono_file_map_open (ffname);
1280 if (filed == NULL) {
1282 *status = MONO_IMAGE_ERROR_ERRNO;
1287 image = g_new0 (MonoImage, 1);
1288 image->raw_buffer_used = TRUE;
1289 image->raw_data_len = mono_file_map_size (filed);
1290 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);
1291 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1292 if (!image->raw_data) {
1293 image->fileio_used = TRUE;
1294 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);
1297 if (!image->raw_data) {
1298 mono_file_map_close (filed);
1301 *status = MONO_IMAGE_IMAGE_INVALID;
1304 iinfo = g_new0 (MonoCLIImageInfo, 1);
1305 image->image_info = iinfo;
1306 image->name = mono_path_resolve_symlinks (fname);
1307 image->ref_only = refonly;
1308 image->metadata_only = metadata_only;
1309 image->ref_count = 1;
1310 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1311 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1313 mono_file_map_close (filed);
1314 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1318 * mono_image_loaded:
1319 * @name: path or assembly name of the image to load
1320 * @refonly: Check with respect to reflection-only loads?
1322 * This routine verifies that the given image is loaded.
1323 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1325 * Returns: the loaded MonoImage, or NULL on failure.
1328 mono_image_loaded_full (const char *name, gboolean refonly)
1332 mono_images_lock ();
1333 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1335 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1336 mono_images_unlock ();
1342 * mono_image_loaded:
1343 * @name: path or assembly name of the image to load
1345 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1347 * Returns: the loaded MonoImage, or NULL on failure.
1350 mono_image_loaded (const char *name)
1352 return mono_image_loaded_full (name, FALSE);
1361 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1363 GuidData *data = (GuidData *)user_data;
1368 image = (MonoImage *)val;
1369 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1374 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1377 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1381 mono_images_lock ();
1382 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1383 mono_images_unlock ();
1388 mono_image_loaded_by_guid (const char *guid)
1390 return mono_image_loaded_by_guid_full (guid, FALSE);
1394 register_image (MonoImage *image)
1397 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1399 mono_images_lock ();
1400 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1403 /* Somebody else beat us to it */
1404 mono_image_addref (image2);
1405 mono_images_unlock ();
1406 mono_image_close (image);
1410 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1411 g_hash_table_insert (loaded_images, image->name, image);
1412 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1413 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1414 mono_images_unlock ();
1420 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1422 MonoCLIImageInfo *iinfo;
1426 if (!data || !data_len) {
1428 *status = MONO_IMAGE_IMAGE_INVALID;
1433 datac = (char *)g_try_malloc (data_len);
1436 *status = MONO_IMAGE_ERROR_ERRNO;
1439 memcpy (datac, data, data_len);
1442 image = g_new0 (MonoImage, 1);
1443 image->raw_data = datac;
1444 image->raw_data_len = data_len;
1445 image->raw_data_allocated = need_copy;
1446 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1447 iinfo = g_new0 (MonoCLIImageInfo, 1);
1448 image->image_info = iinfo;
1449 image->ref_only = refonly;
1450 image->metadata_only = metadata_only;
1451 image->ref_count = 1;
1453 image = do_mono_image_load (image, status, TRUE, TRUE);
1457 return register_image (image);
1461 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1463 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1467 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1469 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1473 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1475 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1479 /* fname is not duplicated. */
1481 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1484 MonoCLIImageInfo* iinfo;
1486 image = g_new0 (MonoImage, 1);
1487 image->raw_data = (char*) module_handle;
1488 image->is_module_handle = TRUE;
1489 iinfo = g_new0 (MonoCLIImageInfo, 1);
1490 image->image_info = iinfo;
1491 image->name = fname;
1492 image->ref_count = has_entry_point ? 0 : 1;
1493 image->has_entry_point = has_entry_point;
1495 image = do_mono_image_load (image, status, TRUE, TRUE);
1499 return register_image (image);
1504 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1507 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1510 g_return_val_if_fail (fname != NULL, NULL);
1513 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1514 // then assemblies need to be loaded with LoadLibrary:
1515 if (!refonly && coree_module_handle) {
1516 HMODULE module_handle;
1517 guint16 *fname_utf16;
1520 absfname = mono_path_resolve_symlinks (fname);
1523 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1524 mono_images_lock ();
1525 image = g_hash_table_lookup (loaded_images, absfname);
1526 if (image) { // Image already loaded
1527 g_assert (image->is_module_handle);
1528 if (image->has_entry_point && image->ref_count == 0) {
1529 /* Increment reference count on images loaded outside of the runtime. */
1530 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1531 /* The image is already loaded because _CorDllMain removes images from the hash. */
1532 module_handle = LoadLibrary (fname_utf16);
1533 g_assert (module_handle == (HMODULE) image->raw_data);
1535 mono_image_addref (image);
1536 mono_images_unlock ();
1538 g_free (fname_utf16);
1543 // Image not loaded, load it now
1544 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1545 module_handle = MonoLoadImage (fname_utf16);
1546 if (status && module_handle == NULL)
1547 last_error = mono_w32error_get_last ();
1549 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1550 image = g_hash_table_lookup (loaded_images, absfname);
1552 mono_image_addref (image);
1553 mono_images_unlock ();
1555 g_free (fname_utf16);
1557 if (module_handle == NULL) {
1561 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1562 *status = MONO_IMAGE_IMAGE_INVALID;
1564 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1574 g_assert (image->is_module_handle);
1575 g_assert (image->has_entry_point);
1580 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1584 absfname = mono_path_canonicalize (fname);
1587 * The easiest solution would be to do all the loading inside the mutex,
1588 * but that would lead to scalability problems. So we let the loading
1589 * happen outside the mutex, and if multiple threads happen to load
1590 * the same image, we discard all but the first copy.
1592 mono_images_lock ();
1593 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1596 if (image) { // Image already loaded
1597 mono_image_addref (image);
1598 mono_images_unlock ();
1601 mono_images_unlock ();
1603 // Image not loaded, load it now
1604 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1608 return register_image (image);
1613 * @fname: filename that points to the module we want to open
1614 * @status: An error condition is returned in this field
1616 * Returns: An open image of type %MonoImage or NULL on error.
1617 * The caller holds a temporary reference to the returned image which should be cleared
1618 * when no longer needed by calling mono_image_close ().
1619 * if NULL, then check the value of @status for details on the error
1622 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1624 return mono_image_open_full (fname, status, FALSE);
1628 * mono_pe_file_open:
1629 * @fname: filename that points to the module we want to open
1630 * @status: An error condition is returned in this field
1632 * Returns: An open image of type %MonoImage or NULL on error. if
1633 * NULL, then check the value of @status for details on the error.
1634 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1635 * It's just a PE file loader, used for FileVersionInfo. It also does
1636 * not use the image cache.
1639 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1641 g_return_val_if_fail (fname != NULL, NULL);
1643 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1647 * mono_image_open_raw
1648 * @fname: filename that points to the module we want to open
1649 * @status: An error condition is returned in this field
1651 * Returns an image without loading neither pe or cli data.
1653 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1656 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1658 g_return_val_if_fail (fname != NULL, NULL);
1660 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1664 * mono_image_open_metadata_only:
1666 * Open an image which contains metadata only without a PE header.
1669 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1671 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1675 mono_image_fixup_vtable (MonoImage *image)
1678 MonoCLIImageInfo *iinfo;
1680 MonoVTableFixup *vtfixup;
1686 g_assert (image->is_module_handle);
1688 iinfo = image->image_info;
1689 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1690 if (!de->rva || !de->size)
1692 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1696 count = de->size / sizeof (MonoVTableFixup);
1698 if (!vtfixup->rva || !vtfixup->count)
1701 slot = mono_image_rva_map (image, vtfixup->rva);
1703 slot_type = vtfixup->type;
1704 slot_count = vtfixup->count;
1705 if (slot_type & VTFIXUP_TYPE_32BIT)
1706 while (slot_count--) {
1707 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1708 slot = ((guint32*) slot) + 1;
1710 else if (slot_type & VTFIXUP_TYPE_64BIT)
1711 while (slot_count--) {
1712 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1713 slot = ((guint32*) slot) + 1;
1716 g_assert_not_reached();
1721 g_assert_not_reached();
1726 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1728 g_hash_table_destroy ((GHashTable*)val);
1733 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1735 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1740 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1742 g_slist_free ((GSList*)val);
1746 * mono_image_addref:
1747 * @image: The image file we wish to add a reference to
1749 * Increases the reference count of an image.
1752 mono_image_addref (MonoImage *image)
1754 InterlockedIncrement (&image->ref_count);
1758 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1760 stream->alloc_size = stream->index = stream->offset = 0;
1761 g_free (stream->data);
1762 stream->data = NULL;
1764 g_hash_table_destroy (stream->hash);
1765 stream->hash = NULL;
1770 free_hash (GHashTable *hash)
1773 g_hash_table_destroy (hash);
1777 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1779 free_hash (cache->delegate_invoke_cache);
1780 free_hash (cache->delegate_begin_invoke_cache);
1781 free_hash (cache->delegate_end_invoke_cache);
1782 free_hash (cache->runtime_invoke_cache);
1783 free_hash (cache->runtime_invoke_vtype_cache);
1785 free_hash (cache->delegate_abstract_invoke_cache);
1787 free_hash (cache->runtime_invoke_direct_cache);
1788 free_hash (cache->managed_wrapper_cache);
1790 free_hash (cache->native_wrapper_cache);
1791 free_hash (cache->native_wrapper_aot_cache);
1792 free_hash (cache->native_wrapper_check_cache);
1793 free_hash (cache->native_wrapper_aot_check_cache);
1795 free_hash (cache->native_func_wrapper_aot_cache);
1796 free_hash (cache->remoting_invoke_cache);
1797 free_hash (cache->synchronized_cache);
1798 free_hash (cache->unbox_wrapper_cache);
1799 free_hash (cache->cominterop_invoke_cache);
1800 free_hash (cache->cominterop_wrapper_cache);
1801 free_hash (cache->thunk_invoke_cache);
1805 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1807 for (int i = 0; i < image_count; ++i) {
1809 if (!mono_image_close_except_pools (images [i]))
1816 * Returns whether mono_image_close_finish() must be called as well.
1817 * We must unload images in two steps because clearing the domain in
1818 * SGen requires the class metadata to be intact, but we need to free
1819 * the mono_g_hash_tables in case a collection occurs during domain
1820 * unloading and the roots would trip up the GC.
1823 mono_image_close_except_pools (MonoImage *image)
1826 GHashTable *loaded_images, *loaded_images_by_name;
1829 g_return_val_if_fail (image != NULL, FALSE);
1832 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1833 * register_image () can't grab an image which is being closed.
1835 mono_images_lock ();
1837 if (InterlockedDecrement (&image->ref_count) > 0) {
1838 mono_images_unlock ();
1842 loaded_images = get_loaded_images_hash (image->ref_only);
1843 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1844 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1845 if (image == image2) {
1846 /* This is not true if we are called from mono_image_open () */
1847 g_hash_table_remove (loaded_images, image->name);
1849 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1850 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1852 mono_images_unlock ();
1855 if (image->is_module_handle && image->has_entry_point) {
1856 mono_images_lock ();
1857 if (image->ref_count == 0) {
1858 /* Image will be closed by _CorDllMain. */
1859 FreeLibrary ((HMODULE) image->raw_data);
1860 mono_images_unlock ();
1863 mono_images_unlock ();
1867 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1869 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1871 mono_image_invoke_unload_hook (image);
1873 mono_metadata_clean_for_image (image);
1876 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1877 * assemblies, so we can't release these references in mono_assembly_close () since the
1878 * MonoImage might outlive its associated MonoAssembly.
1880 if (image->references && !image_is_dynamic (image)) {
1881 for (i = 0; i < image->nreferences; i++) {
1882 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1883 if (!mono_assembly_close_except_image_pools (image->references [i]))
1884 image->references [i] = NULL;
1888 if (image->references) {
1889 g_free (image->references);
1890 image->references = NULL;
1895 mono_images_lock ();
1896 if (image->is_module_handle && !image->has_entry_point)
1897 FreeLibrary ((HMODULE) image->raw_data);
1898 mono_images_unlock ();
1901 if (image->raw_buffer_used) {
1902 if (image->raw_data != NULL) {
1904 if (image->fileio_used)
1905 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1908 mono_file_unmap (image->raw_data, image->raw_data_handle);
1912 if (image->raw_data_allocated) {
1913 /* FIXME: do we need this? (image is disposed anyway) */
1914 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1915 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1917 if ((image->raw_metadata > image->raw_data) &&
1918 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1919 image->raw_metadata = NULL;
1921 for (i = 0; i < ii->cli_section_count; i++)
1922 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1923 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1924 ii->cli_sections [i] = NULL;
1926 g_free (image->raw_data);
1929 if (debug_assembly_unload) {
1930 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1932 g_free (image->name);
1933 g_free (image->guid);
1934 g_free (image->version);
1937 if (image->method_cache)
1938 g_hash_table_destroy (image->method_cache);
1939 if (image->methodref_cache)
1940 g_hash_table_destroy (image->methodref_cache);
1941 mono_internal_hash_table_destroy (&image->class_cache);
1942 mono_conc_hashtable_destroy (image->field_cache);
1943 if (image->array_cache) {
1944 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1945 g_hash_table_destroy (image->array_cache);
1947 if (image->szarray_cache)
1948 g_hash_table_destroy (image->szarray_cache);
1949 if (image->ptr_cache)
1950 g_hash_table_destroy (image->ptr_cache);
1951 if (image->name_cache) {
1952 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1953 g_hash_table_destroy (image->name_cache);
1956 free_hash (image->delegate_bound_static_invoke_cache);
1957 free_hash (image->runtime_invoke_vcall_cache);
1958 free_hash (image->ldfld_wrapper_cache);
1959 free_hash (image->ldflda_wrapper_cache);
1960 free_hash (image->stfld_wrapper_cache);
1961 free_hash (image->isinst_cache);
1962 free_hash (image->castclass_cache);
1963 free_hash (image->icall_wrapper_cache);
1964 free_hash (image->proxy_isinst_cache);
1965 free_hash (image->var_cache_slow);
1966 free_hash (image->mvar_cache_slow);
1967 free_hash (image->var_cache_constrained);
1968 free_hash (image->mvar_cache_constrained);
1969 free_hash (image->wrapper_param_names);
1970 free_hash (image->pinvoke_scopes);
1971 free_hash (image->pinvoke_scope_filenames);
1972 free_hash (image->native_func_wrapper_cache);
1973 free_hash (image->typespec_cache);
1975 mono_wrapper_caches_free (&image->wrapper_caches);
1977 for (i = 0; i < image->gshared_types_len; ++i)
1978 free_hash (image->gshared_types [i]);
1979 g_free (image->gshared_types);
1981 /* The ownership of signatures is not well defined */
1982 g_hash_table_destroy (image->memberref_signatures);
1983 g_hash_table_destroy (image->helper_signatures);
1984 g_hash_table_destroy (image->method_signatures);
1986 if (image->rgctx_template_hash)
1987 g_hash_table_destroy (image->rgctx_template_hash);
1989 if (image->property_hash)
1990 mono_property_hash_destroy (image->property_hash);
1993 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
1994 cleared during shutdown as we don't perform regular appdomain unload for the root one.
1996 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
1997 image->reflection_info_unregister_classes = NULL;
1999 if (image->interface_bitset) {
2000 mono_unload_interface_ids (image->interface_bitset);
2001 mono_bitset_free (image->interface_bitset);
2003 if (image->image_info){
2004 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2006 if (ii->cli_section_tables)
2007 g_free (ii->cli_section_tables);
2008 if (ii->cli_sections)
2009 g_free (ii->cli_sections);
2010 g_free (image->image_info);
2013 mono_image_close_except_pools_all (image->files, image->file_count);
2014 mono_image_close_except_pools_all (image->modules, image->module_count);
2015 if (image->modules_loaded)
2016 g_free (image->modules_loaded);
2018 mono_os_mutex_destroy (&image->szarray_cache_lock);
2019 mono_os_mutex_destroy (&image->lock);
2021 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2022 if (image_is_dynamic (image)) {
2023 /* Dynamic images are GC_MALLOCed */
2024 g_free ((char*)image->module_name);
2025 mono_dynamic_image_free ((MonoDynamicImage*)image);
2028 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2034 mono_image_close_all (MonoImage**images, int image_count)
2036 for (int i = 0; i < image_count; ++i) {
2038 mono_image_close_finish (images [i]);
2045 mono_image_close_finish (MonoImage *image)
2049 if (image->references && !image_is_dynamic (image)) {
2050 for (i = 0; i < image->nreferences; i++) {
2051 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2052 mono_assembly_close_finish (image->references [i]);
2055 g_free (image->references);
2056 image->references = NULL;
2059 mono_image_close_all (image->files, image->file_count);
2060 mono_image_close_all (image->modules, image->module_count);
2062 #ifndef DISABLE_PERFCOUNTERS
2063 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2066 if (!image_is_dynamic (image)) {
2067 if (debug_assembly_unload)
2068 mono_mempool_invalidate (image->mempool);
2070 mono_mempool_destroy (image->mempool);
2074 if (debug_assembly_unload)
2075 mono_mempool_invalidate (image->mempool);
2077 mono_mempool_destroy (image->mempool);
2078 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2085 * @image: The image file we wish to close
2087 * Closes an image file, deallocates all memory consumed and
2088 * unmaps all possible sections of the file
2091 mono_image_close (MonoImage *image)
2093 if (mono_image_close_except_pools (image))
2094 mono_image_close_finish (image);
2098 * mono_image_strerror:
2099 * @status: an code indicating the result from a recent operation
2101 * Returns: a string describing the error
2104 mono_image_strerror (MonoImageOpenStatus status)
2109 case MONO_IMAGE_ERROR_ERRNO:
2110 return strerror (errno);
2111 case MONO_IMAGE_IMAGE_INVALID:
2112 return "File does not contain a valid CIL image";
2113 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2114 return "An assembly was referenced, but could not be found";
2116 return "Internal error";
2120 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2121 guint32 lang_id, gunichar2 *name,
2122 MonoPEResourceDirEntry *entry,
2123 MonoPEResourceDir *root, guint32 level)
2125 gboolean is_string, is_dir;
2126 guint32 name_offset, dir_offset;
2128 /* Level 0 holds a directory entry for each type of resource
2129 * (identified by ID or name).
2131 * Level 1 holds a directory entry for each named resource
2132 * item, and each "anonymous" item of a particular type of
2135 * Level 2 holds a directory entry for each language pointing to
2138 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2139 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2141 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2142 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2147 } else if (level==1) {
2148 if (res_id != name_offset)
2152 is_string==TRUE && name!=lookup (name_offset)) {
2156 } else if (level==2) {
2157 if (is_string || (lang_id != 0 && name_offset != lang_id))
2160 g_assert_not_reached ();
2164 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2165 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2168 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2170 for(i=0; i<entries; i++) {
2171 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2174 ret=mono_image_walk_resource_tree (info, res_id,
2185 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2186 MonoPEResourceDataEntry *res;
2188 res = g_new0 (MonoPEResourceDataEntry, 1);
2190 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2191 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2192 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2193 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2200 * mono_image_lookup_resource:
2201 * @image: the image to look up the resource in
2202 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2203 * @lang_id: The language id.
2204 * @name: the resource name to lookup.
2206 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2207 * of the given resource. The caller should free it using g_free () when no longer
2211 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2213 MonoCLIImageInfo *info;
2214 MonoDotNetHeader *header;
2215 MonoPEDatadir *datadir;
2216 MonoPEDirEntry *rsrc;
2217 MonoPEResourceDir *resource_dir;
2218 MonoPEResourceDirEntry *res_entries;
2225 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2227 info = (MonoCLIImageInfo *)image->image_info;
2232 header=&info->cli_header;
2237 datadir=&header->datadir;
2242 rsrc=&datadir->pe_resource_table;
2247 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2248 if(resource_dir==NULL) {
2252 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2253 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2255 for(i=0; i<entries; i++) {
2256 MonoPEResourceDirEntry *entry=&res_entries[i];
2259 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2260 name, entry, resource_dir,
2271 * mono_image_get_entry_point:
2272 * @image: the image where the entry point will be looked up.
2274 * Use this routine to determine the metadata token for method that
2275 * has been flagged as the entry point.
2277 * Returns: the token for the entry point method in the image
2280 mono_image_get_entry_point (MonoImage *image)
2282 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2286 * mono_image_get_resource:
2287 * @image: the image where the resource will be looked up.
2288 * @offset: The offset to add to the resource
2289 * @size: a pointer to an int where the size of the resource will be stored
2291 * This is a low-level routine that fetches a resource from the
2292 * metadata that starts at a given @offset. The @size parameter is
2293 * filled with the data field as encoded in the metadata.
2295 * Returns: the pointer to the resource whose offset is @offset.
2298 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2300 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2301 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2304 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2307 data = mono_image_rva_map (image, ch->ch_resources.rva);
2312 *size = read32 (data);
2317 // Returning NULL with no error set will be interpeted as "not found"
2319 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2321 char *base_dir, *name;
2323 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2327 mono_error_init (error);
2329 if (fileidx < 1 || fileidx > t->rows)
2332 mono_image_lock (image);
2333 if (image->files && image->files [fileidx - 1]) {
2334 mono_image_unlock (image);
2335 return image->files [fileidx - 1];
2337 mono_image_unlock (image);
2339 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2340 fname = mono_metadata_string_heap (image, fname_id);
2341 base_dir = g_path_get_dirname (image->name);
2342 name = g_build_filename (base_dir, fname, NULL);
2343 res = mono_image_open (name, NULL);
2347 mono_image_lock (image);
2348 if (image->files && image->files [fileidx - 1]) {
2349 MonoImage *old = res;
2350 res = image->files [fileidx - 1];
2351 mono_image_unlock (image);
2352 mono_image_close (old);
2355 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2356 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2357 mono_image_unlock (image);
2358 mono_image_close (res);
2362 for (i = 0; i < res->module_count; ++i) {
2363 if (res->modules [i] && !res->modules [i]->assembly)
2364 res->modules [i]->assembly = image->assembly;
2367 if (!image->files) {
2368 image->files = g_new0 (MonoImage*, t->rows);
2369 image->file_count = t->rows;
2371 image->files [fileidx - 1] = res;
2372 mono_image_unlock (image);
2373 /* vtable fixup can't happen with the image lock held */
2375 if (res->is_module_handle)
2376 mono_image_fixup_vtable (res);
2387 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2390 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2391 mono_error_assert_ok (&error);
2396 * mono_image_get_strong_name:
2397 * @image: a MonoImage
2398 * @size: a guint32 pointer, or NULL.
2400 * If the image has a strong name, and @size is not NULL, the value
2401 * pointed to by size will have the size of the strong name.
2403 * Returns: NULL if the image does not have a strong name, or a
2404 * pointer to the public key.
2407 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2409 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2410 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2413 if (!de->size || !de->rva)
2415 data = mono_image_rva_map (image, de->rva);
2424 * mono_image_strong_name_position:
2425 * @image: a MonoImage
2426 * @size: a guint32 pointer, or NULL.
2428 * If the image has a strong name, and @size is not NULL, the value
2429 * pointed to by size will have the size of the strong name.
2431 * Returns: the position within the image file where the strong name
2435 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2437 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2438 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2443 if (!de->size || !de->rva)
2445 pos = mono_cli_rva_image_map (image, de->rva);
2446 return pos == INVALID_ADDRESS ? 0 : pos;
2450 * mono_image_get_public_key:
2451 * @image: a MonoImage
2452 * @size: a guint32 pointer, or NULL.
2454 * This is used to obtain the public key in the @image.
2456 * If the image has a public key, and @size is not NULL, the value
2457 * pointed to by size will have the size of the public key.
2459 * Returns: NULL if the image does not have a public key, or a pointer
2460 * to the public key.
2463 mono_image_get_public_key (MonoImage *image, guint32 *size)
2468 if (image_is_dynamic (image)) {
2470 *size = ((MonoDynamicImage*)image)->public_key_len;
2471 return (char*)((MonoDynamicImage*)image)->public_key;
2473 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2475 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2478 pubkey = mono_metadata_blob_heap (image, tok);
2479 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2486 * mono_image_get_name:
2487 * @name: a MonoImage
2489 * Returns: the name of the assembly.
2492 mono_image_get_name (MonoImage *image)
2494 return image->assembly_name;
2498 * mono_image_get_filename:
2499 * @image: a MonoImage
2501 * Used to get the filename that hold the actual MonoImage
2503 * Returns: the filename.
2506 mono_image_get_filename (MonoImage *image)
2512 mono_image_get_guid (MonoImage *image)
2517 const MonoTableInfo*
2518 mono_image_get_table_info (MonoImage *image, int table_id)
2520 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2522 return &image->tables [table_id];
2526 mono_image_get_table_rows (MonoImage *image, int table_id)
2528 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2530 return image->tables [table_id].rows;
2534 mono_table_info_get_rows (const MonoTableInfo *table)
2540 * mono_image_get_assembly:
2541 * @image: the MonoImage.
2543 * Use this routine to get the assembly that owns this image.
2545 * Returns: the assembly that holds this image.
2548 mono_image_get_assembly (MonoImage *image)
2550 return image->assembly;
2554 * mono_image_is_dynamic:
2555 * @image: the MonoImage
2557 * Determines if the given image was created dynamically through the
2558 * System.Reflection.Emit API
2560 * Returns: TRUE if the image was created dynamically, FALSE if not.
2563 mono_image_is_dynamic (MonoImage *image)
2565 return image_is_dynamic (image);
2569 * mono_image_has_authenticode_entry:
2570 * @image: the MonoImage
2572 * Use this routine to determine if the image has a Authenticode
2573 * Certificate Table.
2575 * Returns: TRUE if the image contains an authenticode entry in the PE
2579 mono_image_has_authenticode_entry (MonoImage *image)
2581 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2582 MonoDotNetHeader *header = &iinfo->cli_header;
2585 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2586 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2587 return ((de->rva != 0) && (de->size > 8));
2591 mono_image_alloc (MonoImage *image, guint size)
2595 #ifndef DISABLE_PERFCOUNTERS
2596 mono_perfcounters->loader_bytes += size;
2598 mono_image_lock (image);
2599 res = mono_mempool_alloc (image->mempool, size);
2600 mono_image_unlock (image);
2606 mono_image_alloc0 (MonoImage *image, guint size)
2610 #ifndef DISABLE_PERFCOUNTERS
2611 mono_perfcounters->loader_bytes += size;
2613 mono_image_lock (image);
2614 res = mono_mempool_alloc0 (image->mempool, size);
2615 mono_image_unlock (image);
2621 mono_image_strdup (MonoImage *image, const char *s)
2625 #ifndef DISABLE_PERFCOUNTERS
2626 mono_perfcounters->loader_bytes += strlen (s);
2628 mono_image_lock (image);
2629 res = mono_mempool_strdup (image->mempool, s);
2630 mono_image_unlock (image);
2636 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2639 mono_image_lock (image);
2640 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2641 mono_image_unlock (image);
2642 #ifndef DISABLE_PERFCOUNTERS
2643 mono_perfcounters->loader_bytes += strlen (buf);
2649 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2654 va_start (args, format);
2655 buf = mono_image_strdup_vprintf (image, format, args);
2661 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2665 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2666 new_list->data = data;
2667 new_list->prev = list ? list->prev : NULL;
2668 new_list->next = list;
2671 new_list->prev->next = new_list;
2673 list->prev = new_list;
2679 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2683 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2684 new_list->data = data;
2685 new_list->next = NULL;
2687 return g_slist_concat (list, new_list);
2691 mono_image_lock (MonoImage *image)
2693 mono_locks_os_acquire (&image->lock, ImageDataLock);
2697 mono_image_unlock (MonoImage *image)
2699 mono_locks_os_release (&image->lock, ImageDataLock);
2704 * mono_image_property_lookup:
2706 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2708 * LOCKING: Takes the image lock
2711 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2715 mono_image_lock (image);
2716 res = mono_property_hash_lookup (image->property_hash, subject, property);
2717 mono_image_unlock (image);
2723 * mono_image_property_insert:
2725 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2727 * LOCKING: Takes the image lock
2730 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2732 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2733 mono_image_lock (image);
2734 mono_property_hash_insert (image->property_hash, subject, property, value);
2735 mono_image_unlock (image);
2739 * mono_image_property_remove:
2741 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2743 * LOCKING: Takes the image lock
2746 mono_image_property_remove (MonoImage *image, gpointer subject)
2748 mono_image_lock (image);
2749 mono_property_hash_remove_object (image->property_hash, subject);
2750 mono_image_unlock (image);
2754 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2756 MonoImage *image = klass->image;
2757 g_assert (image_is_dynamic (image));
2758 mono_image_lock (image);
2759 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2760 mono_image_unlock (image);
2763 // 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.
2766 * mono_find_image_owner:
2768 * Find the image, if any, which a given pointer is located in the memory of.
2771 mono_find_image_owner (void *ptr)
2773 mono_images_lock ();
2775 MonoImage *owner = NULL;
2777 // Iterate over both by-path image hashes
2778 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2780 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2782 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2783 GHashTableIter iter;
2786 // Iterate over images within a hash
2787 g_hash_table_iter_init (&iter, target);
2788 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2790 mono_image_lock (image);
2791 if (mono_mempool_contains_addr (image->mempool, ptr))
2793 mono_image_unlock (image);
2797 mono_images_unlock ();