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 } IgnoredAssemblyNames;
1106 const char guid [40];
1109 const char *ignored_assemblies_names[] = {
1110 "System.Runtime.InteropServices.RuntimeInformation.dll",
1111 "System.Globalization.Extensions.dll",
1112 "System.IO.Compression.dll",
1113 "System.Net.Http.dll",
1114 "System.Text.Encoding.CodePages.dll",
1115 "System.Reflection.DispatchProxy.dll",
1118 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1120 static const IgnoredAssembly ignored_assemblies [] = {
1121 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1122 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1123 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1124 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1125 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
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 (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1130 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1131 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1132 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1133 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1134 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1135 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1140 static void Main () {
1143 for (int i = 0; i < str.Length; ++i)
1144 h = ((h << 5) + h) ^ str[i];
1146 Console.WriteLine ("{0:X}", h);
1150 hash_guid (const char *str)
1154 h = ((h << 5) + h) ^ *str;
1162 is_problematic_image (MonoImage *image)
1164 int h = hash_guid (image->guid);
1166 //TODO make this more cache effiecient.
1167 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1168 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1169 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1170 const char *needle = ignored_assemblies_names [ignored_assemblies [i].assembly_name];
1171 size_t needle_len = strlen (needle);
1172 size_t asm_len = strlen (image->name);
1173 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1181 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1182 gboolean care_about_cli, gboolean care_about_pecoff)
1184 MonoCLIImageInfo *iinfo;
1185 MonoDotNetHeader *header;
1186 GSList *errors = NULL;
1189 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1191 mono_image_init (image);
1193 iinfo = (MonoCLIImageInfo *)image->image_info;
1194 header = &iinfo->cli_header;
1196 if (!image->metadata_only) {
1197 for (l = image_loaders; l; l = l->next) {
1198 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1199 if (loader->match (image)) {
1200 image->loader = loader;
1204 if (!image->loader) {
1206 *status = MONO_IMAGE_IMAGE_INVALID;
1211 *status = MONO_IMAGE_IMAGE_INVALID;
1213 if (care_about_pecoff == FALSE)
1216 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1219 if (!mono_image_load_pe_data (image))
1222 image->loader = (MonoImageLoader*)&pe_loader;
1225 if (care_about_cli == FALSE) {
1229 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1232 if (!mono_image_load_cli_data (image))
1235 if (!image->ref_only && is_problematic_image (image)) {
1236 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1237 *status = MONO_IMAGE_IMAGE_INVALID;
1241 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1244 mono_image_load_names (image);
1246 load_modules (image);
1249 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1251 *status = MONO_IMAGE_OK;
1257 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1258 g_warning ("Could not load image %s due to %s", image->name, info->message);
1259 mono_free_verify_list (errors);
1261 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1262 mono_image_close (image);
1267 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1268 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1270 MonoCLIImageInfo *iinfo;
1274 if ((filed = mono_file_map_open (fname)) == NULL){
1275 if (IS_PORTABILITY_SET) {
1276 gchar *ffname = mono_portability_find_file (fname, TRUE);
1278 filed = mono_file_map_open (ffname);
1283 if (filed == NULL) {
1285 *status = MONO_IMAGE_ERROR_ERRNO;
1290 image = g_new0 (MonoImage, 1);
1291 image->raw_buffer_used = TRUE;
1292 image->raw_data_len = mono_file_map_size (filed);
1293 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);
1294 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1295 if (!image->raw_data) {
1296 image->fileio_used = TRUE;
1297 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);
1300 if (!image->raw_data) {
1301 mono_file_map_close (filed);
1304 *status = MONO_IMAGE_IMAGE_INVALID;
1307 iinfo = g_new0 (MonoCLIImageInfo, 1);
1308 image->image_info = iinfo;
1309 image->name = mono_path_resolve_symlinks (fname);
1310 image->ref_only = refonly;
1311 image->metadata_only = metadata_only;
1312 image->ref_count = 1;
1313 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1314 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1316 mono_file_map_close (filed);
1317 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1321 * mono_image_loaded:
1322 * @name: path or assembly name of the image to load
1323 * @refonly: Check with respect to reflection-only loads?
1325 * This routine verifies that the given image is loaded.
1326 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1328 * Returns: the loaded MonoImage, or NULL on failure.
1331 mono_image_loaded_full (const char *name, gboolean refonly)
1335 mono_images_lock ();
1336 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1338 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1339 mono_images_unlock ();
1345 * mono_image_loaded:
1346 * @name: path or assembly name of the image to load
1348 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1350 * Returns: the loaded MonoImage, or NULL on failure.
1353 mono_image_loaded (const char *name)
1355 return mono_image_loaded_full (name, FALSE);
1364 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1366 GuidData *data = (GuidData *)user_data;
1371 image = (MonoImage *)val;
1372 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1377 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1380 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1384 mono_images_lock ();
1385 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1386 mono_images_unlock ();
1391 mono_image_loaded_by_guid (const char *guid)
1393 return mono_image_loaded_by_guid_full (guid, FALSE);
1397 register_image (MonoImage *image)
1400 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1402 mono_images_lock ();
1403 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1406 /* Somebody else beat us to it */
1407 mono_image_addref (image2);
1408 mono_images_unlock ();
1409 mono_image_close (image);
1413 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1414 g_hash_table_insert (loaded_images, image->name, image);
1415 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1416 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1417 mono_images_unlock ();
1423 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1425 MonoCLIImageInfo *iinfo;
1429 if (!data || !data_len) {
1431 *status = MONO_IMAGE_IMAGE_INVALID;
1436 datac = (char *)g_try_malloc (data_len);
1439 *status = MONO_IMAGE_ERROR_ERRNO;
1442 memcpy (datac, data, data_len);
1445 image = g_new0 (MonoImage, 1);
1446 image->raw_data = datac;
1447 image->raw_data_len = data_len;
1448 image->raw_data_allocated = need_copy;
1449 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1450 iinfo = g_new0 (MonoCLIImageInfo, 1);
1451 image->image_info = iinfo;
1452 image->ref_only = refonly;
1453 image->metadata_only = metadata_only;
1454 image->ref_count = 1;
1456 image = do_mono_image_load (image, status, TRUE, TRUE);
1460 return register_image (image);
1464 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1466 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1470 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1472 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1476 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1478 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1482 /* fname is not duplicated. */
1484 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1487 MonoCLIImageInfo* iinfo;
1489 image = g_new0 (MonoImage, 1);
1490 image->raw_data = (char*) module_handle;
1491 image->is_module_handle = TRUE;
1492 iinfo = g_new0 (MonoCLIImageInfo, 1);
1493 image->image_info = iinfo;
1494 image->name = fname;
1495 image->ref_count = has_entry_point ? 0 : 1;
1496 image->has_entry_point = has_entry_point;
1498 image = do_mono_image_load (image, status, TRUE, TRUE);
1502 return register_image (image);
1507 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1510 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1513 g_return_val_if_fail (fname != NULL, NULL);
1516 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1517 // then assemblies need to be loaded with LoadLibrary:
1518 if (!refonly && coree_module_handle) {
1519 HMODULE module_handle;
1520 guint16 *fname_utf16;
1523 absfname = mono_path_resolve_symlinks (fname);
1526 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1527 mono_images_lock ();
1528 image = g_hash_table_lookup (loaded_images, absfname);
1529 if (image) { // Image already loaded
1530 g_assert (image->is_module_handle);
1531 if (image->has_entry_point && image->ref_count == 0) {
1532 /* Increment reference count on images loaded outside of the runtime. */
1533 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1534 /* The image is already loaded because _CorDllMain removes images from the hash. */
1535 module_handle = LoadLibrary (fname_utf16);
1536 g_assert (module_handle == (HMODULE) image->raw_data);
1538 mono_image_addref (image);
1539 mono_images_unlock ();
1541 g_free (fname_utf16);
1546 // Image not loaded, load it now
1547 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1548 module_handle = MonoLoadImage (fname_utf16);
1549 if (status && module_handle == NULL)
1550 last_error = mono_w32error_get_last ();
1552 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1553 image = g_hash_table_lookup (loaded_images, absfname);
1555 mono_image_addref (image);
1556 mono_images_unlock ();
1558 g_free (fname_utf16);
1560 if (module_handle == NULL) {
1564 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1565 *status = MONO_IMAGE_IMAGE_INVALID;
1567 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1577 g_assert (image->is_module_handle);
1578 g_assert (image->has_entry_point);
1583 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1587 absfname = mono_path_canonicalize (fname);
1590 * The easiest solution would be to do all the loading inside the mutex,
1591 * but that would lead to scalability problems. So we let the loading
1592 * happen outside the mutex, and if multiple threads happen to load
1593 * the same image, we discard all but the first copy.
1595 mono_images_lock ();
1596 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1599 if (image) { // Image already loaded
1600 mono_image_addref (image);
1601 mono_images_unlock ();
1604 mono_images_unlock ();
1606 // Image not loaded, load it now
1607 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1611 return register_image (image);
1616 * @fname: filename that points to the module we want to open
1617 * @status: An error condition is returned in this field
1619 * Returns: An open image of type %MonoImage or NULL on error.
1620 * The caller holds a temporary reference to the returned image which should be cleared
1621 * when no longer needed by calling mono_image_close ().
1622 * if NULL, then check the value of @status for details on the error
1625 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1627 return mono_image_open_full (fname, status, FALSE);
1631 * mono_pe_file_open:
1632 * @fname: filename that points to the module we want to open
1633 * @status: An error condition is returned in this field
1635 * Returns: An open image of type %MonoImage or NULL on error. if
1636 * NULL, then check the value of @status for details on the error.
1637 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1638 * It's just a PE file loader, used for FileVersionInfo. It also does
1639 * not use the image cache.
1642 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1644 g_return_val_if_fail (fname != NULL, NULL);
1646 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1650 * mono_image_open_raw
1651 * @fname: filename that points to the module we want to open
1652 * @status: An error condition is returned in this field
1654 * Returns an image without loading neither pe or cli data.
1656 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1659 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1661 g_return_val_if_fail (fname != NULL, NULL);
1663 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1667 * mono_image_open_metadata_only:
1669 * Open an image which contains metadata only without a PE header.
1672 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1674 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1678 mono_image_fixup_vtable (MonoImage *image)
1681 MonoCLIImageInfo *iinfo;
1683 MonoVTableFixup *vtfixup;
1689 g_assert (image->is_module_handle);
1691 iinfo = image->image_info;
1692 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1693 if (!de->rva || !de->size)
1695 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1699 count = de->size / sizeof (MonoVTableFixup);
1701 if (!vtfixup->rva || !vtfixup->count)
1704 slot = mono_image_rva_map (image, vtfixup->rva);
1706 slot_type = vtfixup->type;
1707 slot_count = vtfixup->count;
1708 if (slot_type & VTFIXUP_TYPE_32BIT)
1709 while (slot_count--) {
1710 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1711 slot = ((guint32*) slot) + 1;
1713 else if (slot_type & VTFIXUP_TYPE_64BIT)
1714 while (slot_count--) {
1715 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1716 slot = ((guint32*) slot) + 1;
1719 g_assert_not_reached();
1724 g_assert_not_reached();
1729 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1731 g_hash_table_destroy ((GHashTable*)val);
1736 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1738 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1743 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1745 g_slist_free ((GSList*)val);
1749 * mono_image_addref:
1750 * @image: The image file we wish to add a reference to
1752 * Increases the reference count of an image.
1755 mono_image_addref (MonoImage *image)
1757 InterlockedIncrement (&image->ref_count);
1761 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1763 stream->alloc_size = stream->index = stream->offset = 0;
1764 g_free (stream->data);
1765 stream->data = NULL;
1767 g_hash_table_destroy (stream->hash);
1768 stream->hash = NULL;
1773 free_hash (GHashTable *hash)
1776 g_hash_table_destroy (hash);
1780 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1782 free_hash (cache->delegate_invoke_cache);
1783 free_hash (cache->delegate_begin_invoke_cache);
1784 free_hash (cache->delegate_end_invoke_cache);
1785 free_hash (cache->runtime_invoke_cache);
1786 free_hash (cache->runtime_invoke_vtype_cache);
1788 free_hash (cache->delegate_abstract_invoke_cache);
1790 free_hash (cache->runtime_invoke_direct_cache);
1791 free_hash (cache->managed_wrapper_cache);
1793 free_hash (cache->native_wrapper_cache);
1794 free_hash (cache->native_wrapper_aot_cache);
1795 free_hash (cache->native_wrapper_check_cache);
1796 free_hash (cache->native_wrapper_aot_check_cache);
1798 free_hash (cache->native_func_wrapper_aot_cache);
1799 free_hash (cache->remoting_invoke_cache);
1800 free_hash (cache->synchronized_cache);
1801 free_hash (cache->unbox_wrapper_cache);
1802 free_hash (cache->cominterop_invoke_cache);
1803 free_hash (cache->cominterop_wrapper_cache);
1804 free_hash (cache->thunk_invoke_cache);
1808 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1810 for (int i = 0; i < image_count; ++i) {
1812 if (!mono_image_close_except_pools (images [i]))
1819 * Returns whether mono_image_close_finish() must be called as well.
1820 * We must unload images in two steps because clearing the domain in
1821 * SGen requires the class metadata to be intact, but we need to free
1822 * the mono_g_hash_tables in case a collection occurs during domain
1823 * unloading and the roots would trip up the GC.
1826 mono_image_close_except_pools (MonoImage *image)
1829 GHashTable *loaded_images, *loaded_images_by_name;
1832 g_return_val_if_fail (image != NULL, FALSE);
1835 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1836 * register_image () can't grab an image which is being closed.
1838 mono_images_lock ();
1840 if (InterlockedDecrement (&image->ref_count) > 0) {
1841 mono_images_unlock ();
1845 loaded_images = get_loaded_images_hash (image->ref_only);
1846 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1847 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1848 if (image == image2) {
1849 /* This is not true if we are called from mono_image_open () */
1850 g_hash_table_remove (loaded_images, image->name);
1852 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1853 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1855 mono_images_unlock ();
1858 if (image->is_module_handle && image->has_entry_point) {
1859 mono_images_lock ();
1860 if (image->ref_count == 0) {
1861 /* Image will be closed by _CorDllMain. */
1862 FreeLibrary ((HMODULE) image->raw_data);
1863 mono_images_unlock ();
1866 mono_images_unlock ();
1870 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1872 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1874 mono_image_invoke_unload_hook (image);
1876 mono_metadata_clean_for_image (image);
1879 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1880 * assemblies, so we can't release these references in mono_assembly_close () since the
1881 * MonoImage might outlive its associated MonoAssembly.
1883 if (image->references && !image_is_dynamic (image)) {
1884 for (i = 0; i < image->nreferences; i++) {
1885 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1886 if (!mono_assembly_close_except_image_pools (image->references [i]))
1887 image->references [i] = NULL;
1891 if (image->references) {
1892 g_free (image->references);
1893 image->references = NULL;
1898 mono_images_lock ();
1899 if (image->is_module_handle && !image->has_entry_point)
1900 FreeLibrary ((HMODULE) image->raw_data);
1901 mono_images_unlock ();
1904 if (image->raw_buffer_used) {
1905 if (image->raw_data != NULL) {
1907 if (image->fileio_used)
1908 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1911 mono_file_unmap (image->raw_data, image->raw_data_handle);
1915 if (image->raw_data_allocated) {
1916 /* FIXME: do we need this? (image is disposed anyway) */
1917 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1918 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1920 if ((image->raw_metadata > image->raw_data) &&
1921 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1922 image->raw_metadata = NULL;
1924 for (i = 0; i < ii->cli_section_count; i++)
1925 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1926 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1927 ii->cli_sections [i] = NULL;
1929 g_free (image->raw_data);
1932 if (debug_assembly_unload) {
1933 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1935 g_free (image->name);
1936 g_free (image->guid);
1937 g_free (image->version);
1940 if (image->method_cache)
1941 g_hash_table_destroy (image->method_cache);
1942 if (image->methodref_cache)
1943 g_hash_table_destroy (image->methodref_cache);
1944 mono_internal_hash_table_destroy (&image->class_cache);
1945 mono_conc_hashtable_destroy (image->field_cache);
1946 if (image->array_cache) {
1947 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1948 g_hash_table_destroy (image->array_cache);
1950 if (image->szarray_cache)
1951 g_hash_table_destroy (image->szarray_cache);
1952 if (image->ptr_cache)
1953 g_hash_table_destroy (image->ptr_cache);
1954 if (image->name_cache) {
1955 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1956 g_hash_table_destroy (image->name_cache);
1959 free_hash (image->delegate_bound_static_invoke_cache);
1960 free_hash (image->runtime_invoke_vcall_cache);
1961 free_hash (image->ldfld_wrapper_cache);
1962 free_hash (image->ldflda_wrapper_cache);
1963 free_hash (image->stfld_wrapper_cache);
1964 free_hash (image->isinst_cache);
1965 free_hash (image->castclass_cache);
1966 free_hash (image->icall_wrapper_cache);
1967 free_hash (image->proxy_isinst_cache);
1968 free_hash (image->var_cache_slow);
1969 free_hash (image->mvar_cache_slow);
1970 free_hash (image->var_cache_constrained);
1971 free_hash (image->mvar_cache_constrained);
1972 free_hash (image->wrapper_param_names);
1973 free_hash (image->pinvoke_scopes);
1974 free_hash (image->pinvoke_scope_filenames);
1975 free_hash (image->native_func_wrapper_cache);
1976 free_hash (image->typespec_cache);
1978 mono_wrapper_caches_free (&image->wrapper_caches);
1980 for (i = 0; i < image->gshared_types_len; ++i)
1981 free_hash (image->gshared_types [i]);
1982 g_free (image->gshared_types);
1984 /* The ownership of signatures is not well defined */
1985 g_hash_table_destroy (image->memberref_signatures);
1986 g_hash_table_destroy (image->helper_signatures);
1987 g_hash_table_destroy (image->method_signatures);
1989 if (image->rgctx_template_hash)
1990 g_hash_table_destroy (image->rgctx_template_hash);
1992 if (image->property_hash)
1993 mono_property_hash_destroy (image->property_hash);
1996 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
1997 cleared during shutdown as we don't perform regular appdomain unload for the root one.
1999 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2000 image->reflection_info_unregister_classes = NULL;
2002 if (image->interface_bitset) {
2003 mono_unload_interface_ids (image->interface_bitset);
2004 mono_bitset_free (image->interface_bitset);
2006 if (image->image_info){
2007 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2009 if (ii->cli_section_tables)
2010 g_free (ii->cli_section_tables);
2011 if (ii->cli_sections)
2012 g_free (ii->cli_sections);
2013 g_free (image->image_info);
2016 mono_image_close_except_pools_all (image->files, image->file_count);
2017 mono_image_close_except_pools_all (image->modules, image->module_count);
2018 if (image->modules_loaded)
2019 g_free (image->modules_loaded);
2021 mono_os_mutex_destroy (&image->szarray_cache_lock);
2022 mono_os_mutex_destroy (&image->lock);
2024 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2025 if (image_is_dynamic (image)) {
2026 /* Dynamic images are GC_MALLOCed */
2027 g_free ((char*)image->module_name);
2028 mono_dynamic_image_free ((MonoDynamicImage*)image);
2031 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2037 mono_image_close_all (MonoImage**images, int image_count)
2039 for (int i = 0; i < image_count; ++i) {
2041 mono_image_close_finish (images [i]);
2048 mono_image_close_finish (MonoImage *image)
2052 if (image->references && !image_is_dynamic (image)) {
2053 for (i = 0; i < image->nreferences; i++) {
2054 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2055 mono_assembly_close_finish (image->references [i]);
2058 g_free (image->references);
2059 image->references = NULL;
2062 mono_image_close_all (image->files, image->file_count);
2063 mono_image_close_all (image->modules, image->module_count);
2065 #ifndef DISABLE_PERFCOUNTERS
2066 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2069 if (!image_is_dynamic (image)) {
2070 if (debug_assembly_unload)
2071 mono_mempool_invalidate (image->mempool);
2073 mono_mempool_destroy (image->mempool);
2077 if (debug_assembly_unload)
2078 mono_mempool_invalidate (image->mempool);
2080 mono_mempool_destroy (image->mempool);
2081 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2088 * @image: The image file we wish to close
2090 * Closes an image file, deallocates all memory consumed and
2091 * unmaps all possible sections of the file
2094 mono_image_close (MonoImage *image)
2096 if (mono_image_close_except_pools (image))
2097 mono_image_close_finish (image);
2101 * mono_image_strerror:
2102 * @status: an code indicating the result from a recent operation
2104 * Returns: a string describing the error
2107 mono_image_strerror (MonoImageOpenStatus status)
2112 case MONO_IMAGE_ERROR_ERRNO:
2113 return strerror (errno);
2114 case MONO_IMAGE_IMAGE_INVALID:
2115 return "File does not contain a valid CIL image";
2116 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2117 return "An assembly was referenced, but could not be found";
2119 return "Internal error";
2123 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2124 guint32 lang_id, gunichar2 *name,
2125 MonoPEResourceDirEntry *entry,
2126 MonoPEResourceDir *root, guint32 level)
2128 gboolean is_string, is_dir;
2129 guint32 name_offset, dir_offset;
2131 /* Level 0 holds a directory entry for each type of resource
2132 * (identified by ID or name).
2134 * Level 1 holds a directory entry for each named resource
2135 * item, and each "anonymous" item of a particular type of
2138 * Level 2 holds a directory entry for each language pointing to
2141 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2142 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2144 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2145 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2150 } else if (level==1) {
2151 if (res_id != name_offset)
2155 is_string==TRUE && name!=lookup (name_offset)) {
2159 } else if (level==2) {
2160 if (is_string || (lang_id != 0 && name_offset != lang_id))
2163 g_assert_not_reached ();
2167 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2168 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2171 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2173 for(i=0; i<entries; i++) {
2174 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2177 ret=mono_image_walk_resource_tree (info, res_id,
2188 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2189 MonoPEResourceDataEntry *res;
2191 res = g_new0 (MonoPEResourceDataEntry, 1);
2193 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2194 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2195 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2196 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2203 * mono_image_lookup_resource:
2204 * @image: the image to look up the resource in
2205 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2206 * @lang_id: The language id.
2207 * @name: the resource name to lookup.
2209 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2210 * of the given resource. The caller should free it using g_free () when no longer
2214 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2216 MonoCLIImageInfo *info;
2217 MonoDotNetHeader *header;
2218 MonoPEDatadir *datadir;
2219 MonoPEDirEntry *rsrc;
2220 MonoPEResourceDir *resource_dir;
2221 MonoPEResourceDirEntry *res_entries;
2228 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2230 info = (MonoCLIImageInfo *)image->image_info;
2235 header=&info->cli_header;
2240 datadir=&header->datadir;
2245 rsrc=&datadir->pe_resource_table;
2250 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2251 if(resource_dir==NULL) {
2255 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2256 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2258 for(i=0; i<entries; i++) {
2259 MonoPEResourceDirEntry *entry=&res_entries[i];
2262 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2263 name, entry, resource_dir,
2274 * mono_image_get_entry_point:
2275 * @image: the image where the entry point will be looked up.
2277 * Use this routine to determine the metadata token for method that
2278 * has been flagged as the entry point.
2280 * Returns: the token for the entry point method in the image
2283 mono_image_get_entry_point (MonoImage *image)
2285 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2289 * mono_image_get_resource:
2290 * @image: the image where the resource will be looked up.
2291 * @offset: The offset to add to the resource
2292 * @size: a pointer to an int where the size of the resource will be stored
2294 * This is a low-level routine that fetches a resource from the
2295 * metadata that starts at a given @offset. The @size parameter is
2296 * filled with the data field as encoded in the metadata.
2298 * Returns: the pointer to the resource whose offset is @offset.
2301 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2303 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2304 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2307 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2310 data = mono_image_rva_map (image, ch->ch_resources.rva);
2315 *size = read32 (data);
2320 // Returning NULL with no error set will be interpeted as "not found"
2322 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2324 char *base_dir, *name;
2326 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2330 mono_error_init (error);
2332 if (fileidx < 1 || fileidx > t->rows)
2335 mono_image_lock (image);
2336 if (image->files && image->files [fileidx - 1]) {
2337 mono_image_unlock (image);
2338 return image->files [fileidx - 1];
2340 mono_image_unlock (image);
2342 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2343 fname = mono_metadata_string_heap (image, fname_id);
2344 base_dir = g_path_get_dirname (image->name);
2345 name = g_build_filename (base_dir, fname, NULL);
2346 res = mono_image_open (name, NULL);
2350 mono_image_lock (image);
2351 if (image->files && image->files [fileidx - 1]) {
2352 MonoImage *old = res;
2353 res = image->files [fileidx - 1];
2354 mono_image_unlock (image);
2355 mono_image_close (old);
2358 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2359 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2360 mono_image_unlock (image);
2361 mono_image_close (res);
2365 for (i = 0; i < res->module_count; ++i) {
2366 if (res->modules [i] && !res->modules [i]->assembly)
2367 res->modules [i]->assembly = image->assembly;
2370 if (!image->files) {
2371 image->files = g_new0 (MonoImage*, t->rows);
2372 image->file_count = t->rows;
2374 image->files [fileidx - 1] = res;
2375 mono_image_unlock (image);
2376 /* vtable fixup can't happen with the image lock held */
2378 if (res->is_module_handle)
2379 mono_image_fixup_vtable (res);
2390 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2393 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2394 mono_error_assert_ok (&error);
2399 * mono_image_get_strong_name:
2400 * @image: a MonoImage
2401 * @size: a guint32 pointer, or NULL.
2403 * If the image has a strong name, and @size is not NULL, the value
2404 * pointed to by size will have the size of the strong name.
2406 * Returns: NULL if the image does not have a strong name, or a
2407 * pointer to the public key.
2410 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2412 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2413 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2416 if (!de->size || !de->rva)
2418 data = mono_image_rva_map (image, de->rva);
2427 * mono_image_strong_name_position:
2428 * @image: a MonoImage
2429 * @size: a guint32 pointer, or NULL.
2431 * If the image has a strong name, and @size is not NULL, the value
2432 * pointed to by size will have the size of the strong name.
2434 * Returns: the position within the image file where the strong name
2438 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2440 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2441 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2446 if (!de->size || !de->rva)
2448 pos = mono_cli_rva_image_map (image, de->rva);
2449 return pos == INVALID_ADDRESS ? 0 : pos;
2453 * mono_image_get_public_key:
2454 * @image: a MonoImage
2455 * @size: a guint32 pointer, or NULL.
2457 * This is used to obtain the public key in the @image.
2459 * If the image has a public key, and @size is not NULL, the value
2460 * pointed to by size will have the size of the public key.
2462 * Returns: NULL if the image does not have a public key, or a pointer
2463 * to the public key.
2466 mono_image_get_public_key (MonoImage *image, guint32 *size)
2471 if (image_is_dynamic (image)) {
2473 *size = ((MonoDynamicImage*)image)->public_key_len;
2474 return (char*)((MonoDynamicImage*)image)->public_key;
2476 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2478 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2481 pubkey = mono_metadata_blob_heap (image, tok);
2482 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2489 * mono_image_get_name:
2490 * @name: a MonoImage
2492 * Returns: the name of the assembly.
2495 mono_image_get_name (MonoImage *image)
2497 return image->assembly_name;
2501 * mono_image_get_filename:
2502 * @image: a MonoImage
2504 * Used to get the filename that hold the actual MonoImage
2506 * Returns: the filename.
2509 mono_image_get_filename (MonoImage *image)
2515 mono_image_get_guid (MonoImage *image)
2520 const MonoTableInfo*
2521 mono_image_get_table_info (MonoImage *image, int table_id)
2523 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2525 return &image->tables [table_id];
2529 mono_image_get_table_rows (MonoImage *image, int table_id)
2531 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2533 return image->tables [table_id].rows;
2537 mono_table_info_get_rows (const MonoTableInfo *table)
2543 * mono_image_get_assembly:
2544 * @image: the MonoImage.
2546 * Use this routine to get the assembly that owns this image.
2548 * Returns: the assembly that holds this image.
2551 mono_image_get_assembly (MonoImage *image)
2553 return image->assembly;
2557 * mono_image_is_dynamic:
2558 * @image: the MonoImage
2560 * Determines if the given image was created dynamically through the
2561 * System.Reflection.Emit API
2563 * Returns: TRUE if the image was created dynamically, FALSE if not.
2566 mono_image_is_dynamic (MonoImage *image)
2568 return image_is_dynamic (image);
2572 * mono_image_has_authenticode_entry:
2573 * @image: the MonoImage
2575 * Use this routine to determine if the image has a Authenticode
2576 * Certificate Table.
2578 * Returns: TRUE if the image contains an authenticode entry in the PE
2582 mono_image_has_authenticode_entry (MonoImage *image)
2584 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2585 MonoDotNetHeader *header = &iinfo->cli_header;
2588 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2589 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2590 return ((de->rva != 0) && (de->size > 8));
2594 mono_image_alloc (MonoImage *image, guint size)
2598 #ifndef DISABLE_PERFCOUNTERS
2599 mono_perfcounters->loader_bytes += size;
2601 mono_image_lock (image);
2602 res = mono_mempool_alloc (image->mempool, size);
2603 mono_image_unlock (image);
2609 mono_image_alloc0 (MonoImage *image, guint size)
2613 #ifndef DISABLE_PERFCOUNTERS
2614 mono_perfcounters->loader_bytes += size;
2616 mono_image_lock (image);
2617 res = mono_mempool_alloc0 (image->mempool, size);
2618 mono_image_unlock (image);
2624 mono_image_strdup (MonoImage *image, const char *s)
2628 #ifndef DISABLE_PERFCOUNTERS
2629 mono_perfcounters->loader_bytes += strlen (s);
2631 mono_image_lock (image);
2632 res = mono_mempool_strdup (image->mempool, s);
2633 mono_image_unlock (image);
2639 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2642 mono_image_lock (image);
2643 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2644 mono_image_unlock (image);
2645 #ifndef DISABLE_PERFCOUNTERS
2646 mono_perfcounters->loader_bytes += strlen (buf);
2652 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2657 va_start (args, format);
2658 buf = mono_image_strdup_vprintf (image, format, args);
2664 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2668 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2669 new_list->data = data;
2670 new_list->prev = list ? list->prev : NULL;
2671 new_list->next = list;
2674 new_list->prev->next = new_list;
2676 list->prev = new_list;
2682 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2686 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2687 new_list->data = data;
2688 new_list->next = NULL;
2690 return g_slist_concat (list, new_list);
2694 mono_image_lock (MonoImage *image)
2696 mono_locks_os_acquire (&image->lock, ImageDataLock);
2700 mono_image_unlock (MonoImage *image)
2702 mono_locks_os_release (&image->lock, ImageDataLock);
2707 * mono_image_property_lookup:
2709 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2711 * LOCKING: Takes the image lock
2714 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2718 mono_image_lock (image);
2719 res = mono_property_hash_lookup (image->property_hash, subject, property);
2720 mono_image_unlock (image);
2726 * mono_image_property_insert:
2728 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2730 * LOCKING: Takes the image lock
2733 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2735 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2736 mono_image_lock (image);
2737 mono_property_hash_insert (image->property_hash, subject, property, value);
2738 mono_image_unlock (image);
2742 * mono_image_property_remove:
2744 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2746 * LOCKING: Takes the image lock
2749 mono_image_property_remove (MonoImage *image, gpointer subject)
2751 mono_image_lock (image);
2752 mono_property_hash_remove_object (image->property_hash, subject);
2753 mono_image_unlock (image);
2757 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2759 MonoImage *image = klass->image;
2760 g_assert (image_is_dynamic (image));
2761 mono_image_lock (image);
2762 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2763 mono_image_unlock (image);
2766 // 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.
2769 * mono_find_image_owner:
2771 * Find the image, if any, which a given pointer is located in the memory of.
2774 mono_find_image_owner (void *ptr)
2776 mono_images_lock ();
2778 MonoImage *owner = NULL;
2780 // Iterate over both by-path image hashes
2781 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2783 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2785 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2786 GHashTableIter iter;
2789 // Iterate over images within a hash
2790 g_hash_table_iter_init (&iter, target);
2791 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2793 mono_image_lock (image);
2794 if (mono_mempool_contains_addr (image->mempool, ptr))
2796 mono_image_unlock (image);
2800 mono_images_unlock ();