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 SYS_REF_DISP_PROXY = 5, //System.Reflection.DispatchProxy
1101 SYS_VALUE_TUPLE = 6, //System.ValueTuple
1102 } IgnoredAssemblyNames;
1107 const char guid [40];
1110 const char *ignored_assemblies_names[] = {
1111 "System.Runtime.InteropServices.RuntimeInformation.dll",
1112 "System.Globalization.Extensions.dll",
1113 "System.IO.Compression.dll",
1114 "System.Net.Http.dll",
1115 "System.Text.Encoding.CodePages.dll",
1116 "System.Reflection.DispatchProxy.dll",
1117 "System.ValueTuple.dll"
1120 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1122 static const IgnoredAssembly ignored_assemblies [] = {
1123 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1124 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1125 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1126 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1127 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1128 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1129 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1130 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1131 IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1132 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1133 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1134 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1135 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1136 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1137 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1138 IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
1143 static void Main () {
1146 for (int i = 0; i < str.Length; ++i)
1147 h = ((h << 5) + h) ^ str[i];
1149 Console.WriteLine ("{0:X}", h);
1153 hash_guid (const char *str)
1157 h = ((h << 5) + h) ^ *str;
1165 is_problematic_image (MonoImage *image)
1167 int h = hash_guid (image->guid);
1169 //TODO make this more cache effiecient.
1170 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1171 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1172 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1173 const char *needle = ignored_assemblies_names [ignored_assemblies [i].assembly_name];
1174 size_t needle_len = strlen (needle);
1175 size_t asm_len = strlen (image->name);
1176 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1184 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1185 gboolean care_about_cli, gboolean care_about_pecoff)
1187 MonoCLIImageInfo *iinfo;
1188 MonoDotNetHeader *header;
1189 GSList *errors = NULL;
1192 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1194 mono_image_init (image);
1196 iinfo = (MonoCLIImageInfo *)image->image_info;
1197 header = &iinfo->cli_header;
1199 if (!image->metadata_only) {
1200 for (l = image_loaders; l; l = l->next) {
1201 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1202 if (loader->match (image)) {
1203 image->loader = loader;
1207 if (!image->loader) {
1209 *status = MONO_IMAGE_IMAGE_INVALID;
1214 *status = MONO_IMAGE_IMAGE_INVALID;
1216 if (care_about_pecoff == FALSE)
1219 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1222 if (!mono_image_load_pe_data (image))
1225 image->loader = (MonoImageLoader*)&pe_loader;
1228 if (care_about_cli == FALSE) {
1232 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1235 if (!mono_image_load_cli_data (image))
1238 if (!image->ref_only && is_problematic_image (image)) {
1239 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1240 *status = MONO_IMAGE_IMAGE_INVALID;
1244 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1247 mono_image_load_names (image);
1249 load_modules (image);
1252 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1254 *status = MONO_IMAGE_OK;
1260 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1261 g_warning ("Could not load image %s due to %s", image->name, info->message);
1262 mono_free_verify_list (errors);
1264 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1265 mono_image_close (image);
1270 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1271 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1273 MonoCLIImageInfo *iinfo;
1277 if ((filed = mono_file_map_open (fname)) == NULL){
1278 if (IS_PORTABILITY_SET) {
1279 gchar *ffname = mono_portability_find_file (fname, TRUE);
1281 filed = mono_file_map_open (ffname);
1286 if (filed == NULL) {
1288 *status = MONO_IMAGE_ERROR_ERRNO;
1293 image = g_new0 (MonoImage, 1);
1294 image->raw_buffer_used = TRUE;
1295 image->raw_data_len = mono_file_map_size (filed);
1296 image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1297 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1298 if (!image->raw_data) {
1299 image->fileio_used = TRUE;
1300 image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1303 if (!image->raw_data) {
1304 mono_file_map_close (filed);
1307 *status = MONO_IMAGE_IMAGE_INVALID;
1310 iinfo = g_new0 (MonoCLIImageInfo, 1);
1311 image->image_info = iinfo;
1312 image->name = mono_path_resolve_symlinks (fname);
1313 image->ref_only = refonly;
1314 image->metadata_only = metadata_only;
1315 image->ref_count = 1;
1316 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1317 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1319 mono_file_map_close (filed);
1320 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1324 * mono_image_loaded:
1325 * @name: path or assembly name of the image to load
1326 * @refonly: Check with respect to reflection-only loads?
1328 * This routine verifies that the given image is loaded.
1329 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1331 * Returns: the loaded MonoImage, or NULL on failure.
1334 mono_image_loaded_full (const char *name, gboolean refonly)
1338 mono_images_lock ();
1339 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1341 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1342 mono_images_unlock ();
1348 * mono_image_loaded:
1349 * @name: path or assembly name of the image to load
1351 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1353 * Returns: the loaded MonoImage, or NULL on failure.
1356 mono_image_loaded (const char *name)
1358 return mono_image_loaded_full (name, FALSE);
1367 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1369 GuidData *data = (GuidData *)user_data;
1374 image = (MonoImage *)val;
1375 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1380 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1383 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1387 mono_images_lock ();
1388 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1389 mono_images_unlock ();
1394 mono_image_loaded_by_guid (const char *guid)
1396 return mono_image_loaded_by_guid_full (guid, FALSE);
1400 register_image (MonoImage *image)
1403 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1405 mono_images_lock ();
1406 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1409 /* Somebody else beat us to it */
1410 mono_image_addref (image2);
1411 mono_images_unlock ();
1412 mono_image_close (image);
1416 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1417 g_hash_table_insert (loaded_images, image->name, image);
1418 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1419 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1420 mono_images_unlock ();
1426 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1428 MonoCLIImageInfo *iinfo;
1432 if (!data || !data_len) {
1434 *status = MONO_IMAGE_IMAGE_INVALID;
1439 datac = (char *)g_try_malloc (data_len);
1442 *status = MONO_IMAGE_ERROR_ERRNO;
1445 memcpy (datac, data, data_len);
1448 image = g_new0 (MonoImage, 1);
1449 image->raw_data = datac;
1450 image->raw_data_len = data_len;
1451 image->raw_data_allocated = need_copy;
1452 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1453 iinfo = g_new0 (MonoCLIImageInfo, 1);
1454 image->image_info = iinfo;
1455 image->ref_only = refonly;
1456 image->metadata_only = metadata_only;
1457 image->ref_count = 1;
1459 image = do_mono_image_load (image, status, TRUE, TRUE);
1463 return register_image (image);
1467 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1469 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1473 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1475 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1479 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1481 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1485 /* fname is not duplicated. */
1487 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1490 MonoCLIImageInfo* iinfo;
1492 image = g_new0 (MonoImage, 1);
1493 image->raw_data = (char*) module_handle;
1494 image->is_module_handle = TRUE;
1495 iinfo = g_new0 (MonoCLIImageInfo, 1);
1496 image->image_info = iinfo;
1497 image->name = fname;
1498 image->ref_count = has_entry_point ? 0 : 1;
1499 image->has_entry_point = has_entry_point;
1501 image = do_mono_image_load (image, status, TRUE, TRUE);
1505 return register_image (image);
1510 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1513 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1516 g_return_val_if_fail (fname != NULL, NULL);
1519 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1520 // then assemblies need to be loaded with LoadLibrary:
1521 if (!refonly && coree_module_handle) {
1522 HMODULE module_handle;
1523 guint16 *fname_utf16;
1526 absfname = mono_path_resolve_symlinks (fname);
1529 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1530 mono_images_lock ();
1531 image = g_hash_table_lookup (loaded_images, absfname);
1532 if (image) { // Image already loaded
1533 g_assert (image->is_module_handle);
1534 if (image->has_entry_point && image->ref_count == 0) {
1535 /* Increment reference count on images loaded outside of the runtime. */
1536 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1537 /* The image is already loaded because _CorDllMain removes images from the hash. */
1538 module_handle = LoadLibrary (fname_utf16);
1539 g_assert (module_handle == (HMODULE) image->raw_data);
1541 mono_image_addref (image);
1542 mono_images_unlock ();
1544 g_free (fname_utf16);
1549 // Image not loaded, load it now
1550 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1551 module_handle = MonoLoadImage (fname_utf16);
1552 if (status && module_handle == NULL)
1553 last_error = mono_w32error_get_last ();
1555 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1556 image = g_hash_table_lookup (loaded_images, absfname);
1558 mono_image_addref (image);
1559 mono_images_unlock ();
1561 g_free (fname_utf16);
1563 if (module_handle == NULL) {
1567 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1568 *status = MONO_IMAGE_IMAGE_INVALID;
1570 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1580 g_assert (image->is_module_handle);
1581 g_assert (image->has_entry_point);
1586 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1590 absfname = mono_path_canonicalize (fname);
1593 * The easiest solution would be to do all the loading inside the mutex,
1594 * but that would lead to scalability problems. So we let the loading
1595 * happen outside the mutex, and if multiple threads happen to load
1596 * the same image, we discard all but the first copy.
1598 mono_images_lock ();
1599 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1602 if (image) { // Image already loaded
1603 mono_image_addref (image);
1604 mono_images_unlock ();
1607 mono_images_unlock ();
1609 // Image not loaded, load it now
1610 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1614 return register_image (image);
1619 * @fname: filename that points to the module we want to open
1620 * @status: An error condition is returned in this field
1622 * Returns: An open image of type %MonoImage or NULL on error.
1623 * The caller holds a temporary reference to the returned image which should be cleared
1624 * when no longer needed by calling mono_image_close ().
1625 * if NULL, then check the value of @status for details on the error
1628 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1630 return mono_image_open_full (fname, status, FALSE);
1634 * mono_pe_file_open:
1635 * @fname: filename that points to the module we want to open
1636 * @status: An error condition is returned in this field
1638 * Returns: An open image of type %MonoImage or NULL on error. if
1639 * NULL, then check the value of @status for details on the error.
1640 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1641 * It's just a PE file loader, used for FileVersionInfo. It also does
1642 * not use the image cache.
1645 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1647 g_return_val_if_fail (fname != NULL, NULL);
1649 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1653 * mono_image_open_raw
1654 * @fname: filename that points to the module we want to open
1655 * @status: An error condition is returned in this field
1657 * Returns an image without loading neither pe or cli data.
1659 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1662 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1664 g_return_val_if_fail (fname != NULL, NULL);
1666 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1670 * mono_image_open_metadata_only:
1672 * Open an image which contains metadata only without a PE header.
1675 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1677 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1681 mono_image_fixup_vtable (MonoImage *image)
1684 MonoCLIImageInfo *iinfo;
1686 MonoVTableFixup *vtfixup;
1692 g_assert (image->is_module_handle);
1694 iinfo = image->image_info;
1695 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1696 if (!de->rva || !de->size)
1698 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1702 count = de->size / sizeof (MonoVTableFixup);
1704 if (!vtfixup->rva || !vtfixup->count)
1707 slot = mono_image_rva_map (image, vtfixup->rva);
1709 slot_type = vtfixup->type;
1710 slot_count = vtfixup->count;
1711 if (slot_type & VTFIXUP_TYPE_32BIT)
1712 while (slot_count--) {
1713 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1714 slot = ((guint32*) slot) + 1;
1716 else if (slot_type & VTFIXUP_TYPE_64BIT)
1717 while (slot_count--) {
1718 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1719 slot = ((guint32*) slot) + 1;
1722 g_assert_not_reached();
1727 g_assert_not_reached();
1732 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1734 g_hash_table_destroy ((GHashTable*)val);
1739 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1741 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1746 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1748 g_slist_free ((GSList*)val);
1752 * mono_image_addref:
1753 * @image: The image file we wish to add a reference to
1755 * Increases the reference count of an image.
1758 mono_image_addref (MonoImage *image)
1760 InterlockedIncrement (&image->ref_count);
1764 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1766 stream->alloc_size = stream->index = stream->offset = 0;
1767 g_free (stream->data);
1768 stream->data = NULL;
1770 g_hash_table_destroy (stream->hash);
1771 stream->hash = NULL;
1776 free_hash (GHashTable *hash)
1779 g_hash_table_destroy (hash);
1783 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1785 free_hash (cache->delegate_invoke_cache);
1786 free_hash (cache->delegate_begin_invoke_cache);
1787 free_hash (cache->delegate_end_invoke_cache);
1788 free_hash (cache->runtime_invoke_cache);
1789 free_hash (cache->runtime_invoke_vtype_cache);
1791 free_hash (cache->delegate_abstract_invoke_cache);
1793 free_hash (cache->runtime_invoke_direct_cache);
1794 free_hash (cache->managed_wrapper_cache);
1796 free_hash (cache->native_wrapper_cache);
1797 free_hash (cache->native_wrapper_aot_cache);
1798 free_hash (cache->native_wrapper_check_cache);
1799 free_hash (cache->native_wrapper_aot_check_cache);
1801 free_hash (cache->native_func_wrapper_aot_cache);
1802 free_hash (cache->remoting_invoke_cache);
1803 free_hash (cache->synchronized_cache);
1804 free_hash (cache->unbox_wrapper_cache);
1805 free_hash (cache->cominterop_invoke_cache);
1806 free_hash (cache->cominterop_wrapper_cache);
1807 free_hash (cache->thunk_invoke_cache);
1811 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1813 for (int i = 0; i < image_count; ++i) {
1815 if (!mono_image_close_except_pools (images [i]))
1822 * Returns whether mono_image_close_finish() must be called as well.
1823 * We must unload images in two steps because clearing the domain in
1824 * SGen requires the class metadata to be intact, but we need to free
1825 * the mono_g_hash_tables in case a collection occurs during domain
1826 * unloading and the roots would trip up the GC.
1829 mono_image_close_except_pools (MonoImage *image)
1832 GHashTable *loaded_images, *loaded_images_by_name;
1835 g_return_val_if_fail (image != NULL, FALSE);
1838 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1839 * register_image () can't grab an image which is being closed.
1841 mono_images_lock ();
1843 if (InterlockedDecrement (&image->ref_count) > 0) {
1844 mono_images_unlock ();
1848 loaded_images = get_loaded_images_hash (image->ref_only);
1849 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1850 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1851 if (image == image2) {
1852 /* This is not true if we are called from mono_image_open () */
1853 g_hash_table_remove (loaded_images, image->name);
1855 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1856 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1858 mono_images_unlock ();
1861 if (image->is_module_handle && image->has_entry_point) {
1862 mono_images_lock ();
1863 if (image->ref_count == 0) {
1864 /* Image will be closed by _CorDllMain. */
1865 FreeLibrary ((HMODULE) image->raw_data);
1866 mono_images_unlock ();
1869 mono_images_unlock ();
1873 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1875 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1877 mono_image_invoke_unload_hook (image);
1879 mono_metadata_clean_for_image (image);
1882 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1883 * assemblies, so we can't release these references in mono_assembly_close () since the
1884 * MonoImage might outlive its associated MonoAssembly.
1886 if (image->references && !image_is_dynamic (image)) {
1887 for (i = 0; i < image->nreferences; i++) {
1888 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1889 if (!mono_assembly_close_except_image_pools (image->references [i]))
1890 image->references [i] = NULL;
1894 if (image->references) {
1895 g_free (image->references);
1896 image->references = NULL;
1901 mono_images_lock ();
1902 if (image->is_module_handle && !image->has_entry_point)
1903 FreeLibrary ((HMODULE) image->raw_data);
1904 mono_images_unlock ();
1907 if (image->raw_buffer_used) {
1908 if (image->raw_data != NULL) {
1910 if (image->fileio_used)
1911 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1914 mono_file_unmap (image->raw_data, image->raw_data_handle);
1918 if (image->raw_data_allocated) {
1919 /* FIXME: do we need this? (image is disposed anyway) */
1920 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1921 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1923 if ((image->raw_metadata > image->raw_data) &&
1924 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1925 image->raw_metadata = NULL;
1927 for (i = 0; i < ii->cli_section_count; i++)
1928 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1929 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1930 ii->cli_sections [i] = NULL;
1932 g_free (image->raw_data);
1935 if (debug_assembly_unload) {
1936 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1938 g_free (image->name);
1939 g_free (image->guid);
1940 g_free (image->version);
1943 if (image->method_cache)
1944 g_hash_table_destroy (image->method_cache);
1945 if (image->methodref_cache)
1946 g_hash_table_destroy (image->methodref_cache);
1947 mono_internal_hash_table_destroy (&image->class_cache);
1948 mono_conc_hashtable_destroy (image->field_cache);
1949 if (image->array_cache) {
1950 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1951 g_hash_table_destroy (image->array_cache);
1953 if (image->szarray_cache)
1954 g_hash_table_destroy (image->szarray_cache);
1955 if (image->ptr_cache)
1956 g_hash_table_destroy (image->ptr_cache);
1957 if (image->name_cache) {
1958 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1959 g_hash_table_destroy (image->name_cache);
1962 free_hash (image->delegate_bound_static_invoke_cache);
1963 free_hash (image->runtime_invoke_vcall_cache);
1964 free_hash (image->ldfld_wrapper_cache);
1965 free_hash (image->ldflda_wrapper_cache);
1966 free_hash (image->stfld_wrapper_cache);
1967 free_hash (image->isinst_cache);
1968 free_hash (image->castclass_cache);
1969 free_hash (image->icall_wrapper_cache);
1970 free_hash (image->proxy_isinst_cache);
1971 free_hash (image->var_cache_slow);
1972 free_hash (image->mvar_cache_slow);
1973 free_hash (image->var_cache_constrained);
1974 free_hash (image->mvar_cache_constrained);
1975 free_hash (image->wrapper_param_names);
1976 free_hash (image->pinvoke_scopes);
1977 free_hash (image->pinvoke_scope_filenames);
1978 free_hash (image->native_func_wrapper_cache);
1979 free_hash (image->typespec_cache);
1981 mono_wrapper_caches_free (&image->wrapper_caches);
1983 for (i = 0; i < image->gshared_types_len; ++i)
1984 free_hash (image->gshared_types [i]);
1985 g_free (image->gshared_types);
1987 /* The ownership of signatures is not well defined */
1988 g_hash_table_destroy (image->memberref_signatures);
1989 g_hash_table_destroy (image->helper_signatures);
1990 g_hash_table_destroy (image->method_signatures);
1992 if (image->rgctx_template_hash)
1993 g_hash_table_destroy (image->rgctx_template_hash);
1995 if (image->property_hash)
1996 mono_property_hash_destroy (image->property_hash);
1999 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2000 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2002 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2003 image->reflection_info_unregister_classes = NULL;
2005 if (image->interface_bitset) {
2006 mono_unload_interface_ids (image->interface_bitset);
2007 mono_bitset_free (image->interface_bitset);
2009 if (image->image_info){
2010 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2012 if (ii->cli_section_tables)
2013 g_free (ii->cli_section_tables);
2014 if (ii->cli_sections)
2015 g_free (ii->cli_sections);
2016 g_free (image->image_info);
2019 mono_image_close_except_pools_all (image->files, image->file_count);
2020 mono_image_close_except_pools_all (image->modules, image->module_count);
2021 if (image->modules_loaded)
2022 g_free (image->modules_loaded);
2024 mono_os_mutex_destroy (&image->szarray_cache_lock);
2025 mono_os_mutex_destroy (&image->lock);
2027 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2028 if (image_is_dynamic (image)) {
2029 /* Dynamic images are GC_MALLOCed */
2030 g_free ((char*)image->module_name);
2031 mono_dynamic_image_free ((MonoDynamicImage*)image);
2034 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2040 mono_image_close_all (MonoImage**images, int image_count)
2042 for (int i = 0; i < image_count; ++i) {
2044 mono_image_close_finish (images [i]);
2051 mono_image_close_finish (MonoImage *image)
2055 if (image->references && !image_is_dynamic (image)) {
2056 for (i = 0; i < image->nreferences; i++) {
2057 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2058 mono_assembly_close_finish (image->references [i]);
2061 g_free (image->references);
2062 image->references = NULL;
2065 mono_image_close_all (image->files, image->file_count);
2066 mono_image_close_all (image->modules, image->module_count);
2068 #ifndef DISABLE_PERFCOUNTERS
2069 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2072 if (!image_is_dynamic (image)) {
2073 if (debug_assembly_unload)
2074 mono_mempool_invalidate (image->mempool);
2076 mono_mempool_destroy (image->mempool);
2080 if (debug_assembly_unload)
2081 mono_mempool_invalidate (image->mempool);
2083 mono_mempool_destroy (image->mempool);
2084 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2091 * @image: The image file we wish to close
2093 * Closes an image file, deallocates all memory consumed and
2094 * unmaps all possible sections of the file
2097 mono_image_close (MonoImage *image)
2099 if (mono_image_close_except_pools (image))
2100 mono_image_close_finish (image);
2104 * mono_image_strerror:
2105 * @status: an code indicating the result from a recent operation
2107 * Returns: a string describing the error
2110 mono_image_strerror (MonoImageOpenStatus status)
2115 case MONO_IMAGE_ERROR_ERRNO:
2116 return strerror (errno);
2117 case MONO_IMAGE_IMAGE_INVALID:
2118 return "File does not contain a valid CIL image";
2119 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2120 return "An assembly was referenced, but could not be found";
2122 return "Internal error";
2126 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2127 guint32 lang_id, gunichar2 *name,
2128 MonoPEResourceDirEntry *entry,
2129 MonoPEResourceDir *root, guint32 level)
2131 gboolean is_string, is_dir;
2132 guint32 name_offset, dir_offset;
2134 /* Level 0 holds a directory entry for each type of resource
2135 * (identified by ID or name).
2137 * Level 1 holds a directory entry for each named resource
2138 * item, and each "anonymous" item of a particular type of
2141 * Level 2 holds a directory entry for each language pointing to
2144 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2145 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2147 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2148 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2153 } else if (level==1) {
2154 if (res_id != name_offset)
2158 is_string==TRUE && name!=lookup (name_offset)) {
2162 } else if (level==2) {
2163 if (is_string || (lang_id != 0 && name_offset != lang_id))
2166 g_assert_not_reached ();
2170 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2171 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2174 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2176 for(i=0; i<entries; i++) {
2177 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2180 ret=mono_image_walk_resource_tree (info, res_id,
2191 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2192 MonoPEResourceDataEntry *res;
2194 res = g_new0 (MonoPEResourceDataEntry, 1);
2196 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2197 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2198 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2199 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2206 * mono_image_lookup_resource:
2207 * @image: the image to look up the resource in
2208 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2209 * @lang_id: The language id.
2210 * @name: the resource name to lookup.
2212 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2213 * of the given resource. The caller should free it using g_free () when no longer
2217 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2219 MonoCLIImageInfo *info;
2220 MonoDotNetHeader *header;
2221 MonoPEDatadir *datadir;
2222 MonoPEDirEntry *rsrc;
2223 MonoPEResourceDir *resource_dir;
2224 MonoPEResourceDirEntry *res_entries;
2231 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2233 info = (MonoCLIImageInfo *)image->image_info;
2238 header=&info->cli_header;
2243 datadir=&header->datadir;
2248 rsrc=&datadir->pe_resource_table;
2253 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2254 if(resource_dir==NULL) {
2258 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2259 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2261 for(i=0; i<entries; i++) {
2262 MonoPEResourceDirEntry *entry=&res_entries[i];
2265 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2266 name, entry, resource_dir,
2277 * mono_image_get_entry_point:
2278 * @image: the image where the entry point will be looked up.
2280 * Use this routine to determine the metadata token for method that
2281 * has been flagged as the entry point.
2283 * Returns: the token for the entry point method in the image
2286 mono_image_get_entry_point (MonoImage *image)
2288 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2292 * mono_image_get_resource:
2293 * @image: the image where the resource will be looked up.
2294 * @offset: The offset to add to the resource
2295 * @size: a pointer to an int where the size of the resource will be stored
2297 * This is a low-level routine that fetches a resource from the
2298 * metadata that starts at a given @offset. The @size parameter is
2299 * filled with the data field as encoded in the metadata.
2301 * Returns: the pointer to the resource whose offset is @offset.
2304 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2306 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2307 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2310 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2313 data = mono_image_rva_map (image, ch->ch_resources.rva);
2318 *size = read32 (data);
2323 // Returning NULL with no error set will be interpeted as "not found"
2325 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2327 char *base_dir, *name;
2329 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2333 mono_error_init (error);
2335 if (fileidx < 1 || fileidx > t->rows)
2338 mono_image_lock (image);
2339 if (image->files && image->files [fileidx - 1]) {
2340 mono_image_unlock (image);
2341 return image->files [fileidx - 1];
2343 mono_image_unlock (image);
2345 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2346 fname = mono_metadata_string_heap (image, fname_id);
2347 base_dir = g_path_get_dirname (image->name);
2348 name = g_build_filename (base_dir, fname, NULL);
2349 res = mono_image_open (name, NULL);
2353 mono_image_lock (image);
2354 if (image->files && image->files [fileidx - 1]) {
2355 MonoImage *old = res;
2356 res = image->files [fileidx - 1];
2357 mono_image_unlock (image);
2358 mono_image_close (old);
2361 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2362 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2363 mono_image_unlock (image);
2364 mono_image_close (res);
2368 for (i = 0; i < res->module_count; ++i) {
2369 if (res->modules [i] && !res->modules [i]->assembly)
2370 res->modules [i]->assembly = image->assembly;
2373 if (!image->files) {
2374 image->files = g_new0 (MonoImage*, t->rows);
2375 image->file_count = t->rows;
2377 image->files [fileidx - 1] = res;
2378 mono_image_unlock (image);
2379 /* vtable fixup can't happen with the image lock held */
2381 if (res->is_module_handle)
2382 mono_image_fixup_vtable (res);
2393 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2396 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2397 mono_error_assert_ok (&error);
2402 * mono_image_get_strong_name:
2403 * @image: a MonoImage
2404 * @size: a guint32 pointer, or NULL.
2406 * If the image has a strong name, and @size is not NULL, the value
2407 * pointed to by size will have the size of the strong name.
2409 * Returns: NULL if the image does not have a strong name, or a
2410 * pointer to the public key.
2413 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2415 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2416 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2419 if (!de->size || !de->rva)
2421 data = mono_image_rva_map (image, de->rva);
2430 * mono_image_strong_name_position:
2431 * @image: a MonoImage
2432 * @size: a guint32 pointer, or NULL.
2434 * If the image has a strong name, and @size is not NULL, the value
2435 * pointed to by size will have the size of the strong name.
2437 * Returns: the position within the image file where the strong name
2441 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2443 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2444 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2449 if (!de->size || !de->rva)
2451 pos = mono_cli_rva_image_map (image, de->rva);
2452 return pos == INVALID_ADDRESS ? 0 : pos;
2456 * mono_image_get_public_key:
2457 * @image: a MonoImage
2458 * @size: a guint32 pointer, or NULL.
2460 * This is used to obtain the public key in the @image.
2462 * If the image has a public key, and @size is not NULL, the value
2463 * pointed to by size will have the size of the public key.
2465 * Returns: NULL if the image does not have a public key, or a pointer
2466 * to the public key.
2469 mono_image_get_public_key (MonoImage *image, guint32 *size)
2474 if (image_is_dynamic (image)) {
2476 *size = ((MonoDynamicImage*)image)->public_key_len;
2477 return (char*)((MonoDynamicImage*)image)->public_key;
2479 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2481 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2484 pubkey = mono_metadata_blob_heap (image, tok);
2485 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2492 * mono_image_get_name:
2493 * @name: a MonoImage
2495 * Returns: the name of the assembly.
2498 mono_image_get_name (MonoImage *image)
2500 return image->assembly_name;
2504 * mono_image_get_filename:
2505 * @image: a MonoImage
2507 * Used to get the filename that hold the actual MonoImage
2509 * Returns: the filename.
2512 mono_image_get_filename (MonoImage *image)
2518 mono_image_get_guid (MonoImage *image)
2523 const MonoTableInfo*
2524 mono_image_get_table_info (MonoImage *image, int table_id)
2526 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2528 return &image->tables [table_id];
2532 mono_image_get_table_rows (MonoImage *image, int table_id)
2534 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2536 return image->tables [table_id].rows;
2540 mono_table_info_get_rows (const MonoTableInfo *table)
2546 * mono_image_get_assembly:
2547 * @image: the MonoImage.
2549 * Use this routine to get the assembly that owns this image.
2551 * Returns: the assembly that holds this image.
2554 mono_image_get_assembly (MonoImage *image)
2556 return image->assembly;
2560 * mono_image_is_dynamic:
2561 * @image: the MonoImage
2563 * Determines if the given image was created dynamically through the
2564 * System.Reflection.Emit API
2566 * Returns: TRUE if the image was created dynamically, FALSE if not.
2569 mono_image_is_dynamic (MonoImage *image)
2571 return image_is_dynamic (image);
2575 * mono_image_has_authenticode_entry:
2576 * @image: the MonoImage
2578 * Use this routine to determine if the image has a Authenticode
2579 * Certificate Table.
2581 * Returns: TRUE if the image contains an authenticode entry in the PE
2585 mono_image_has_authenticode_entry (MonoImage *image)
2587 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2588 MonoDotNetHeader *header = &iinfo->cli_header;
2591 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2592 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2593 return ((de->rva != 0) && (de->size > 8));
2597 mono_image_alloc (MonoImage *image, guint size)
2601 #ifndef DISABLE_PERFCOUNTERS
2602 mono_perfcounters->loader_bytes += size;
2604 mono_image_lock (image);
2605 res = mono_mempool_alloc (image->mempool, size);
2606 mono_image_unlock (image);
2612 mono_image_alloc0 (MonoImage *image, guint size)
2616 #ifndef DISABLE_PERFCOUNTERS
2617 mono_perfcounters->loader_bytes += size;
2619 mono_image_lock (image);
2620 res = mono_mempool_alloc0 (image->mempool, size);
2621 mono_image_unlock (image);
2627 mono_image_strdup (MonoImage *image, const char *s)
2631 #ifndef DISABLE_PERFCOUNTERS
2632 mono_perfcounters->loader_bytes += strlen (s);
2634 mono_image_lock (image);
2635 res = mono_mempool_strdup (image->mempool, s);
2636 mono_image_unlock (image);
2642 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2645 mono_image_lock (image);
2646 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2647 mono_image_unlock (image);
2648 #ifndef DISABLE_PERFCOUNTERS
2649 mono_perfcounters->loader_bytes += strlen (buf);
2655 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2660 va_start (args, format);
2661 buf = mono_image_strdup_vprintf (image, format, args);
2667 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2671 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2672 new_list->data = data;
2673 new_list->prev = list ? list->prev : NULL;
2674 new_list->next = list;
2677 new_list->prev->next = new_list;
2679 list->prev = new_list;
2685 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2689 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2690 new_list->data = data;
2691 new_list->next = NULL;
2693 return g_slist_concat (list, new_list);
2697 mono_image_lock (MonoImage *image)
2699 mono_locks_os_acquire (&image->lock, ImageDataLock);
2703 mono_image_unlock (MonoImage *image)
2705 mono_locks_os_release (&image->lock, ImageDataLock);
2710 * mono_image_property_lookup:
2712 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2714 * LOCKING: Takes the image lock
2717 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2721 mono_image_lock (image);
2722 res = mono_property_hash_lookup (image->property_hash, subject, property);
2723 mono_image_unlock (image);
2729 * mono_image_property_insert:
2731 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2733 * LOCKING: Takes the image lock
2736 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2738 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2739 mono_image_lock (image);
2740 mono_property_hash_insert (image->property_hash, subject, property, value);
2741 mono_image_unlock (image);
2745 * mono_image_property_remove:
2747 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2749 * LOCKING: Takes the image lock
2752 mono_image_property_remove (MonoImage *image, gpointer subject)
2754 mono_image_lock (image);
2755 mono_property_hash_remove_object (image->property_hash, subject);
2756 mono_image_unlock (image);
2760 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2762 MonoImage *image = klass->image;
2763 g_assert (image_is_dynamic (image));
2764 mono_image_lock (image);
2765 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2766 mono_image_unlock (image);
2769 // This is support for the mempool reference tracking feature in checked-build, but lives in image.c due to use of static variables of this file.
2772 * mono_find_image_owner:
2774 * Find the image, if any, which a given pointer is located in the memory of.
2777 mono_find_image_owner (void *ptr)
2779 mono_images_lock ();
2781 MonoImage *owner = NULL;
2783 // Iterate over both by-path image hashes
2784 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2786 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2788 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2789 GHashTableIter iter;
2792 // Iterate over images within a hash
2793 g_hash_table_iter_init (&iter, target);
2794 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2796 mono_image_lock (image);
2797 if (mono_mempool_contains_addr (image->mempool, ptr))
2799 mono_image_unlock (image);
2803 mono_images_unlock ();