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_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
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 if (image->heap_pdb.size) {
599 * Obtain token sizes from the pdb stream.
601 /* 24 = guid + entry point */
603 image->referenced_tables = read64 (image->heap_pdb.data + pos);
605 image->referenced_table_rows = g_new0 (int, 64);
606 for (int i = 0; i < 64; ++i) {
607 if (image->referenced_tables & ((guint64)1 << i)) {
608 image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
614 mono_metadata_compute_table_bases (image);
619 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
621 if (!load_metadata_ptrs (image, iinfo))
624 return load_tables (image);
628 mono_image_check_for_module_cctor (MonoImage *image)
630 MonoTableInfo *t, *mt;
631 t = &image->tables [MONO_TABLE_TYPEDEF];
632 mt = &image->tables [MONO_TABLE_METHOD];
633 if (image_is_dynamic (image)) {
635 image->checked_module_cctor = TRUE;
639 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
640 const char *name = mono_metadata_string_heap (image, nameidx);
641 if (strcmp (name, "<Module>") == 0) {
642 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
645 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
647 last_method = mt->rows;
648 for (; first_method < last_method; first_method++) {
649 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
650 name = mono_metadata_string_heap (image, nameidx);
651 if (strcmp (name, ".cctor") == 0) {
652 image->has_module_cctor = TRUE;
653 image->checked_module_cctor = TRUE;
659 image->has_module_cctor = FALSE;
660 image->checked_module_cctor = TRUE;
664 load_modules (MonoImage *image)
671 t = &image->tables [MONO_TABLE_MODULEREF];
672 image->modules = g_new0 (MonoImage *, t->rows);
673 image->modules_loaded = g_new0 (gboolean, t->rows);
674 image->module_count = t->rows;
678 * mono_image_load_module_checked:
680 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
681 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
684 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
687 MonoTableInfo *file_table;
690 gboolean refonly = image->ref_only;
691 GList *list_iter, *valid_modules = NULL;
692 MonoImageOpenStatus status;
696 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
698 if (image->modules_loaded [idx - 1])
699 return image->modules [idx - 1];
701 file_table = &image->tables [MONO_TABLE_FILE];
702 for (i = 0; i < file_table->rows; i++) {
703 guint32 cols [MONO_FILE_SIZE];
704 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
705 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
707 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
710 t = &image->tables [MONO_TABLE_MODULEREF];
711 base_dir = g_path_get_dirname (image->name);
716 guint32 cols [MONO_MODULEREF_SIZE];
717 /* if there is no file table, we try to load the module... */
718 int valid = file_table->rows == 0;
720 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
721 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
722 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
723 /* be safe with string dups, but we could just compare string indexes */
724 if (strcmp (list_iter->data, name) == 0) {
730 module_ref = g_build_filename (base_dir, name, NULL);
731 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
733 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
734 mono_image_close (moduleImage);
737 g_list_free (valid_modules);
741 image->modules [idx - 1] = moduleImage;
744 if (image->modules [idx - 1]->is_module_handle)
745 mono_image_fixup_vtable (image->modules [idx - 1]);
747 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
753 image->modules_loaded [idx - 1] = TRUE;
756 g_list_free (valid_modules);
758 return image->modules [idx - 1];
762 mono_image_load_module (MonoImage *image, int idx)
765 MonoImage *result = mono_image_load_module_checked (image, idx, &error);
766 mono_error_assert_ok (&error);
771 class_key_extract (gpointer value)
773 MonoClass *klass = (MonoClass *)value;
775 return GUINT_TO_POINTER (klass->type_token);
779 class_next_value (gpointer value)
781 MonoClassDef *klass = (MonoClassDef *)value;
783 return (gpointer*)&klass->next_class_cache;
787 mono_image_init (MonoImage *image)
789 mono_os_mutex_init_recursive (&image->lock);
790 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
792 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
793 mono_internal_hash_table_init (&image->class_cache,
797 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
799 image->typespec_cache = g_hash_table_new (NULL, NULL);
800 image->memberref_signatures = g_hash_table_new (NULL, NULL);
801 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
802 image->method_signatures = g_hash_table_new (NULL, NULL);
804 image->property_hash = mono_property_hash_new ();
807 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
808 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
809 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
810 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
811 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
820 * Returns < 0 to indicate an error.
823 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
825 MonoDotNetHeader64 header64;
828 if (!image->is_module_handle)
830 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
833 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
835 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
838 /* endian swap the fields common between PE and PE+ */
839 SWAP32 (header->coff.coff_time);
840 SWAP32 (header->coff.coff_symptr);
841 SWAP32 (header->coff.coff_symcount);
842 SWAP16 (header->coff.coff_machine);
843 SWAP16 (header->coff.coff_sections);
844 SWAP16 (header->coff.coff_opt_header_size);
845 SWAP16 (header->coff.coff_attributes);
847 SWAP32 (header->pe.pe_code_size);
848 SWAP32 (header->pe.pe_uninit_data_size);
849 SWAP32 (header->pe.pe_rva_entry_point);
850 SWAP32 (header->pe.pe_rva_code_base);
851 SWAP32 (header->pe.pe_rva_data_base);
852 SWAP16 (header->pe.pe_magic);
854 /* now we are ready for the basic tests */
856 if (header->pe.pe_magic == 0x10B) {
857 offset += sizeof (MonoDotNetHeader);
858 SWAP32 (header->pe.pe_data_size);
859 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
862 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
863 SWAP32 (header->nt.pe_stack_reserve);
864 SWAP32 (header->nt.pe_stack_commit);
865 SWAP32 (header->nt.pe_heap_reserve);
866 SWAP32 (header->nt.pe_heap_commit);
867 } else if (header->pe.pe_magic == 0x20B) {
868 /* PE32+ file format */
869 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
871 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
872 offset += sizeof (MonoDotNetHeader64);
873 /* copy the fields already swapped. the last field, pe_data_size, is missing */
874 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
875 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
876 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
878 SWAP64 (header64.nt.pe_image_base);
879 header->nt.pe_image_base = header64.nt.pe_image_base;
880 SWAP64 (header64.nt.pe_stack_reserve);
881 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
882 SWAP64 (header64.nt.pe_stack_commit);
883 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
884 SWAP64 (header64.nt.pe_heap_reserve);
885 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
886 SWAP64 (header64.nt.pe_heap_commit);
887 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
889 header->nt.pe_section_align = header64.nt.pe_section_align;
890 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
891 header->nt.pe_os_major = header64.nt.pe_os_major;
892 header->nt.pe_os_minor = header64.nt.pe_os_minor;
893 header->nt.pe_user_major = header64.nt.pe_user_major;
894 header->nt.pe_user_minor = header64.nt.pe_user_minor;
895 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
896 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
897 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
898 header->nt.pe_image_size = header64.nt.pe_image_size;
899 header->nt.pe_header_size = header64.nt.pe_header_size;
900 header->nt.pe_checksum = header64.nt.pe_checksum;
901 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
902 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
903 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
904 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
906 /* copy the datadir */
907 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
912 /* MonoPEHeaderNT: not used yet */
913 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
914 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
915 SWAP16 (header->nt.pe_os_major); /* must be 4 */
916 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
917 SWAP16 (header->nt.pe_user_major);
918 SWAP16 (header->nt.pe_user_minor);
919 SWAP16 (header->nt.pe_subsys_major);
920 SWAP16 (header->nt.pe_subsys_minor);
921 SWAP32 (header->nt.pe_reserved_1);
922 SWAP32 (header->nt.pe_image_size);
923 SWAP32 (header->nt.pe_header_size);
924 SWAP32 (header->nt.pe_checksum);
925 SWAP16 (header->nt.pe_subsys_required);
926 SWAP16 (header->nt.pe_dll_flags);
927 SWAP32 (header->nt.pe_loader_flags);
928 SWAP32 (header->nt.pe_data_dir_count);
930 /* MonoDotNetHeader: mostly unused */
931 SWAPPDE (header->datadir.pe_export_table);
932 SWAPPDE (header->datadir.pe_import_table);
933 SWAPPDE (header->datadir.pe_resource_table);
934 SWAPPDE (header->datadir.pe_exception_table);
935 SWAPPDE (header->datadir.pe_certificate_table);
936 SWAPPDE (header->datadir.pe_reloc_table);
937 SWAPPDE (header->datadir.pe_debug);
938 SWAPPDE (header->datadir.pe_copyright);
939 SWAPPDE (header->datadir.pe_global_ptr);
940 SWAPPDE (header->datadir.pe_tls_table);
941 SWAPPDE (header->datadir.pe_load_config_table);
942 SWAPPDE (header->datadir.pe_bound_import);
943 SWAPPDE (header->datadir.pe_iat);
944 SWAPPDE (header->datadir.pe_delay_import_desc);
945 SWAPPDE (header->datadir.pe_cli_header);
946 SWAPPDE (header->datadir.pe_reserved);
949 if (image->is_module_handle)
950 image->raw_data_len = header->nt.pe_image_size;
957 mono_image_load_pe_data (MonoImage *image)
959 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
963 pe_image_load_pe_data (MonoImage *image)
965 MonoCLIImageInfo *iinfo;
966 MonoDotNetHeader *header;
967 MonoMSDOSHeader msdos;
970 iinfo = (MonoCLIImageInfo *)image->image_info;
971 header = &iinfo->cli_header;
974 if (!image->is_module_handle)
976 if (offset + sizeof (msdos) > image->raw_data_len)
978 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
980 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
983 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
985 offset = msdos.pe_offset;
987 offset = do_load_header (image, header, offset);
992 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
994 if (header->coff.coff_machine != 0x14c)
1000 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1001 * which produces binaries with 7.0. From Sergey:
1003 * The reason is that MSVC7 uses traditional compile/link
1004 * sequence for CIL executables, and VS.NET (and Framework
1005 * SDK) includes linker version 7, that puts 7.0 in this
1006 * field. That's why it's currently not possible to load VC
1007 * binaries with Mono. This field is pretty much meaningless
1008 * anyway (what linker?).
1010 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1015 * FIXME: byte swap all addresses here for header.
1018 if (!load_section_tables (image, iinfo, offset))
1028 mono_image_load_cli_data (MonoImage *image)
1030 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1034 pe_image_load_cli_data (MonoImage *image)
1036 MonoCLIImageInfo *iinfo;
1037 MonoDotNetHeader *header;
1039 iinfo = (MonoCLIImageInfo *)image->image_info;
1040 header = &iinfo->cli_header;
1042 /* Load the CLI header */
1043 if (!mono_image_load_cli_header (image, iinfo))
1046 if (!mono_image_load_metadata (image, iinfo))
1053 mono_image_load_names (MonoImage *image)
1055 /* modules don't have an assembly table row */
1056 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1057 image->assembly_name = mono_metadata_string_heap (image,
1058 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1059 0, MONO_ASSEMBLY_NAME));
1062 /* Portable pdb images don't have a MODULE row */
1063 if (image->tables [MONO_TABLE_MODULE].rows) {
1064 image->module_name = mono_metadata_string_heap (image,
1065 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1066 0, MONO_MODULE_NAME));
1071 pe_image_load_tables (MonoImage *image)
1077 pe_image_match (MonoImage *image)
1079 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1084 static const MonoImageLoader pe_loader = {
1086 pe_image_load_pe_data,
1087 pe_image_load_cli_data,
1088 pe_image_load_tables,
1092 install_pe_loader (void)
1094 mono_install_image_loader (&pe_loader);
1100 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1101 Mono provides its own implementation of those assemblies so it's safe to do so.
1103 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1105 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_names.
1107 This is to be removed once a proper fix is shipped through nuget.
1112 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1113 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1114 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1115 SYS_NET_HTTP = 3, //System.Net.Http
1116 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1117 SYS_REF_DISP_PROXY = 5, //System.Reflection.DispatchProxy
1118 SYS_VALUE_TUPLE = 6, //System.ValueTuple
1119 } IgnoredAssemblyNames;
1124 const char guid [40];
1127 const char *ignored_assemblies_names[] = {
1128 "System.Runtime.InteropServices.RuntimeInformation.dll",
1129 "System.Globalization.Extensions.dll",
1130 "System.IO.Compression.dll",
1131 "System.Net.Http.dll",
1132 "System.Text.Encoding.CodePages.dll",
1133 "System.Reflection.DispatchProxy.dll",
1134 "System.ValueTuple.dll"
1137 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1139 static const IgnoredAssembly ignored_assemblies [] = {
1140 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1141 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1142 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1143 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1144 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1145 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1146 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1147 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1148 IGNORED_ASSEMBLY (0x4A15555E, SYS_REF_DISP_PROXY, "E40AFEB4-CABE-4124-8412-B46AB79C92FD", "4.0.0 net46"),
1149 IGNORED_ASSEMBLY (0xD20D9783, SYS_REF_DISP_PROXY, "2A69F0AD-B86B-40F2-8E4C-5B671E47479F", "4.0.1 netstandard1.3"),
1150 IGNORED_ASSEMBLY (0xA33A7E68, SYS_REF_DISP_PROXY, "D4E8D2DB-BD65-4168-99EA-D2C1BDEBF9CC", "4.3.0 netstandard1.3"),
1151 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1152 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1153 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1154 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1155 IGNORED_ASSEMBLY (0x75B4B041, SYS_VALUE_TUPLE, "F81A4140-A898-4E2B-B6E9-55CE78C273EC", "4.3.0 netstandard1.0"),
1160 static void Main () {
1163 for (int i = 0; i < str.Length; ++i)
1164 h = ((h << 5) + h) ^ str[i];
1166 Console.WriteLine ("{0:X}", h);
1170 hash_guid (const char *str)
1174 h = ((h << 5) + h) ^ *str;
1182 is_problematic_image (MonoImage *image)
1184 int h = hash_guid (image->guid);
1186 //TODO make this more cache effiecient.
1187 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1188 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1189 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1190 const char *needle = ignored_assemblies_names [ignored_assemblies [i].assembly_name];
1191 size_t needle_len = strlen (needle);
1192 size_t asm_len = strlen (image->name);
1193 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1201 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1202 gboolean care_about_cli, gboolean care_about_pecoff)
1204 MonoCLIImageInfo *iinfo;
1205 MonoDotNetHeader *header;
1206 GSList *errors = NULL;
1209 mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1211 mono_image_init (image);
1213 iinfo = (MonoCLIImageInfo *)image->image_info;
1214 header = &iinfo->cli_header;
1216 if (!image->metadata_only) {
1217 for (l = image_loaders; l; l = l->next) {
1218 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1219 if (loader->match (image)) {
1220 image->loader = loader;
1224 if (!image->loader) {
1226 *status = MONO_IMAGE_IMAGE_INVALID;
1231 *status = MONO_IMAGE_IMAGE_INVALID;
1233 if (care_about_pecoff == FALSE)
1236 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1239 if (!mono_image_load_pe_data (image))
1242 image->loader = (MonoImageLoader*)&pe_loader;
1245 if (care_about_cli == FALSE) {
1249 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1252 if (!mono_image_load_cli_data (image))
1255 if (!image->ref_only && is_problematic_image (image)) {
1256 if (image->load_from_context) {
1257 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1259 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1260 *status = MONO_IMAGE_IMAGE_INVALID;
1265 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1268 mono_image_load_names (image);
1270 load_modules (image);
1273 mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1275 *status = MONO_IMAGE_OK;
1281 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1282 g_warning ("Could not load image %s due to %s", image->name, info->message);
1283 mono_free_verify_list (errors);
1285 mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1286 mono_image_close (image);
1291 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1292 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1294 MonoCLIImageInfo *iinfo;
1298 if ((filed = mono_file_map_open (fname)) == NULL){
1299 if (IS_PORTABILITY_SET) {
1300 gchar *ffname = mono_portability_find_file (fname, TRUE);
1302 filed = mono_file_map_open (ffname);
1307 if (filed == NULL) {
1309 *status = MONO_IMAGE_ERROR_ERRNO;
1314 image = g_new0 (MonoImage, 1);
1315 image->raw_buffer_used = TRUE;
1316 image->raw_data_len = mono_file_map_size (filed);
1317 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);
1318 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1319 if (!image->raw_data) {
1320 image->fileio_used = TRUE;
1321 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);
1324 if (!image->raw_data) {
1325 mono_file_map_close (filed);
1328 *status = MONO_IMAGE_IMAGE_INVALID;
1331 iinfo = g_new0 (MonoCLIImageInfo, 1);
1332 image->image_info = iinfo;
1333 image->name = mono_path_resolve_symlinks (fname);
1334 image->ref_only = refonly;
1335 image->metadata_only = metadata_only;
1336 image->load_from_context = load_from_context;
1337 image->ref_count = 1;
1338 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1339 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1341 mono_file_map_close (filed);
1342 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1346 * mono_image_loaded:
1347 * @name: path or assembly name of the image to load
1348 * @refonly: Check with respect to reflection-only loads?
1350 * This routine verifies that the given image is loaded.
1351 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1353 * Returns: the loaded MonoImage, or NULL on failure.
1356 mono_image_loaded_full (const char *name, gboolean refonly)
1360 mono_images_lock ();
1361 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1363 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1364 mono_images_unlock ();
1370 * mono_image_loaded:
1371 * @name: path or assembly name of the image to load
1373 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1375 * Returns: the loaded MonoImage, or NULL on failure.
1378 mono_image_loaded (const char *name)
1380 return mono_image_loaded_full (name, FALSE);
1389 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1391 GuidData *data = (GuidData *)user_data;
1396 image = (MonoImage *)val;
1397 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1402 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1405 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1409 mono_images_lock ();
1410 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1411 mono_images_unlock ();
1416 mono_image_loaded_by_guid (const char *guid)
1418 return mono_image_loaded_by_guid_full (guid, FALSE);
1422 register_image (MonoImage *image)
1425 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1427 mono_images_lock ();
1428 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1431 /* Somebody else beat us to it */
1432 mono_image_addref (image2);
1433 mono_images_unlock ();
1434 mono_image_close (image);
1438 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1439 g_hash_table_insert (loaded_images, image->name, image);
1440 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1441 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1442 mono_images_unlock ();
1448 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1450 MonoCLIImageInfo *iinfo;
1454 if (!data || !data_len) {
1456 *status = MONO_IMAGE_IMAGE_INVALID;
1461 datac = (char *)g_try_malloc (data_len);
1464 *status = MONO_IMAGE_ERROR_ERRNO;
1467 memcpy (datac, data, data_len);
1470 image = g_new0 (MonoImage, 1);
1471 image->raw_data = datac;
1472 image->raw_data_len = data_len;
1473 image->raw_data_allocated = need_copy;
1474 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1475 iinfo = g_new0 (MonoCLIImageInfo, 1);
1476 image->image_info = iinfo;
1477 image->ref_only = refonly;
1478 image->metadata_only = metadata_only;
1479 image->ref_count = 1;
1481 image = do_mono_image_load (image, status, TRUE, TRUE);
1485 return register_image (image);
1489 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1491 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1495 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1497 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1501 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1503 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1507 /* fname is not duplicated. */
1509 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1512 MonoCLIImageInfo* iinfo;
1514 image = g_new0 (MonoImage, 1);
1515 image->raw_data = (char*) module_handle;
1516 image->is_module_handle = TRUE;
1517 iinfo = g_new0 (MonoCLIImageInfo, 1);
1518 image->image_info = iinfo;
1519 image->name = fname;
1520 image->ref_count = has_entry_point ? 0 : 1;
1521 image->has_entry_point = has_entry_point;
1523 image = do_mono_image_load (image, status, TRUE, TRUE);
1527 return register_image (image);
1532 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1534 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1538 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1541 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1544 g_return_val_if_fail (fname != NULL, NULL);
1547 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1548 // then assemblies need to be loaded with LoadLibrary:
1549 if (!refonly && coree_module_handle) {
1550 HMODULE module_handle;
1551 guint16 *fname_utf16;
1554 absfname = mono_path_resolve_symlinks (fname);
1557 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1558 mono_images_lock ();
1559 image = g_hash_table_lookup (loaded_images, absfname);
1560 if (image) { // Image already loaded
1561 g_assert (image->is_module_handle);
1562 if (image->has_entry_point && image->ref_count == 0) {
1563 /* Increment reference count on images loaded outside of the runtime. */
1564 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1565 /* The image is already loaded because _CorDllMain removes images from the hash. */
1566 module_handle = LoadLibrary (fname_utf16);
1567 g_assert (module_handle == (HMODULE) image->raw_data);
1569 mono_image_addref (image);
1570 mono_images_unlock ();
1572 g_free (fname_utf16);
1577 // Image not loaded, load it now
1578 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1579 module_handle = MonoLoadImage (fname_utf16);
1580 if (status && module_handle == NULL)
1581 last_error = mono_w32error_get_last ();
1583 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1584 image = g_hash_table_lookup (loaded_images, absfname);
1586 mono_image_addref (image);
1587 mono_images_unlock ();
1589 g_free (fname_utf16);
1591 if (module_handle == NULL) {
1595 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1596 *status = MONO_IMAGE_IMAGE_INVALID;
1598 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1608 g_assert (image->is_module_handle);
1609 g_assert (image->has_entry_point);
1614 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1618 absfname = mono_path_canonicalize (fname);
1621 * The easiest solution would be to do all the loading inside the mutex,
1622 * but that would lead to scalability problems. So we let the loading
1623 * happen outside the mutex, and if multiple threads happen to load
1624 * the same image, we discard all but the first copy.
1626 mono_images_lock ();
1627 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1630 if (image) { // Image already loaded
1631 mono_image_addref (image);
1632 mono_images_unlock ();
1635 mono_images_unlock ();
1637 // Image not loaded, load it now
1638 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1642 return register_image (image);
1647 * @fname: filename that points to the module we want to open
1648 * @status: An error condition is returned in this field
1650 * Returns: An open image of type %MonoImage or NULL on error.
1651 * The caller holds a temporary reference to the returned image which should be cleared
1652 * when no longer needed by calling mono_image_close ().
1653 * if NULL, then check the value of @status for details on the error
1656 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1658 return mono_image_open_full (fname, status, FALSE);
1662 * mono_pe_file_open:
1663 * @fname: filename that points to the module we want to open
1664 * @status: An error condition is returned in this field
1666 * Returns: An open image of type %MonoImage or NULL on error. if
1667 * NULL, then check the value of @status for details on the error.
1668 * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1669 * It's just a PE file loader, used for FileVersionInfo. It also does
1670 * not use the image cache.
1673 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1675 g_return_val_if_fail (fname != NULL, NULL);
1677 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1681 * mono_image_open_raw
1682 * @fname: filename that points to the module we want to open
1683 * @status: An error condition is returned in this field
1685 * Returns an image without loading neither pe or cli data.
1687 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1690 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1692 g_return_val_if_fail (fname != NULL, NULL);
1694 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1698 * mono_image_open_metadata_only:
1700 * Open an image which contains metadata only without a PE header.
1703 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1705 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1709 mono_image_fixup_vtable (MonoImage *image)
1712 MonoCLIImageInfo *iinfo;
1714 MonoVTableFixup *vtfixup;
1720 g_assert (image->is_module_handle);
1722 iinfo = image->image_info;
1723 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1724 if (!de->rva || !de->size)
1726 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1730 count = de->size / sizeof (MonoVTableFixup);
1732 if (!vtfixup->rva || !vtfixup->count)
1735 slot = mono_image_rva_map (image, vtfixup->rva);
1737 slot_type = vtfixup->type;
1738 slot_count = vtfixup->count;
1739 if (slot_type & VTFIXUP_TYPE_32BIT)
1740 while (slot_count--) {
1741 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1742 slot = ((guint32*) slot) + 1;
1744 else if (slot_type & VTFIXUP_TYPE_64BIT)
1745 while (slot_count--) {
1746 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1747 slot = ((guint32*) slot) + 1;
1750 g_assert_not_reached();
1755 g_assert_not_reached();
1760 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1762 g_hash_table_destroy ((GHashTable*)val);
1767 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1769 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1774 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1776 g_slist_free ((GSList*)val);
1780 * mono_image_addref:
1781 * @image: The image file we wish to add a reference to
1783 * Increases the reference count of an image.
1786 mono_image_addref (MonoImage *image)
1788 InterlockedIncrement (&image->ref_count);
1792 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1794 stream->alloc_size = stream->index = stream->offset = 0;
1795 g_free (stream->data);
1796 stream->data = NULL;
1798 g_hash_table_destroy (stream->hash);
1799 stream->hash = NULL;
1804 free_hash (GHashTable *hash)
1807 g_hash_table_destroy (hash);
1811 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1813 free_hash (cache->delegate_invoke_cache);
1814 free_hash (cache->delegate_begin_invoke_cache);
1815 free_hash (cache->delegate_end_invoke_cache);
1816 free_hash (cache->runtime_invoke_cache);
1817 free_hash (cache->runtime_invoke_vtype_cache);
1819 free_hash (cache->delegate_abstract_invoke_cache);
1821 free_hash (cache->runtime_invoke_direct_cache);
1822 free_hash (cache->managed_wrapper_cache);
1824 free_hash (cache->native_wrapper_cache);
1825 free_hash (cache->native_wrapper_aot_cache);
1826 free_hash (cache->native_wrapper_check_cache);
1827 free_hash (cache->native_wrapper_aot_check_cache);
1829 free_hash (cache->native_func_wrapper_aot_cache);
1830 free_hash (cache->remoting_invoke_cache);
1831 free_hash (cache->synchronized_cache);
1832 free_hash (cache->unbox_wrapper_cache);
1833 free_hash (cache->cominterop_invoke_cache);
1834 free_hash (cache->cominterop_wrapper_cache);
1835 free_hash (cache->thunk_invoke_cache);
1839 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1841 for (int i = 0; i < image_count; ++i) {
1843 if (!mono_image_close_except_pools (images [i]))
1850 * Returns whether mono_image_close_finish() must be called as well.
1851 * We must unload images in two steps because clearing the domain in
1852 * SGen requires the class metadata to be intact, but we need to free
1853 * the mono_g_hash_tables in case a collection occurs during domain
1854 * unloading and the roots would trip up the GC.
1857 mono_image_close_except_pools (MonoImage *image)
1860 GHashTable *loaded_images, *loaded_images_by_name;
1863 g_return_val_if_fail (image != NULL, FALSE);
1866 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1867 * register_image () can't grab an image which is being closed.
1869 mono_images_lock ();
1871 if (InterlockedDecrement (&image->ref_count) > 0) {
1872 mono_images_unlock ();
1876 loaded_images = get_loaded_images_hash (image->ref_only);
1877 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1878 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1879 if (image == image2) {
1880 /* This is not true if we are called from mono_image_open () */
1881 g_hash_table_remove (loaded_images, image->name);
1883 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1884 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1886 mono_images_unlock ();
1889 if (image->is_module_handle && image->has_entry_point) {
1890 mono_images_lock ();
1891 if (image->ref_count == 0) {
1892 /* Image will be closed by _CorDllMain. */
1893 FreeLibrary ((HMODULE) image->raw_data);
1894 mono_images_unlock ();
1897 mono_images_unlock ();
1901 mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1903 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1905 mono_image_invoke_unload_hook (image);
1907 mono_metadata_clean_for_image (image);
1910 * The caches inside a MonoImage might refer to metadata which is stored in referenced
1911 * assemblies, so we can't release these references in mono_assembly_close () since the
1912 * MonoImage might outlive its associated MonoAssembly.
1914 if (image->references && !image_is_dynamic (image)) {
1915 for (i = 0; i < image->nreferences; i++) {
1916 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1917 if (!mono_assembly_close_except_image_pools (image->references [i]))
1918 image->references [i] = NULL;
1922 if (image->references) {
1923 g_free (image->references);
1924 image->references = NULL;
1929 mono_images_lock ();
1930 if (image->is_module_handle && !image->has_entry_point)
1931 FreeLibrary ((HMODULE) image->raw_data);
1932 mono_images_unlock ();
1935 if (image->raw_buffer_used) {
1936 if (image->raw_data != NULL) {
1938 if (image->fileio_used)
1939 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1942 mono_file_unmap (image->raw_data, image->raw_data_handle);
1946 if (image->raw_data_allocated) {
1947 /* FIXME: do we need this? (image is disposed anyway) */
1948 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1949 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
1951 if ((image->raw_metadata > image->raw_data) &&
1952 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1953 image->raw_metadata = NULL;
1955 for (i = 0; i < ii->cli_section_count; i++)
1956 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1957 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1958 ii->cli_sections [i] = NULL;
1960 g_free (image->raw_data);
1963 if (debug_assembly_unload) {
1964 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1966 g_free (image->name);
1967 g_free (image->guid);
1968 g_free (image->version);
1971 if (image->method_cache)
1972 g_hash_table_destroy (image->method_cache);
1973 if (image->methodref_cache)
1974 g_hash_table_destroy (image->methodref_cache);
1975 mono_internal_hash_table_destroy (&image->class_cache);
1976 mono_conc_hashtable_destroy (image->field_cache);
1977 if (image->array_cache) {
1978 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1979 g_hash_table_destroy (image->array_cache);
1981 if (image->szarray_cache)
1982 g_hash_table_destroy (image->szarray_cache);
1983 if (image->ptr_cache)
1984 g_hash_table_destroy (image->ptr_cache);
1985 if (image->name_cache) {
1986 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1987 g_hash_table_destroy (image->name_cache);
1990 free_hash (image->delegate_bound_static_invoke_cache);
1991 free_hash (image->runtime_invoke_vcall_cache);
1992 free_hash (image->ldfld_wrapper_cache);
1993 free_hash (image->ldflda_wrapper_cache);
1994 free_hash (image->stfld_wrapper_cache);
1995 free_hash (image->isinst_cache);
1996 free_hash (image->castclass_cache);
1997 free_hash (image->icall_wrapper_cache);
1998 free_hash (image->proxy_isinst_cache);
1999 free_hash (image->var_cache_slow);
2000 free_hash (image->mvar_cache_slow);
2001 free_hash (image->var_cache_constrained);
2002 free_hash (image->mvar_cache_constrained);
2003 free_hash (image->wrapper_param_names);
2004 free_hash (image->pinvoke_scopes);
2005 free_hash (image->pinvoke_scope_filenames);
2006 free_hash (image->native_func_wrapper_cache);
2007 free_hash (image->typespec_cache);
2009 mono_wrapper_caches_free (&image->wrapper_caches);
2011 for (i = 0; i < image->gshared_types_len; ++i)
2012 free_hash (image->gshared_types [i]);
2013 g_free (image->gshared_types);
2015 /* The ownership of signatures is not well defined */
2016 g_hash_table_destroy (image->memberref_signatures);
2017 g_hash_table_destroy (image->helper_signatures);
2018 g_hash_table_destroy (image->method_signatures);
2020 if (image->rgctx_template_hash)
2021 g_hash_table_destroy (image->rgctx_template_hash);
2023 if (image->property_hash)
2024 mono_property_hash_destroy (image->property_hash);
2027 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2028 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2030 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2031 image->reflection_info_unregister_classes = NULL;
2033 if (image->interface_bitset) {
2034 mono_unload_interface_ids (image->interface_bitset);
2035 mono_bitset_free (image->interface_bitset);
2037 if (image->image_info){
2038 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2040 if (ii->cli_section_tables)
2041 g_free (ii->cli_section_tables);
2042 if (ii->cli_sections)
2043 g_free (ii->cli_sections);
2044 g_free (image->image_info);
2047 mono_image_close_except_pools_all (image->files, image->file_count);
2048 mono_image_close_except_pools_all (image->modules, image->module_count);
2049 if (image->modules_loaded)
2050 g_free (image->modules_loaded);
2052 mono_os_mutex_destroy (&image->szarray_cache_lock);
2053 mono_os_mutex_destroy (&image->lock);
2055 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2056 if (image_is_dynamic (image)) {
2057 /* Dynamic images are GC_MALLOCed */
2058 g_free ((char*)image->module_name);
2059 mono_dynamic_image_free ((MonoDynamicImage*)image);
2062 mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
2068 mono_image_close_all (MonoImage**images, int image_count)
2070 for (int i = 0; i < image_count; ++i) {
2072 mono_image_close_finish (images [i]);
2079 mono_image_close_finish (MonoImage *image)
2083 if (image->references && !image_is_dynamic (image)) {
2084 for (i = 0; i < image->nreferences; i++) {
2085 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2086 mono_assembly_close_finish (image->references [i]);
2089 g_free (image->references);
2090 image->references = NULL;
2093 mono_image_close_all (image->files, image->file_count);
2094 mono_image_close_all (image->modules, image->module_count);
2096 #ifndef DISABLE_PERFCOUNTERS
2097 mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
2100 if (!image_is_dynamic (image)) {
2101 if (debug_assembly_unload)
2102 mono_mempool_invalidate (image->mempool);
2104 mono_mempool_destroy (image->mempool);
2108 if (debug_assembly_unload)
2109 mono_mempool_invalidate (image->mempool);
2111 mono_mempool_destroy (image->mempool);
2112 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2119 * @image: The image file we wish to close
2121 * Closes an image file, deallocates all memory consumed and
2122 * unmaps all possible sections of the file
2125 mono_image_close (MonoImage *image)
2127 if (mono_image_close_except_pools (image))
2128 mono_image_close_finish (image);
2132 * mono_image_strerror:
2133 * @status: an code indicating the result from a recent operation
2135 * Returns: a string describing the error
2138 mono_image_strerror (MonoImageOpenStatus status)
2143 case MONO_IMAGE_ERROR_ERRNO:
2144 return strerror (errno);
2145 case MONO_IMAGE_IMAGE_INVALID:
2146 return "File does not contain a valid CIL image";
2147 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2148 return "An assembly was referenced, but could not be found";
2150 return "Internal error";
2154 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2155 guint32 lang_id, gunichar2 *name,
2156 MonoPEResourceDirEntry *entry,
2157 MonoPEResourceDir *root, guint32 level)
2159 gboolean is_string, is_dir;
2160 guint32 name_offset, dir_offset;
2162 /* Level 0 holds a directory entry for each type of resource
2163 * (identified by ID or name).
2165 * Level 1 holds a directory entry for each named resource
2166 * item, and each "anonymous" item of a particular type of
2169 * Level 2 holds a directory entry for each language pointing to
2172 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2173 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2175 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2176 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2181 } else if (level==1) {
2182 if (res_id != name_offset)
2186 is_string==TRUE && name!=lookup (name_offset)) {
2190 } else if (level==2) {
2191 if (is_string || (lang_id != 0 && name_offset != lang_id))
2194 g_assert_not_reached ();
2198 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2199 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2202 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2204 for(i=0; i<entries; i++) {
2205 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2208 ret=mono_image_walk_resource_tree (info, res_id,
2219 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2220 MonoPEResourceDataEntry *res;
2222 res = g_new0 (MonoPEResourceDataEntry, 1);
2224 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2225 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2226 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2227 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2234 * mono_image_lookup_resource:
2235 * @image: the image to look up the resource in
2236 * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2237 * @lang_id: The language id.
2238 * @name: the resource name to lookup.
2240 * Returns: NULL if not found, otherwise a pointer to the in-memory representation
2241 * of the given resource. The caller should free it using g_free () when no longer
2245 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2247 MonoCLIImageInfo *info;
2248 MonoDotNetHeader *header;
2249 MonoPEDatadir *datadir;
2250 MonoPEDirEntry *rsrc;
2251 MonoPEResourceDir *resource_dir;
2252 MonoPEResourceDirEntry *res_entries;
2259 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2261 info = (MonoCLIImageInfo *)image->image_info;
2266 header=&info->cli_header;
2271 datadir=&header->datadir;
2276 rsrc=&datadir->pe_resource_table;
2281 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2282 if(resource_dir==NULL) {
2286 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2287 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2289 for(i=0; i<entries; i++) {
2290 MonoPEResourceDirEntry *entry=&res_entries[i];
2293 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2294 name, entry, resource_dir,
2305 * mono_image_get_entry_point:
2306 * @image: the image where the entry point will be looked up.
2308 * Use this routine to determine the metadata token for method that
2309 * has been flagged as the entry point.
2311 * Returns: the token for the entry point method in the image
2314 mono_image_get_entry_point (MonoImage *image)
2316 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2320 * mono_image_get_resource:
2321 * @image: the image where the resource will be looked up.
2322 * @offset: The offset to add to the resource
2323 * @size: a pointer to an int where the size of the resource will be stored
2325 * This is a low-level routine that fetches a resource from the
2326 * metadata that starts at a given @offset. The @size parameter is
2327 * filled with the data field as encoded in the metadata.
2329 * Returns: the pointer to the resource whose offset is @offset.
2332 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2334 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2335 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2338 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2341 data = mono_image_rva_map (image, ch->ch_resources.rva);
2346 *size = read32 (data);
2351 // Returning NULL with no error set will be interpeted as "not found"
2353 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2355 char *base_dir, *name;
2357 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2363 if (fileidx < 1 || fileidx > t->rows)
2366 mono_image_lock (image);
2367 if (image->files && image->files [fileidx - 1]) {
2368 mono_image_unlock (image);
2369 return image->files [fileidx - 1];
2371 mono_image_unlock (image);
2373 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2374 fname = mono_metadata_string_heap (image, fname_id);
2375 base_dir = g_path_get_dirname (image->name);
2376 name = g_build_filename (base_dir, fname, NULL);
2377 res = mono_image_open (name, NULL);
2381 mono_image_lock (image);
2382 if (image->files && image->files [fileidx - 1]) {
2383 MonoImage *old = res;
2384 res = image->files [fileidx - 1];
2385 mono_image_unlock (image);
2386 mono_image_close (old);
2389 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2390 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2391 mono_image_unlock (image);
2392 mono_image_close (res);
2396 for (i = 0; i < res->module_count; ++i) {
2397 if (res->modules [i] && !res->modules [i]->assembly)
2398 res->modules [i]->assembly = image->assembly;
2401 if (!image->files) {
2402 image->files = g_new0 (MonoImage*, t->rows);
2403 image->file_count = t->rows;
2405 image->files [fileidx - 1] = res;
2406 mono_image_unlock (image);
2407 /* vtable fixup can't happen with the image lock held */
2409 if (res->is_module_handle)
2410 mono_image_fixup_vtable (res);
2421 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2424 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2425 mono_error_assert_ok (&error);
2430 * mono_image_get_strong_name:
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: NULL if the image does not have a strong name, or a
2438 * pointer to the public key.
2441 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2443 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2444 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2447 if (!de->size || !de->rva)
2449 data = mono_image_rva_map (image, de->rva);
2458 * mono_image_strong_name_position:
2459 * @image: a MonoImage
2460 * @size: a guint32 pointer, or NULL.
2462 * If the image has a strong name, and @size is not NULL, the value
2463 * pointed to by size will have the size of the strong name.
2465 * Returns: the position within the image file where the strong name
2469 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2471 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2472 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2477 if (!de->size || !de->rva)
2479 pos = mono_cli_rva_image_map (image, de->rva);
2480 return pos == INVALID_ADDRESS ? 0 : pos;
2484 * mono_image_get_public_key:
2485 * @image: a MonoImage
2486 * @size: a guint32 pointer, or NULL.
2488 * This is used to obtain the public key in the @image.
2490 * If the image has a public key, and @size is not NULL, the value
2491 * pointed to by size will have the size of the public key.
2493 * Returns: NULL if the image does not have a public key, or a pointer
2494 * to the public key.
2497 mono_image_get_public_key (MonoImage *image, guint32 *size)
2502 if (image_is_dynamic (image)) {
2504 *size = ((MonoDynamicImage*)image)->public_key_len;
2505 return (char*)((MonoDynamicImage*)image)->public_key;
2507 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2509 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2512 pubkey = mono_metadata_blob_heap (image, tok);
2513 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2520 * mono_image_get_name:
2521 * @name: a MonoImage
2523 * Returns: the name of the assembly.
2526 mono_image_get_name (MonoImage *image)
2528 return image->assembly_name;
2532 * mono_image_get_filename:
2533 * @image: a MonoImage
2535 * Used to get the filename that hold the actual MonoImage
2537 * Returns: the filename.
2540 mono_image_get_filename (MonoImage *image)
2546 mono_image_get_guid (MonoImage *image)
2551 const MonoTableInfo*
2552 mono_image_get_table_info (MonoImage *image, int table_id)
2554 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2556 return &image->tables [table_id];
2560 mono_image_get_table_rows (MonoImage *image, int table_id)
2562 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2564 return image->tables [table_id].rows;
2568 mono_table_info_get_rows (const MonoTableInfo *table)
2574 * mono_image_get_assembly:
2575 * @image: the MonoImage.
2577 * Use this routine to get the assembly that owns this image.
2579 * Returns: the assembly that holds this image.
2582 mono_image_get_assembly (MonoImage *image)
2584 return image->assembly;
2588 * mono_image_is_dynamic:
2589 * @image: the MonoImage
2591 * Determines if the given image was created dynamically through the
2592 * System.Reflection.Emit API
2594 * Returns: TRUE if the image was created dynamically, FALSE if not.
2597 mono_image_is_dynamic (MonoImage *image)
2599 return image_is_dynamic (image);
2603 * mono_image_has_authenticode_entry:
2604 * @image: the MonoImage
2606 * Use this routine to determine if the image has a Authenticode
2607 * Certificate Table.
2609 * Returns: TRUE if the image contains an authenticode entry in the PE
2613 mono_image_has_authenticode_entry (MonoImage *image)
2615 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2616 MonoDotNetHeader *header = &iinfo->cli_header;
2619 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2620 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2621 return ((de->rva != 0) && (de->size > 8));
2625 mono_image_alloc (MonoImage *image, guint size)
2629 #ifndef DISABLE_PERFCOUNTERS
2630 mono_perfcounters->loader_bytes += size;
2632 mono_image_lock (image);
2633 res = mono_mempool_alloc (image->mempool, size);
2634 mono_image_unlock (image);
2640 mono_image_alloc0 (MonoImage *image, guint size)
2644 #ifndef DISABLE_PERFCOUNTERS
2645 mono_perfcounters->loader_bytes += size;
2647 mono_image_lock (image);
2648 res = mono_mempool_alloc0 (image->mempool, size);
2649 mono_image_unlock (image);
2655 mono_image_strdup (MonoImage *image, const char *s)
2659 #ifndef DISABLE_PERFCOUNTERS
2660 mono_perfcounters->loader_bytes += strlen (s);
2662 mono_image_lock (image);
2663 res = mono_mempool_strdup (image->mempool, s);
2664 mono_image_unlock (image);
2670 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2673 mono_image_lock (image);
2674 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2675 mono_image_unlock (image);
2676 #ifndef DISABLE_PERFCOUNTERS
2677 mono_perfcounters->loader_bytes += strlen (buf);
2683 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2688 va_start (args, format);
2689 buf = mono_image_strdup_vprintf (image, format, args);
2695 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2699 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2700 new_list->data = data;
2701 new_list->prev = list ? list->prev : NULL;
2702 new_list->next = list;
2705 new_list->prev->next = new_list;
2707 list->prev = new_list;
2713 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2717 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2718 new_list->data = data;
2719 new_list->next = NULL;
2721 return g_slist_concat (list, new_list);
2725 mono_image_lock (MonoImage *image)
2727 mono_locks_os_acquire (&image->lock, ImageDataLock);
2731 mono_image_unlock (MonoImage *image)
2733 mono_locks_os_release (&image->lock, ImageDataLock);
2738 * mono_image_property_lookup:
2740 * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2742 * LOCKING: Takes the image lock
2745 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2749 mono_image_lock (image);
2750 res = mono_property_hash_lookup (image->property_hash, subject, property);
2751 mono_image_unlock (image);
2757 * mono_image_property_insert:
2759 * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2761 * LOCKING: Takes the image lock
2764 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2766 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2767 mono_image_lock (image);
2768 mono_property_hash_insert (image->property_hash, subject, property, value);
2769 mono_image_unlock (image);
2773 * mono_image_property_remove:
2775 * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2777 * LOCKING: Takes the image lock
2780 mono_image_property_remove (MonoImage *image, gpointer subject)
2782 mono_image_lock (image);
2783 mono_property_hash_remove_object (image->property_hash, subject);
2784 mono_image_unlock (image);
2788 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2790 MonoImage *image = klass->image;
2791 g_assert (image_is_dynamic (image));
2792 mono_image_lock (image);
2793 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2794 mono_image_unlock (image);
2797 // 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.
2800 * mono_find_image_owner:
2802 * Find the image, if any, which a given pointer is located in the memory of.
2805 mono_find_image_owner (void *ptr)
2807 mono_images_lock ();
2809 MonoImage *owner = NULL;
2811 // Iterate over both by-path image hashes
2812 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2814 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2816 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2817 GHashTableIter iter;
2820 // Iterate over images within a hash
2821 g_hash_table_iter_init (&iter, target);
2822 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2824 mono_image_lock (image);
2825 if (mono_mempool_contains_addr (image->mempool, ptr))
2827 mono_image_unlock (image);
2831 mono_images_unlock ();