3 * Routines for manipulating an image stored in an
4 * extended PE/COFF file.
7 * Miguel de Icaza (miguel@ximian.com)
8 * Paolo Molaro (lupus@ximian.com)
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
23 #include "mono-endian.h"
24 #include "tabledefs.h"
25 #include "tokentype.h"
26 #include "metadata-internals.h"
27 #include "profiler-private.h"
31 #include <mono/metadata/exception-internals.h>
32 #include <mono/utils/checked-build.h>
33 #include <mono/utils/mono-logger-internals.h>
34 #include <mono/utils/mono-errno.h>
35 #include <mono/utils/mono-path.h>
36 #include <mono/utils/mono-mmap.h>
37 #include <mono/utils/mono-io-portability.h>
38 #include <mono/utils/atomic.h>
39 #include <mono/utils/mono-proclib.h>
40 #include <mono/metadata/class-internals.h>
41 #include <mono/metadata/assembly.h>
42 #include <mono/metadata/object-internals.h>
43 #include <mono/metadata/security-core-clr.h>
44 #include <mono/metadata/verify-internals.h>
45 #include <mono/metadata/verify.h>
46 #include <mono/metadata/image-internals.h>
47 #include <mono/metadata/loaded-images-internals.h>
48 #include <mono/metadata/w32process-internals.h>
49 #include <sys/types.h>
54 #include <mono/metadata/w32error.h>
56 #define INVALID_ADDRESS 0xffffffff
58 // Amount initially reserved in each image's mempool.
59 // FIXME: This number is arbitrary, a more practical number should be found
60 #define INITIAL_IMAGE_SIZE 512
62 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
63 // Can be used on modules loaded through either the "file" or "module" mechanism
65 assign_assembly_parent_for_netmodule (MonoImage
*image
, MonoImage
*assemblyImage
, MonoError
*error
)
68 MonoAssembly
*assembly
= assemblyImage
->assembly
;
71 // Assembly currently assigned
72 MonoAssembly
*assemblyOld
= image
->assembly
;
74 if (assemblyOld
== assembly
)
76 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
);
79 gpointer result
= mono_atomic_xchg_ptr((gpointer
*)&image
->assembly
, assembly
);
80 if (result
== assembly
)
85 static gboolean debug_assembly_unload
= FALSE
;
87 #define mono_images_storage_lock() do { if (mutex_inited) mono_os_mutex_lock (&images_storage_mutex); } while (0)
88 #define mono_images_storage_unlock() do { if (mutex_inited) mono_os_mutex_unlock (&images_storage_mutex); } while (0)
89 static gboolean mutex_inited
;
90 static mono_mutex_t images_mutex
;
91 static mono_mutex_t images_storage_mutex
;
94 mono_images_lock (void)
97 mono_os_mutex_lock (&images_mutex
);
101 mono_images_unlock(void)
104 mono_os_mutex_unlock (&images_mutex
);
108 mono_image_open_a_lot_parameterized (MonoLoadedImages
*li
, MonoAssemblyLoadContext
*alc
, const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean load_from_context
, gboolean
*problematic
);
110 /* Maps string keys to MonoImageStorage values.
112 * The MonoImageStorage in the hash owns the key.
114 static GHashTable
*images_storage_hash
;
116 static void install_pe_loader (void);
118 typedef struct ImageUnloadHook ImageUnloadHook
;
119 struct ImageUnloadHook
{
120 MonoImageUnloadFunc func
;
124 static GSList
*image_unload_hooks
;
127 mono_install_image_unload_hook (MonoImageUnloadFunc func
, gpointer user_data
)
129 ImageUnloadHook
*hook
;
131 g_return_if_fail (func
!= NULL
);
133 hook
= g_new0 (ImageUnloadHook
, 1);
135 hook
->user_data
= user_data
;
136 image_unload_hooks
= g_slist_prepend (image_unload_hooks
, hook
);
140 mono_remove_image_unload_hook (MonoImageUnloadFunc func
, gpointer user_data
)
143 ImageUnloadHook
*hook
;
145 for (l
= image_unload_hooks
; l
; l
= l
->next
) {
146 hook
= (ImageUnloadHook
*)l
->data
;
148 if (hook
->func
== func
&& hook
->user_data
== user_data
) {
150 image_unload_hooks
= g_slist_delete_link (image_unload_hooks
, l
);
157 mono_image_invoke_unload_hook (MonoImage
*image
)
160 ImageUnloadHook
*hook
;
162 for (l
= image_unload_hooks
; l
; l
= l
->next
) {
163 hook
= (ImageUnloadHook
*)l
->data
;
165 hook
->func (image
, hook
->user_data
);
169 static GSList
*image_loaders
;
172 mono_install_image_loader (const MonoImageLoader
*loader
)
174 image_loaders
= g_slist_prepend (image_loaders
, (MonoImageLoader
*)loader
);
177 /* returns offset relative to image->raw_data */
179 mono_cli_rva_image_map (MonoImage
*image
, guint32 addr
)
181 MonoCLIImageInfo
*iinfo
= image
->image_info
;
182 const int top
= iinfo
->cli_section_count
;
183 MonoSectionTable
*tables
= iinfo
->cli_section_tables
;
186 if (image
->metadata_only
)
189 for (i
= 0; i
< top
; i
++){
190 if ((addr
>= tables
->st_virtual_address
) &&
191 (addr
< tables
->st_virtual_address
+ tables
->st_raw_data_size
)){
193 if (m_image_is_module_handle (image
))
196 return addr
- tables
->st_virtual_address
+ tables
->st_raw_data_ptr
;
200 return INVALID_ADDRESS
;
204 * mono_image_rva_map:
205 * \param image a \c MonoImage
206 * \param addr relative virtual address (RVA)
208 * This is a low-level routine used by the runtime to map relative
209 * virtual address (RVA) into their location in memory.
211 * \returns the address in memory for the given RVA, or NULL if the
212 * RVA is not valid for this image.
215 mono_image_rva_map (MonoImage
*image
, guint32 addr
)
217 MonoCLIImageInfo
*iinfo
= image
->image_info
;
218 const int top
= iinfo
->cli_section_count
;
219 MonoSectionTable
*tables
= iinfo
->cli_section_tables
;
223 if (m_image_is_module_handle (image
)) {
224 if (addr
&& addr
< image
->raw_data_len
)
225 return image
->raw_data
+ addr
;
231 for (i
= 0; i
< top
; i
++){
232 if ((addr
>= tables
->st_virtual_address
) &&
233 (addr
< tables
->st_virtual_address
+ tables
->st_raw_data_size
)){
234 if (!iinfo
->cli_sections
[i
]) {
235 if (!mono_image_ensure_section_idx (image
, i
))
238 return (char*)iinfo
->cli_sections
[i
] +
239 (addr
- tables
->st_virtual_address
);
249 * Initialize the global variables used by this module.
252 mono_images_init (void)
254 mono_os_mutex_init (&images_storage_mutex
);
255 mono_os_mutex_init_recursive (&images_mutex
);
257 images_storage_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
259 #ifndef ENABLE_NETCORE
260 mono_loaded_images_init (mono_get_global_loaded_images (), NULL
);
263 debug_assembly_unload
= g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
265 install_pe_loader ();
271 * mono_images_cleanup:
273 * Free all resources used by this module.
276 mono_images_cleanup (void)
278 mono_os_mutex_destroy (&images_mutex
);
280 #ifndef ENABLE_NETCORE
281 mono_loaded_images_cleanup (mono_get_global_loaded_images (), TRUE
);
284 g_hash_table_destroy (images_storage_hash
);
286 mono_os_mutex_destroy (&images_storage_mutex
);
288 mutex_inited
= FALSE
;
292 * mono_image_ensure_section_idx:
293 * \param image The image we are operating on
294 * \param 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 (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
299 * \returns TRUE on success
302 mono_image_ensure_section_idx (MonoImage
*image
, int section
)
304 MonoCLIImageInfo
*iinfo
= 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 (m_image_is_module_handle (image
))
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 * \param image The image we are operating on
329 * \param 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
= 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
);
539 if (!image
->metadata_only
) {
540 g_assert (image
->heap_guid
.data
);
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
;
663 #ifndef ENABLE_NETCORE
665 load_modules (MonoImage
*image
)
672 t
= &image
->tables
[MONO_TABLE_MODULEREF
];
673 image
->modules
= g_new0 (MonoImage
*, t
->rows
);
674 image
->modules_loaded
= g_new0 (gboolean
, t
->rows
);
675 image
->module_count
= t
->rows
;
680 * mono_image_load_module_checked:
682 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
683 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
686 mono_image_load_module_checked (MonoImage
*image
, int idx
, MonoError
*error
)
689 MonoTableInfo
*file_table
;
692 gboolean refonly
= image
->ref_only
;
693 GList
*list_iter
, *valid_modules
= NULL
;
694 MonoImageOpenStatus status
;
698 if ((image
->module_count
== 0) || (idx
> image
->module_count
|| idx
<= 0))
700 if (image
->modules_loaded
[idx
- 1])
701 return image
->modules
[idx
- 1];
703 #ifdef ENABLE_NETCORE
704 /* SRE still uses image->modules, but they are not loaded from files, so the rest of this function is dead code for netcore */
705 g_assert_not_reached ();
708 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Loading module %d of %s (%s)", idx
, image
->assembly
? image
->assembly
->aname
.name
: "some assembly", image
->name
);
710 file_table
= &image
->tables
[MONO_TABLE_FILE
];
711 for (i
= 0; i
< file_table
->rows
; i
++) {
712 guint32 cols
[MONO_FILE_SIZE
];
713 mono_metadata_decode_row (file_table
, i
, cols
, MONO_FILE_SIZE
);
714 if (cols
[MONO_FILE_FLAGS
] == FILE_CONTAINS_NO_METADATA
)
716 valid_modules
= g_list_prepend (valid_modules
, (char*)mono_metadata_string_heap (image
, cols
[MONO_FILE_NAME
]));
719 t
= &image
->tables
[MONO_TABLE_MODULEREF
];
720 base_dir
= g_path_get_dirname (image
->name
);
725 guint32 cols
[MONO_MODULEREF_SIZE
];
726 /* if there is no file table, we try to load the module... */
727 int valid
= file_table
->rows
== 0;
729 mono_metadata_decode_row (t
, idx
- 1, cols
, MONO_MODULEREF_SIZE
);
730 name
= mono_metadata_string_heap (image
, cols
[MONO_MODULEREF_NAME
]);
731 for (list_iter
= valid_modules
; list_iter
; list_iter
= list_iter
->next
) {
732 /* be safe with string dups, but we could just compare string indexes */
733 if (strcmp ((const char*)list_iter
->data
, name
) == 0) {
739 MonoAssemblyLoadContext
*alc
= mono_image_get_alc (image
);
740 MonoLoadedImages
*li
= mono_image_get_loaded_images_for_modules (image
);
741 module_ref
= g_build_filename (base_dir
, name
, (const char*)NULL
);
742 MonoImage
*moduleImage
= mono_image_open_a_lot_parameterized (li
, alc
, module_ref
, &status
, refonly
, FALSE
, NULL
);
744 if (!assign_assembly_parent_for_netmodule (moduleImage
, image
, error
)) {
745 mono_image_close (moduleImage
);
748 g_list_free (valid_modules
);
752 image
->modules
[idx
- 1] = moduleImage
;
755 if (m_image_is_module_handle (image
->modules
[idx
- 1]))
756 mono_image_fixup_vtable (image
->modules
[idx
- 1]);
758 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
764 image
->modules_loaded
[idx
- 1] = TRUE
;
767 g_list_free (valid_modules
);
769 return image
->modules
[idx
- 1];
774 * mono_image_load_module:
777 mono_image_load_module (MonoImage
*image
, int idx
)
780 MonoImage
*result
= mono_image_load_module_checked (image
, idx
, error
);
781 mono_error_assert_ok (error
);
786 class_key_extract (gpointer value
)
788 MonoClass
*klass
= (MonoClass
*)value
;
790 return GUINT_TO_POINTER (m_class_get_type_token (klass
));
794 class_next_value (gpointer value
)
796 MonoClassDef
*klass
= (MonoClassDef
*)value
;
798 return (gpointer
*)m_classdef_get_next_class_cache (klass
);
805 mono_image_init (MonoImage
*image
)
807 mono_os_mutex_init_recursive (&image
->lock
);
808 mono_os_mutex_init_recursive (&image
->szarray_cache_lock
);
810 image
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SIZE
);
811 mono_internal_hash_table_init (&image
->class_cache
,
815 image
->field_cache
= mono_conc_hashtable_new (NULL
, NULL
);
817 image
->typespec_cache
= mono_conc_hashtable_new (NULL
, NULL
);
818 image
->memberref_signatures
= g_hash_table_new (NULL
, NULL
);
819 image
->method_signatures
= g_hash_table_new (NULL
, NULL
);
821 image
->property_hash
= mono_property_hash_new ();
824 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
825 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
826 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
827 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
828 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
837 * Returns < 0 to indicate an error.
840 do_load_header (MonoImage
*image
, MonoDotNetHeader
*header
, int offset
)
842 MonoDotNetHeader64 header64
;
845 if (!m_image_is_module_handle (image
))
847 if (offset
+ sizeof (MonoDotNetHeader32
) > image
->raw_data_len
)
850 memcpy (header
, image
->raw_data
+ offset
, sizeof (MonoDotNetHeader
));
852 if (header
->pesig
[0] != 'P' || header
->pesig
[1] != 'E' || header
->pesig
[2] || header
->pesig
[3])
855 /* endian swap the fields common between PE and PE+ */
856 SWAP32 (header
->coff
.coff_time
);
857 SWAP32 (header
->coff
.coff_symptr
);
858 SWAP32 (header
->coff
.coff_symcount
);
859 SWAP16 (header
->coff
.coff_machine
);
860 SWAP16 (header
->coff
.coff_sections
);
861 SWAP16 (header
->coff
.coff_opt_header_size
);
862 SWAP16 (header
->coff
.coff_attributes
);
864 SWAP32 (header
->pe
.pe_code_size
);
865 SWAP32 (header
->pe
.pe_uninit_data_size
);
866 SWAP32 (header
->pe
.pe_rva_entry_point
);
867 SWAP32 (header
->pe
.pe_rva_code_base
);
868 SWAP32 (header
->pe
.pe_rva_data_base
);
869 SWAP16 (header
->pe
.pe_magic
);
871 /* now we are ready for the basic tests */
873 if (header
->pe
.pe_magic
== 0x10B) {
874 offset
+= sizeof (MonoDotNetHeader
);
875 SWAP32 (header
->pe
.pe_data_size
);
876 if (header
->coff
.coff_opt_header_size
!= (sizeof (MonoDotNetHeader
) - sizeof (MonoCOFFHeader
) - 4))
879 SWAP32 (header
->nt
.pe_image_base
); /* must be 0x400000 */
880 SWAP32 (header
->nt
.pe_stack_reserve
);
881 SWAP32 (header
->nt
.pe_stack_commit
);
882 SWAP32 (header
->nt
.pe_heap_reserve
);
883 SWAP32 (header
->nt
.pe_heap_commit
);
884 } else if (header
->pe
.pe_magic
== 0x20B) {
885 /* PE32+ file format */
886 if (header
->coff
.coff_opt_header_size
!= (sizeof (MonoDotNetHeader64
) - sizeof (MonoCOFFHeader
) - 4))
888 memcpy (&header64
, image
->raw_data
+ offset
, sizeof (MonoDotNetHeader64
));
889 offset
+= sizeof (MonoDotNetHeader64
);
890 /* copy the fields already swapped. the last field, pe_data_size, is missing */
891 memcpy (&header64
, header
, sizeof (MonoDotNetHeader
) - 4);
892 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
893 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
895 SWAP64 (header64
.nt
.pe_image_base
);
896 header
->nt
.pe_image_base
= header64
.nt
.pe_image_base
;
897 SWAP64 (header64
.nt
.pe_stack_reserve
);
898 header
->nt
.pe_stack_reserve
= header64
.nt
.pe_stack_reserve
;
899 SWAP64 (header64
.nt
.pe_stack_commit
);
900 header
->nt
.pe_stack_commit
= header64
.nt
.pe_stack_commit
;
901 SWAP64 (header64
.nt
.pe_heap_reserve
);
902 header
->nt
.pe_heap_reserve
= header64
.nt
.pe_heap_reserve
;
903 SWAP64 (header64
.nt
.pe_heap_commit
);
904 header
->nt
.pe_heap_commit
= header64
.nt
.pe_heap_commit
;
906 header
->nt
.pe_section_align
= header64
.nt
.pe_section_align
;
907 header
->nt
.pe_file_alignment
= header64
.nt
.pe_file_alignment
;
908 header
->nt
.pe_os_major
= header64
.nt
.pe_os_major
;
909 header
->nt
.pe_os_minor
= header64
.nt
.pe_os_minor
;
910 header
->nt
.pe_user_major
= header64
.nt
.pe_user_major
;
911 header
->nt
.pe_user_minor
= header64
.nt
.pe_user_minor
;
912 header
->nt
.pe_subsys_major
= header64
.nt
.pe_subsys_major
;
913 header
->nt
.pe_subsys_minor
= header64
.nt
.pe_subsys_minor
;
914 header
->nt
.pe_reserved_1
= header64
.nt
.pe_reserved_1
;
915 header
->nt
.pe_image_size
= header64
.nt
.pe_image_size
;
916 header
->nt
.pe_header_size
= header64
.nt
.pe_header_size
;
917 header
->nt
.pe_checksum
= header64
.nt
.pe_checksum
;
918 header
->nt
.pe_subsys_required
= header64
.nt
.pe_subsys_required
;
919 header
->nt
.pe_dll_flags
= header64
.nt
.pe_dll_flags
;
920 header
->nt
.pe_loader_flags
= header64
.nt
.pe_loader_flags
;
921 header
->nt
.pe_data_dir_count
= header64
.nt
.pe_data_dir_count
;
923 /* copy the datadir */
924 memcpy (&header
->datadir
, &header64
.datadir
, sizeof (MonoPEDatadir
));
929 /* MonoPEHeaderNT: not used yet */
930 SWAP32 (header
->nt
.pe_section_align
); /* must be 8192 */
931 SWAP32 (header
->nt
.pe_file_alignment
); /* must be 512 or 4096 */
932 SWAP16 (header
->nt
.pe_os_major
); /* must be 4 */
933 SWAP16 (header
->nt
.pe_os_minor
); /* must be 0 */
934 SWAP16 (header
->nt
.pe_user_major
);
935 SWAP16 (header
->nt
.pe_user_minor
);
936 SWAP16 (header
->nt
.pe_subsys_major
);
937 SWAP16 (header
->nt
.pe_subsys_minor
);
938 SWAP32 (header
->nt
.pe_reserved_1
);
939 SWAP32 (header
->nt
.pe_image_size
);
940 SWAP32 (header
->nt
.pe_header_size
);
941 SWAP32 (header
->nt
.pe_checksum
);
942 SWAP16 (header
->nt
.pe_subsys_required
);
943 SWAP16 (header
->nt
.pe_dll_flags
);
944 SWAP32 (header
->nt
.pe_loader_flags
);
945 SWAP32 (header
->nt
.pe_data_dir_count
);
947 /* MonoDotNetHeader: mostly unused */
948 SWAPPDE (header
->datadir
.pe_export_table
);
949 SWAPPDE (header
->datadir
.pe_import_table
);
950 SWAPPDE (header
->datadir
.pe_resource_table
);
951 SWAPPDE (header
->datadir
.pe_exception_table
);
952 SWAPPDE (header
->datadir
.pe_certificate_table
);
953 SWAPPDE (header
->datadir
.pe_reloc_table
);
954 SWAPPDE (header
->datadir
.pe_debug
);
955 SWAPPDE (header
->datadir
.pe_copyright
);
956 SWAPPDE (header
->datadir
.pe_global_ptr
);
957 SWAPPDE (header
->datadir
.pe_tls_table
);
958 SWAPPDE (header
->datadir
.pe_load_config_table
);
959 SWAPPDE (header
->datadir
.pe_bound_import
);
960 SWAPPDE (header
->datadir
.pe_iat
);
961 SWAPPDE (header
->datadir
.pe_delay_import_desc
);
962 SWAPPDE (header
->datadir
.pe_cli_header
);
963 SWAPPDE (header
->datadir
.pe_reserved
);
966 if (m_image_is_module_handle (image
))
967 image
->storage
->raw_data_len
= header
->nt
.pe_image_size
;
974 mono_image_load_pe_data (MonoImage
*image
)
976 return ((MonoImageLoader
*)image
->loader
)->load_pe_data (image
);
980 pe_image_load_pe_data (MonoImage
*image
)
982 MonoCLIImageInfo
*iinfo
;
983 MonoDotNetHeader
*header
;
984 MonoMSDOSHeader msdos
;
987 iinfo
= image
->image_info
;
988 header
= &iinfo
->cli_header
;
991 if (!m_image_is_module_handle (image
))
993 if (offset
+ sizeof (msdos
) > image
->raw_data_len
)
995 memcpy (&msdos
, image
->raw_data
+ offset
, sizeof (msdos
));
997 if (!(msdos
.msdos_sig
[0] == 'M' && msdos
.msdos_sig
[1] == 'Z'))
1000 msdos
.pe_offset
= GUINT32_FROM_LE (msdos
.pe_offset
);
1002 offset
= msdos
.pe_offset
;
1004 offset
= do_load_header (image
, header
, offset
);
1009 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1010 * we skip this test.
1011 if (header->coff.coff_machine != 0x14c)
1017 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1018 * which produces binaries with 7.0. From Sergey:
1020 * The reason is that MSVC7 uses traditional compile/link
1021 * sequence for CIL executables, and VS.NET (and Framework
1022 * SDK) includes linker version 7, that puts 7.0 in this
1023 * field. That's why it's currently not possible to load VC
1024 * binaries with Mono. This field is pretty much meaningless
1025 * anyway (what linker?).
1027 if (header
->pe
.pe_major
!= 6 || header
->pe
.pe_minor
!= 0)
1032 * FIXME: byte swap all addresses here for header.
1035 if (!load_section_tables (image
, iinfo
, offset
))
1045 mono_image_load_cli_data (MonoImage
*image
)
1047 return ((MonoImageLoader
*)image
->loader
)->load_cli_data (image
);
1051 pe_image_load_cli_data (MonoImage
*image
)
1053 MonoCLIImageInfo
*iinfo
;
1055 iinfo
= image
->image_info
;
1057 /* Load the CLI header */
1058 if (!mono_image_load_cli_header (image
, iinfo
))
1061 if (!mono_image_load_metadata (image
, iinfo
))
1068 mono_image_load_time_date_stamp (MonoImage
*image
)
1070 image
->time_date_stamp
= 0;
1072 if (!image
->filename
)
1075 gunichar2
*uni_name
= g_utf8_to_utf16 (image
->filename
, -1, NULL
, NULL
, NULL
);
1076 mono_pe_file_time_date_stamp (uni_name
, &image
->time_date_stamp
);
1082 mono_image_load_names (MonoImage
*image
)
1084 /* modules don't have an assembly table row */
1085 if (image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
1086 image
->assembly_name
= mono_metadata_string_heap (image
,
1087 mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_ASSEMBLY
],
1088 0, MONO_ASSEMBLY_NAME
));
1091 /* Portable pdb images don't have a MODULE row */
1092 if (image
->tables
[MONO_TABLE_MODULE
].rows
) {
1093 image
->module_name
= mono_metadata_string_heap (image
,
1094 mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_MODULE
],
1095 0, MONO_MODULE_NAME
));
1100 pe_image_load_tables (MonoImage
*image
)
1106 pe_image_match (MonoImage
*image
)
1108 if (image
->raw_data
[0] == 'M' && image
->raw_data
[1] == 'Z')
1113 static const MonoImageLoader pe_loader
= {
1115 pe_image_load_pe_data
,
1116 pe_image_load_cli_data
,
1117 pe_image_load_tables
,
1121 install_pe_loader (void)
1123 mono_install_image_loader (&pe_loader
);
1129 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1130 Mono provides its own implementation of those assemblies so it's safe to do so.
1132 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1134 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1136 This is to be removed once a proper fix is shipped through nuget.
1138 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1139 If any assemblies are added/removed, then this should be regenerated with:
1141 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1146 SYS_RT_INTEROP_RUNTIME_INFO
= 0, //System.Runtime.InteropServices.RuntimeInformation
1147 SYS_GLOBALIZATION_EXT
= 1, //System.Globalization.Extensions
1148 SYS_IO_COMPRESSION
= 2, //System.IO.Compression
1149 SYS_NET_HTTP
= 3, //System.Net.Http
1150 SYS_TEXT_ENC_CODEPAGES
= 4, //System.Text.Encoding.CodePages
1151 SYS_THREADING_OVERLAPPED
= 5, //System.Threading.Overlapped
1152 } IgnoredAssemblyNames
;
1157 const char guid
[40];
1162 guint16 major
, minor
, build
, revision
;
1163 } IgnoredAssemblyVersion
;
1165 static const char *ignored_assemblies_file_names
[] = {
1166 "System.Runtime.InteropServices.RuntimeInformation.dll",
1167 "System.Globalization.Extensions.dll",
1168 "System.IO.Compression.dll",
1169 "System.Net.Http.dll",
1170 "System.Text.Encoding.CodePages.dll",
1171 "System.Threading.Overlapped.dll"
1174 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { (int)HASH, NAME, GUID }
1176 static const IgnoredAssembly ignored_assemblies
[] = {
1177 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP
, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1178 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT
, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1179 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO
, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1180 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO
, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1181 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO
, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1182 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION
, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1183 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION
, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1184 IGNORED_ASSEMBLY (0x1FB3F8E8, SYS_GLOBALIZATION_EXT
, "B9BA8638-25D2-4A3B-B91F-16B3D3799861", "2.1.100-preview-62617-01 net461"),
1185 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP
, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1186 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP
, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1187 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED
, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1188 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT
, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1189 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT
, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1190 IGNORED_ASSEMBLY (0x3E21E75A, SYS_TEXT_ENC_CODEPAGES
, "67D3A14A-8F55-4C9F-9699-EDD0876369DA", "4.5.0 net461"),
1191 IGNORED_ASSEMBLY (0x420963C4, SYS_NET_HTTP
, "084B071E-1637-4B3F-B7CD-6CEF28A6E4AE", "4.3.4 net46"),
1192 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT
, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1193 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO
, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1194 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP
, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1195 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT
, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1196 IGNORED_ASSEMBLY (0x4E906129, SYS_NET_HTTP
, "27BBDD4C-EAF0-4A95-B172-EE502D76A725", "2.1.100-preview-62617-01 net461"),
1197 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION
, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1198 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION
, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1199 IGNORED_ASSEMBLY (0x66CEDA9, SYS_THREADING_OVERLAPPED
, "A0439CB6-A5E6-4813-A76C-13F92ADDDED5", "2.1.100-preview-62617-01 net461"),
1200 IGNORED_ASSEMBLY (0x6AE7C015, SYS_IO_COMPRESSION
, "35DD20B5-8766-476B-B5D2-0EA16EF0A946", "2.1.100-preview-62617-01 net461"),
1201 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED
, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46"),
1202 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO
, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1203 IGNORED_ASSEMBLY (0x765A8E04, SYS_RT_INTEROP_RUNTIME_INFO
, "E46BA45E-6A63-47CD-AF70-2C3016AFF75A", "2.1.100-preview-62617-01 net461"),
1204 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO
, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1205 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED
, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1206 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED
, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1207 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP
, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1208 IGNORED_ASSEMBLY (0x8BFCB05D, SYS_THREADING_OVERLAPPED
, "82D565AC-E41C-4E29-9939-C031C88EDBDD", "2.1.100-preview-62617-01 net471"),
1209 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO
, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1210 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED
, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1211 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES
, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1212 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP
, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1213 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP
, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1214 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO
, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1215 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO
, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1216 IGNORED_ASSEMBLY (0xA99E866F, SYS_NET_HTTP
, "41ACE450-8F44-455A-97AC-0679E5462071", "2.1.100-preview-62617-01 net471"),
1217 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED
, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1218 IGNORED_ASSEMBLY (0xAF2093B8, SYS_TEXT_ENC_CODEPAGES
, "D2B4F262-31A4-4E80-9CFB-26A2249A735E", "4.5.1 net461"),
1219 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION
, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1220 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION
, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1221 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO
, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1222 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED
, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1223 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO
, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1224 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP
, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1225 IGNORED_ASSEMBLY (0xD3ABE53A, SYS_RT_INTEROP_RUNTIME_INFO
, "488CE209-4E5D-40E7-BE8C-F81F2B99F13A", "2.1.100-preview-62617-01 net462"),
1226 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP
, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1227 IGNORED_ASSEMBLY (0xE16ECCCD, SYS_GLOBALIZATION_EXT
, "1A2B9B2A-02F5-4C78-AB0C-7C6D2795CE2B", "2.1.100-preview-62617-01 net471"),
1228 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT
, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1229 IGNORED_ASSEMBLY (0xE758DAD4, SYS_IO_COMPRESSION
, "8DBD1669-97BC-4190-9BD8-738561193741", "2.1.100-preview-62617-01 net471"),
1230 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES
, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1231 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT
, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1232 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES
, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1233 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP
, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1234 IGNORED_ASSEMBLY (0xFC67D3A7, SYS_RT_INTEROP_RUNTIME_INFO
, "FD6C8616-C1D8-43F9-AC17-A1C48A45FDA2", "2.1.100-preview-62617-01 net47")
1238 static const char *ignored_assemblies_names
[] = {
1239 "System.Runtime.InteropServices.RuntimeInformation",
1240 "System.Globalization.Extensions",
1241 "System.IO.Compression",
1243 "System.Text.Encoding.CodePages",
1244 "System.Threading.Overlapped"
1247 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { NAME, MAJOR, MINOR, BUILD, REVISION }
1249 static const IgnoredAssemblyVersion ignored_assembly_versions
[] = {
1250 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 0, 0, 0),
1251 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 0, 1, 0),
1252 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 0, 2, 0),
1253 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 1, 0, 0),
1254 IGNORED_ASM_VER (SYS_IO_COMPRESSION
, 4, 1, 0, 0),
1255 IGNORED_ASM_VER (SYS_IO_COMPRESSION
, 4, 1, 2, 0),
1256 IGNORED_ASM_VER (SYS_IO_COMPRESSION
, 4, 2, 0, 0),
1257 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 0, 0),
1258 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 0, 1),
1259 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 0),
1260 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 1),
1261 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 2),
1262 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 3),
1263 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 2, 0, 0),
1264 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO
, 4, 0, 0, 0),
1265 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO
, 4, 0, 1, 0),
1266 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO
, 4, 0, 2, 0),
1267 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 0, 1, 0),
1268 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 0, 2, 0),
1269 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 1, 0, 0),
1270 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 1, 1, 0),
1271 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 0, 0, 0),
1272 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 0, 1, 0),
1273 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 0, 2, 0),
1274 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 1, 0, 0)
1278 mono_assembly_is_problematic_version (const char *name
, guint16 major
, guint16 minor
, guint16 build
, guint16 revision
)
1280 for (int i
= 0; i
< G_N_ELEMENTS (ignored_assembly_versions
); ++i
) {
1281 if (ignored_assembly_versions
[i
].major
!= major
||
1282 ignored_assembly_versions
[i
].minor
!= minor
||
1283 ignored_assembly_versions
[i
].build
!= build
||
1284 ignored_assembly_versions
[i
].revision
!= revision
)
1286 if (!strcmp (ignored_assemblies_names
[ignored_assembly_versions
[i
].assembly_name
], name
))
1294 static void Main () {
1297 for (int i = 0; i < str.Length; ++i)
1298 h = ((h << 5) + h) ^ str[i];
1300 Console.WriteLine ("{0:X}", h);
1304 hash_guid (const char *str
)
1308 h
= ((h
<< 5) + h
) ^ *str
;
1316 mono_is_problematic_image (MonoImage
*image
)
1318 int h
= hash_guid (image
->guid
);
1320 //TODO make this more cache effiecient.
1321 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1322 for (int i
= 0; i
< G_N_ELEMENTS (ignored_assemblies
); ++i
) {
1323 if (ignored_assemblies
[i
].hash
== h
&& !strcmp (image
->guid
, ignored_assemblies
[i
].guid
)) {
1324 const char *needle
= ignored_assemblies_file_names
[ignored_assemblies
[i
].assembly_name
];
1325 size_t needle_len
= strlen (needle
);
1326 size_t asm_len
= strlen (image
->name
);
1327 if (asm_len
> needle_len
&& !g_ascii_strcasecmp (image
->name
+ (asm_len
- needle_len
), needle
))
1335 do_mono_image_load (MonoImage
*image
, MonoImageOpenStatus
*status
,
1336 gboolean care_about_cli
, gboolean care_about_pecoff
)
1341 MONO_PROFILER_RAISE (image_loading
, (image
));
1343 mono_image_init (image
);
1345 if (!image
->metadata_only
) {
1346 for (l
= image_loaders
; l
; l
= l
->next
) {
1347 MonoImageLoader
*loader
= (MonoImageLoader
*)l
->data
;
1348 if (loader
->match (image
)) {
1349 image
->loader
= loader
;
1353 if (!image
->loader
) {
1355 *status
= MONO_IMAGE_IMAGE_INVALID
;
1360 *status
= MONO_IMAGE_IMAGE_INVALID
;
1362 if (care_about_pecoff
== FALSE
)
1365 if (image
->loader
== &pe_loader
&& !mono_verifier_verify_pe_data (image
, error
))
1368 if (!mono_image_load_pe_data (image
))
1371 image
->loader
= (MonoImageLoader
*)&pe_loader
;
1374 if (care_about_cli
== FALSE
) {
1378 if (image
->loader
== &pe_loader
&& !image
->metadata_only
&& !mono_verifier_verify_cli_data (image
, error
))
1381 if (!mono_image_load_cli_data (image
))
1384 if (!image
->ref_only
&& mono_is_problematic_image (image
)) {
1385 if (image
->load_from_context
) {
1386 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Loading problematic image %s", image
->name
);
1388 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Denying load of problematic image %s", image
->name
);
1390 *status
= MONO_IMAGE_IMAGE_INVALID
;
1395 if (image
->loader
== &pe_loader
&& !image
->metadata_only
&& !mono_verifier_verify_table_data (image
, error
))
1398 mono_image_load_names (image
);
1400 mono_image_load_time_date_stamp (image
);
1402 #ifndef ENABLE_NETCORE
1403 load_modules (image
);
1407 MONO_PROFILER_RAISE (image_loaded
, (image
));
1409 *status
= MONO_IMAGE_OK
;
1414 if (!is_ok (error
)) {
1415 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Could not load image %s due to %s", image
->name
, mono_error_get_message (error
));
1416 mono_error_cleanup (error
);
1418 MONO_PROFILER_RAISE (image_failed
, (image
));
1419 mono_image_close (image
);
1424 mono_image_storage_trypublish (MonoImageStorage
*candidate
, MonoImageStorage
**out_storage
)
1427 mono_images_storage_lock ();
1428 MonoImageStorage
*val
= (MonoImageStorage
*)g_hash_table_lookup (images_storage_hash
, candidate
->key
);
1430 mono_refcount_inc (val
);
1434 g_hash_table_insert (images_storage_hash
, candidate
->key
, candidate
);
1437 mono_images_storage_unlock ();
1442 mono_image_storage_unpublish (MonoImageStorage
*storage
)
1444 mono_images_storage_lock ();
1445 g_assert (storage
->ref
.ref
== 0);
1447 MonoImageStorage
*published
= (MonoImageStorage
*)g_hash_table_lookup (images_storage_hash
, storage
->key
);
1448 if (published
== storage
) {
1449 g_hash_table_remove (images_storage_hash
, storage
->key
);
1452 mono_images_storage_unlock ();
1456 mono_image_storage_tryaddref (const char *key
, MonoImageStorage
**found
)
1458 gboolean result
= FALSE
;
1459 mono_images_storage_lock ();
1460 MonoImageStorage
*val
= (MonoImageStorage
*)g_hash_table_lookup (images_storage_hash
, key
);
1462 mono_refcount_inc (val
);
1466 mono_images_storage_unlock ();
1471 mono_image_storage_dtor (gpointer self
)
1473 MonoImageStorage
*storage
= (MonoImageStorage
*)self
;
1475 mono_image_storage_unpublish (storage
);
1478 if (storage
->is_module_handle
&& !storage
->has_entry_point
) {
1479 mono_images_lock ();
1480 FreeLibrary ((HMODULE
) storage
->raw_data
);
1481 mono_images_unlock ();
1485 if (storage
->raw_buffer_used
) {
1486 if (storage
->raw_data
!= NULL
) {
1488 if (storage
->fileio_used
)
1489 mono_file_unmap_fileio (storage
->raw_data
, storage
->raw_data_handle
);
1492 mono_file_unmap (storage
->raw_data
, storage
->raw_data_handle
);
1495 if (storage
->raw_data_allocated
) {
1496 g_free (storage
->raw_data
);
1499 g_free (storage
->key
);
1505 mono_image_storage_close (MonoImageStorage
*storage
)
1507 mono_refcount_dec (storage
);
1511 mono_image_init_raw_data (MonoImage
*image
, const MonoImageStorage
*storage
)
1515 image
->raw_data
= storage
->raw_data
;
1516 image
->raw_data_len
= storage
->raw_data_len
;
1520 static MonoImageStorage
*
1521 mono_image_storage_open (const char *fname
)
1525 key
= mono_path_resolve_symlinks (fname
);
1526 MonoImageStorage
*published_storage
= NULL
;
1527 if (mono_image_storage_tryaddref (key
, &published_storage
)) {
1529 return published_storage
;
1533 if ((filed
= mono_file_map_open (fname
)) == NULL
){
1534 if (IS_PORTABILITY_SET
) {
1535 gchar
*ffname
= mono_portability_find_file (fname
, TRUE
);
1537 filed
= mono_file_map_open (ffname
);
1542 if (filed
== NULL
) {
1548 MonoImageStorage
*storage
= g_new0 (MonoImageStorage
, 1);
1549 mono_refcount_init (storage
, mono_image_storage_dtor
);
1550 storage
->raw_buffer_used
= TRUE
;
1551 storage
->raw_data_len
= mono_file_map_size (filed
);
1552 storage
->raw_data
= (char*)mono_file_map (storage
->raw_data_len
, MONO_MMAP_READ
|MONO_MMAP_PRIVATE
, mono_file_map_fd (filed
), 0, &storage
->raw_data_handle
);
1553 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1554 if (!storage
->raw_data
) {
1555 storage
->fileio_used
= TRUE
;
1556 storage
->raw_data
= (char *)mono_file_map_fileio (storage
->raw_data_len
, MONO_MMAP_READ
|MONO_MMAP_PRIVATE
, mono_file_map_fd (filed
), 0, &storage
->raw_data_handle
);
1559 mono_file_map_close (filed
);
1563 MonoImageStorage
*other_storage
= NULL
;
1564 if (!mono_image_storage_trypublish (storage
, &other_storage
)) {
1565 mono_image_storage_close (storage
);
1566 storage
= other_storage
;
1571 static MonoImageStorage
*
1572 mono_image_storage_new_raw_data (char *datac
, guint32 data_len
, gboolean raw_data_allocated
, const char *name
)
1574 char *key
= (name
== NULL
) ? g_strdup_printf ("data-%p", datac
) : g_strdup (name
);
1575 MonoImageStorage
*published_storage
= NULL
;
1576 if (mono_image_storage_tryaddref (key
, &published_storage
)) {
1578 return published_storage
;
1581 MonoImageStorage
*storage
= g_new0 (MonoImageStorage
, 1);
1582 mono_refcount_init (storage
, mono_image_storage_dtor
);
1584 storage
->raw_data
= datac
;
1585 storage
->raw_data_len
= data_len
;
1586 storage
->raw_data_allocated
= raw_data_allocated
;
1589 MonoImageStorage
*other_storage
= NULL
;
1590 if (!mono_image_storage_trypublish (storage
, &other_storage
)) {
1591 mono_image_storage_close (storage
);
1592 storage
= other_storage
;
1598 do_mono_image_open (MonoAssemblyLoadContext
*alc
, const char *fname
, MonoImageOpenStatus
*status
,
1599 gboolean care_about_cli
, gboolean care_about_pecoff
, gboolean refonly
, gboolean metadata_only
, gboolean load_from_context
)
1601 MonoCLIImageInfo
*iinfo
;
1604 MonoImageStorage
*storage
= mono_image_storage_open (fname
);
1608 *status
= MONO_IMAGE_ERROR_ERRNO
;
1612 image
= g_new0 (MonoImage
, 1);
1613 image
->storage
= storage
;
1614 mono_image_init_raw_data (image
, storage
);
1615 if (!image
->raw_data
) {
1616 mono_image_storage_close (image
->storage
);
1619 *status
= MONO_IMAGE_IMAGE_INVALID
;
1622 iinfo
= g_new0 (MonoCLIImageInfo
, 1);
1623 image
->image_info
= iinfo
;
1624 image
->name
= mono_path_resolve_symlinks (fname
);
1625 image
->filename
= g_strdup (image
->name
);
1626 image
->ref_only
= refonly
;
1627 image
->metadata_only
= metadata_only
;
1628 image
->load_from_context
= load_from_context
;
1629 image
->ref_count
= 1;
1630 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1631 image
->core_clr_platform_code
= mono_security_core_clr_determine_platform_image (image
);
1632 #ifdef ENABLE_NETCORE
1635 return do_mono_image_load (image
, status
, care_about_cli
, care_about_pecoff
);
1639 * mono_image_loaded_full:
1640 * \param name path or assembly name of the image to load
1641 * \param refonly Check with respect to reflection-only loads?
1643 * This routine verifies that the given image is loaded.
1644 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1646 * \returns the loaded \c MonoImage, or NULL on failure.
1649 mono_image_loaded_full (const char *name
, gboolean refonly
)
1652 MONO_ENTER_GC_UNSAFE
;
1653 MonoDomain
*domain
= mono_domain_get ();
1654 result
= mono_image_loaded_internal (mono_domain_default_alc (domain
), name
, refonly
);
1655 MONO_EXIT_GC_UNSAFE
;
1660 * mono_image_loaded_internal:
1661 * \param alc The AssemblyLoadContext that should be checked
1662 * \param name path or assembly name of the image to load
1663 * \param refonly Check with respect to reflection-only loads?
1665 * This routine verifies that the given image is loaded.
1666 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1668 * \returns the loaded \c MonoImage, or NULL on failure.
1671 mono_image_loaded_internal (MonoAssemblyLoadContext
*alc
, const char *name
, gboolean refonly
)
1673 MonoLoadedImages
*li
= mono_alc_get_loaded_images (alc
);
1676 mono_images_lock ();
1677 res
= (MonoImage
*)g_hash_table_lookup (mono_loaded_images_get_hash (li
, refonly
), name
);
1679 res
= (MonoImage
*)g_hash_table_lookup (mono_loaded_images_get_by_name_hash (li
, refonly
), name
);
1680 mono_images_unlock ();
1686 * mono_image_loaded:
1687 * \param name path or assembly name of the image to load
1688 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1689 * \returns the loaded \c MonoImage, or NULL on failure.
1692 mono_image_loaded (const char *name
)
1695 MONO_ENTER_GC_UNSAFE
;
1696 MonoDomain
*domain
= mono_domain_get ();
1697 result
= mono_image_loaded_internal (mono_domain_default_alc (domain
), name
, FALSE
);
1698 MONO_EXIT_GC_UNSAFE
;
1708 find_by_guid (gpointer key
, gpointer val
, gpointer user_data
)
1710 GuidData
*data
= (GuidData
*)user_data
;
1715 image
= (MonoImage
*)val
;
1716 if (strcmp (data
->guid
, mono_image_get_guid (image
)) == 0)
1721 mono_image_loaded_by_guid_internal (const char *guid
, gboolean refonly
);
1724 * mono_image_loaded_by_guid_full:
1726 * Looks only in the global loaded images hash, will miss assemblies loaded
1727 * into an AssemblyLoadContext.
1730 mono_image_loaded_by_guid_full (const char *guid
, gboolean refonly
)
1732 return mono_image_loaded_by_guid_internal (guid
, refonly
);
1736 * mono_image_loaded_by_guid_internal:
1738 * Do not use. Looks only in the global loaded images hash, will miss Assembly
1742 mono_image_loaded_by_guid_internal (const char *guid
, gboolean refonly
)
1744 #ifndef ENABLE_NETCORE
1746 GHashTable
*loaded_images
= mono_loaded_images_get_hash (mono_get_global_loaded_images (), refonly
);
1750 mono_images_lock ();
1751 g_hash_table_foreach (loaded_images
, find_by_guid
, &data
);
1752 mono_images_unlock ();
1755 /* TODO: Maybe implement this for netcore by searching only the default ALC of the current domain */
1761 * mono_image_loaded_by_guid:
1763 * Looks only in the global loaded images hash, will miss assemblies loaded
1764 * into an AssemblyLoadContext.
1767 mono_image_loaded_by_guid (const char *guid
)
1769 return mono_image_loaded_by_guid_internal (guid
, FALSE
);
1773 register_image (MonoLoadedImages
*li
, MonoImage
*image
, gboolean
*problematic
)
1776 GHashTable
*loaded_images
= mono_loaded_images_get_hash (li
, image
->ref_only
);
1778 mono_images_lock ();
1779 image2
= (MonoImage
*)g_hash_table_lookup (loaded_images
, image
->name
);
1782 /* Somebody else beat us to it */
1783 mono_image_addref (image2
);
1784 mono_images_unlock ();
1785 mono_image_close (image
);
1789 GHashTable
*loaded_images_by_name
= mono_loaded_images_get_by_name_hash (li
, image
->ref_only
);
1790 g_hash_table_insert (loaded_images
, image
->name
, image
);
1791 if (image
->assembly_name
&& (g_hash_table_lookup (loaded_images_by_name
, image
->assembly_name
) == NULL
))
1792 g_hash_table_insert (loaded_images_by_name
, (char *) image
->assembly_name
, image
);
1793 mono_images_unlock ();
1795 if (mono_is_problematic_image (image
)) {
1796 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Registering %s, problematic image '%s'", image
->ref_only
? "REFONLY" : "default", image
->name
);
1798 *problematic
= TRUE
;
1804 mono_image_open_from_data_internal (MonoAssemblyLoadContext
*alc
, char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean metadata_only
, const char *name
)
1806 MonoCLIImageInfo
*iinfo
;
1810 if (!data
|| !data_len
) {
1812 *status
= MONO_IMAGE_IMAGE_INVALID
;
1817 datac
= (char *)g_try_malloc (data_len
);
1820 *status
= MONO_IMAGE_ERROR_ERRNO
;
1823 memcpy (datac
, data
, data_len
);
1826 MonoImageStorage
*storage
= mono_image_storage_new_raw_data (datac
, data_len
, need_copy
, name
);
1827 image
= g_new0 (MonoImage
, 1);
1828 image
->storage
= storage
;
1829 mono_image_init_raw_data (image
, storage
);
1830 image
->name
= (name
== NULL
) ? g_strdup_printf ("data-%p", datac
) : g_strdup(name
);
1831 image
->filename
= name
? g_strdup (name
) : NULL
;
1832 iinfo
= g_new0 (MonoCLIImageInfo
, 1);
1833 image
->image_info
= iinfo
;
1834 image
->ref_only
= refonly
;
1835 image
->metadata_only
= metadata_only
;
1836 image
->ref_count
= 1;
1837 #ifdef ENABLE_NETCORE
1841 image
= do_mono_image_load (image
, status
, TRUE
, TRUE
);
1845 return register_image (mono_alc_get_loaded_images (alc
), image
, NULL
);
1849 * mono_image_open_from_data_with_name:
1852 mono_image_open_from_data_with_name (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
, gboolean refonly
, const char *name
)
1855 MONO_ENTER_GC_UNSAFE
;
1856 MonoDomain
*domain
= mono_domain_get ();
1857 result
= mono_image_open_from_data_internal (mono_domain_default_alc (domain
), data
, data_len
, need_copy
, status
, refonly
, FALSE
, name
);
1858 MONO_EXIT_GC_UNSAFE
;
1863 * mono_image_open_from_data_full:
1866 mono_image_open_from_data_full (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
, gboolean refonly
)
1869 MONO_ENTER_GC_UNSAFE
;
1870 MonoDomain
*domain
= mono_domain_get ();
1871 result
= mono_image_open_from_data_internal (mono_domain_default_alc (domain
), data
, data_len
, need_copy
, status
, refonly
, FALSE
, NULL
);
1872 MONO_EXIT_GC_UNSAFE
;
1877 * mono_image_open_from_data:
1880 mono_image_open_from_data (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
)
1883 MONO_ENTER_GC_UNSAFE
;
1884 MonoDomain
*domain
= mono_domain_get ();
1885 result
= mono_image_open_from_data_internal (mono_domain_default_alc (domain
), data
, data_len
, need_copy
, status
, FALSE
, FALSE
, NULL
);
1886 MONO_EXIT_GC_UNSAFE
;
1891 static MonoImageStorage
*
1892 mono_image_storage_open_from_module_handle (HMODULE module_handle
, const char *fname
, gboolean has_entry_point
)
1894 char *key
= g_strdup (fname
);
1895 MonoImageStorage
*published_storage
= NULL
;
1896 if (mono_image_storage_tryaddref (key
, &published_storage
)) {
1898 return published_storage
;
1901 MonoImageStorage
*storage
= g_new0 (MonoImageStorage
, 1);
1902 mono_refcount_init (storage
, mono_image_storage_dtor
);
1903 storage
->raw_data
= (char*) module_handle
;
1904 storage
->is_module_handle
= TRUE
;
1905 storage
->has_entry_point
= has_entry_point
;
1909 MonoImageStorage
*other_storage
= NULL
;
1910 if (!mono_image_storage_trypublish (storage
, &other_storage
)) {
1911 mono_image_storage_close (storage
);
1912 storage
= other_storage
;
1917 /* fname is not duplicated. */
1919 mono_image_open_from_module_handle (MonoAssemblyLoadContext
*alc
, HMODULE module_handle
, char* fname
, gboolean has_entry_point
, MonoImageOpenStatus
* status
)
1922 MonoCLIImageInfo
* iinfo
;
1924 MonoImageStorage
*storage
= mono_image_storage_open_from_module_handle (module_handle
, fname
, has_entry_point
);
1925 image
= g_new0 (MonoImage
, 1);
1926 image
->storage
= storage
;
1927 mono_image_init_raw_data (image
, storage
);
1928 iinfo
= g_new0 (MonoCLIImageInfo
, 1);
1929 image
->image_info
= iinfo
;
1930 image
->name
= fname
;
1931 image
->filename
= g_strdup (image
->name
);
1932 image
->ref_count
= has_entry_point
? 0 : 1;
1933 #ifdef ENABLE_NETCORE
1937 image
= do_mono_image_load (image
, status
, TRUE
, TRUE
);
1941 return register_image (mono_alc_get_loaded_images (alc
), image
, NULL
);
1946 * mono_image_open_full:
1949 mono_image_open_full (const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
)
1951 MonoAssemblyLoadContext
*alc
= mono_domain_default_alc (mono_domain_get ());
1952 return mono_image_open_a_lot (alc
, fname
, status
, refonly
, FALSE
);
1956 mono_image_open_a_lot_parameterized (MonoLoadedImages
*li
, MonoAssemblyLoadContext
*alc
, const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean load_from_context
, gboolean
*problematic
)
1959 GHashTable
*loaded_images
= mono_loaded_images_get_hash (li
, refonly
);
1962 g_return_val_if_fail (fname
!= NULL
, NULL
);
1965 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1966 // then assemblies need to be loaded with LoadLibrary:
1967 if (!refonly
&& coree_module_handle
) {
1968 HMODULE module_handle
;
1969 gunichar2
*fname_utf16
;
1972 absfname
= mono_path_resolve_symlinks (fname
);
1975 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1976 mono_images_lock ();
1977 image
= (MonoImage
*)g_hash_table_lookup (loaded_images
, absfname
);
1978 if (image
) { // Image already loaded
1979 if (!load_from_context
&& mono_is_problematic_image (image
)) {
1980 // If we previously loaded a problematic image, don't
1981 // return it if we're not in LoadFrom context.
1983 // Note: this has an interaction with
1984 // mono_problematic_image_reprobe - at that point we
1985 // have a problematic image opened, but we don't want
1986 // to see it again when we go searching for an image
1988 mono_images_unlock ();
1991 *problematic
= TRUE
;
1995 g_assert (m_image_is_module_handle (image
));
1996 if (m_image_has_entry_point (image
) && image
->ref_count
== 0) {
1997 /* Increment reference count on images loaded outside of the runtime. */
1998 fname_utf16
= g_utf8_to_utf16 (absfname
, -1, NULL
, NULL
, NULL
);
1999 /* The image is already loaded because _CorDllMain removes images from the hash. */
2000 module_handle
= LoadLibrary (fname_utf16
);
2001 g_assert (module_handle
== (HMODULE
) image
->raw_data
);
2003 mono_image_addref (image
);
2004 mono_images_unlock ();
2006 g_free (fname_utf16
);
2011 // Image not loaded, load it now
2012 fname_utf16
= g_utf8_to_utf16 (absfname
, -1, NULL
, NULL
, NULL
);
2013 module_handle
= MonoLoadImage (fname_utf16
);
2014 if (status
&& module_handle
== NULL
)
2015 last_error
= mono_w32error_get_last ();
2017 /* mono_image_open_from_module_handle is called by _CorDllMain. */
2018 image
= (MonoImage
*)g_hash_table_lookup (loaded_images
, absfname
);
2020 mono_image_addref (image
);
2021 mono_images_unlock ();
2023 g_free (fname_utf16
);
2025 if (module_handle
== NULL
) {
2029 if (last_error
== ERROR_BAD_EXE_FORMAT
|| last_error
== STATUS_INVALID_IMAGE_FORMAT
) {
2031 *status
= MONO_IMAGE_IMAGE_INVALID
;
2033 if (last_error
== ERROR_FILE_NOT_FOUND
|| last_error
== ERROR_PATH_NOT_FOUND
)
2034 mono_set_errno (ENOENT
);
2043 g_assert (m_image_is_module_handle (image
));
2044 g_assert (m_image_has_entry_point (image
));
2049 return mono_image_open_from_module_handle (alc
, module_handle
, absfname
, FALSE
, status
);
2053 absfname
= mono_path_resolve_symlinks (fname
);
2056 * The easiest solution would be to do all the loading inside the mutex,
2057 * but that would lead to scalability problems. So we let the loading
2058 * happen outside the mutex, and if multiple threads happen to load
2059 * the same image, we discard all but the first copy.
2061 mono_images_lock ();
2062 image
= (MonoImage
*)g_hash_table_lookup (loaded_images
, absfname
);
2065 if (image
) { // Image already loaded
2066 if (!refonly
&& !load_from_context
&& mono_is_problematic_image (image
)) {
2067 // If we previously loaded a problematic image, don't
2068 // return it if we're not in LoadFrom context.
2070 // Note: this has an interaction with
2071 // mono_problematic_image_reprobe - at that point we
2072 // have a problematic image opened, but we don't want
2073 // to see it again when we go searching for an image
2075 mono_images_unlock ();
2076 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Not returning problematic image '%s' refcount=%d", image
->name
, image
->ref_count
);
2078 *problematic
= TRUE
;
2081 mono_image_addref (image
);
2082 mono_images_unlock ();
2085 mono_images_unlock ();
2087 // Image not loaded, load it now
2088 image
= do_mono_image_open (alc
, fname
, status
, TRUE
, TRUE
, refonly
, FALSE
, load_from_context
);
2092 return register_image (li
, image
, problematic
);
2096 mono_image_open_a_lot (MonoAssemblyLoadContext
*alc
, const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean load_from_context
)
2098 MonoLoadedImages
*li
= mono_alc_get_loaded_images (alc
);
2099 return mono_image_open_a_lot_parameterized (li
, alc
, fname
, status
, refonly
, load_from_context
, NULL
);
2103 mono_is_problematic_file (const char *fname
)
2105 MonoImageOpenStatus status
;
2106 gboolean problematic
= FALSE
;
2108 MonoDomain
*domain
= mono_domain_get ();
2109 MonoAssemblyLoadContext
*alc
= mono_domain_default_alc (domain
);
2110 MonoLoadedImages
*li
= mono_alc_get_loaded_images (alc
);
2111 MonoImage
*opened
= mono_image_open_a_lot_parameterized (li
, alc
, fname
, &status
, FALSE
, FALSE
, &problematic
);
2113 mono_image_close (opened
);
2121 * \param fname filename that points to the module we want to open
2122 * \param status An error condition is returned in this field
2123 * \returns An open image of type \c MonoImage or NULL on error.
2124 * The caller holds a temporary reference to the returned image which should be cleared
2125 * when no longer needed by calling \c mono_image_close.
2126 * if NULL, then check the value of \p status for details on the error
2129 mono_image_open (const char *fname
, MonoImageOpenStatus
*status
)
2131 MonoAssemblyLoadContext
*alc
= mono_domain_default_alc (mono_domain_get ());
2132 return mono_image_open_a_lot (alc
, fname
, status
, FALSE
, FALSE
);
2136 * mono_pe_file_open:
2137 * \param fname filename that points to the module we want to open
2138 * \param status An error condition is returned in this field
2139 * \returns An open image of type \c MonoImage or NULL on error. if
2140 * NULL, then check the value of \p status for details on the error.
2141 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
2142 * It's just a PE file loader, used for \c FileVersionInfo. It also does
2143 * not use the image cache.
2146 mono_pe_file_open (const char *fname
, MonoImageOpenStatus
*status
)
2148 g_return_val_if_fail (fname
!= NULL
, NULL
);
2149 MonoAssemblyLoadContext
*alc
= mono_domain_default_alc (mono_domain_get ());
2151 return do_mono_image_open (alc
, fname
, status
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
);
2155 * mono_image_open_raw
2156 * \param fname filename that points to the module we want to open
2157 * \param status An error condition is returned in this field
2158 * \returns an image without loading neither pe or cli data.
2159 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
2162 mono_image_open_raw (MonoAssemblyLoadContext
*alc
, const char *fname
, MonoImageOpenStatus
*status
)
2164 g_return_val_if_fail (fname
!= NULL
, NULL
);
2166 return do_mono_image_open (alc
, fname
, status
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
);
2170 * mono_image_open_metadata_only:
2172 * Open an image which contains metadata only without a PE header.
2175 mono_image_open_metadata_only (MonoAssemblyLoadContext
*alc
, const char *fname
, MonoImageOpenStatus
*status
)
2177 return do_mono_image_open (alc
, fname
, status
, TRUE
, TRUE
, FALSE
, TRUE
, FALSE
);
2181 * mono_image_fixup_vtable:
2184 mono_image_fixup_vtable (MonoImage
*image
)
2187 MonoCLIImageInfo
*iinfo
;
2189 MonoVTableFixup
*vtfixup
;
2195 g_assert (m_image_is_module_handle (image
));
2197 iinfo
= image
->image_info
;
2198 de
= &iinfo
->cli_cli_header
.ch_vtable_fixups
;
2199 if (!de
->rva
|| !de
->size
)
2201 vtfixup
= (MonoVTableFixup
*) mono_image_rva_map (image
, de
->rva
);
2205 count
= de
->size
/ sizeof (MonoVTableFixup
);
2207 if (!vtfixup
->rva
|| !vtfixup
->count
)
2210 slot
= mono_image_rva_map (image
, vtfixup
->rva
);
2212 slot_type
= vtfixup
->type
;
2213 slot_count
= vtfixup
->count
;
2214 if (slot_type
& VTFIXUP_TYPE_32BIT
)
2215 while (slot_count
--) {
2216 *((guint32
*) slot
) = (guint32
)(gsize
)mono_marshal_get_vtfixup_ftnptr (image
, *((guint32
*) slot
), slot_type
);
2217 slot
= ((guint32
*) slot
) + 1;
2219 else if (slot_type
& VTFIXUP_TYPE_64BIT
)
2220 while (slot_count
--) {
2221 *((guint64
*) slot
) = (guint64
) mono_marshal_get_vtfixup_ftnptr (image
, *((guint64
*) slot
), slot_type
);
2222 slot
= ((guint32
*) slot
) + 1;
2225 g_assert_not_reached();
2230 g_assert_not_reached();
2235 free_hash_table (gpointer key
, gpointer val
, gpointer user_data
)
2237 g_hash_table_destroy ((GHashTable
*)val
);
2242 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
2244 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
2249 free_array_cache_entry (gpointer key
, gpointer val
, gpointer user_data
)
2251 g_slist_free ((GSList
*)val
);
2255 * mono_image_addref:
2256 * \param image The image file we wish to add a reference to
2257 * Increases the reference count of an image.
2260 mono_image_addref (MonoImage
*image
)
2262 mono_atomic_inc_i32 (&image
->ref_count
);
2266 mono_dynamic_stream_reset (MonoDynamicStream
* stream
)
2268 stream
->alloc_size
= stream
->index
= stream
->offset
= 0;
2269 g_free (stream
->data
);
2270 stream
->data
= NULL
;
2272 g_hash_table_destroy (stream
->hash
);
2273 stream
->hash
= NULL
;
2278 free_hash (GHashTable
*hash
)
2281 g_hash_table_destroy (hash
);
2285 mono_wrapper_caches_free (MonoWrapperCaches
*cache
)
2287 free_hash (cache
->delegate_invoke_cache
);
2288 free_hash (cache
->delegate_begin_invoke_cache
);
2289 free_hash (cache
->delegate_end_invoke_cache
);
2290 free_hash (cache
->runtime_invoke_signature_cache
);
2292 free_hash (cache
->delegate_abstract_invoke_cache
);
2294 free_hash (cache
->runtime_invoke_method_cache
);
2295 free_hash (cache
->managed_wrapper_cache
);
2297 free_hash (cache
->native_wrapper_cache
);
2298 free_hash (cache
->native_wrapper_aot_cache
);
2299 free_hash (cache
->native_wrapper_check_cache
);
2300 free_hash (cache
->native_wrapper_aot_check_cache
);
2302 free_hash (cache
->native_func_wrapper_aot_cache
);
2303 free_hash (cache
->remoting_invoke_cache
);
2304 free_hash (cache
->synchronized_cache
);
2305 free_hash (cache
->unbox_wrapper_cache
);
2306 free_hash (cache
->cominterop_invoke_cache
);
2307 free_hash (cache
->cominterop_wrapper_cache
);
2308 free_hash (cache
->thunk_invoke_cache
);
2312 mono_image_close_except_pools_all (MonoImage
**images
, int image_count
)
2314 for (int i
= 0; i
< image_count
; ++i
) {
2316 if (!mono_image_close_except_pools (images
[i
]))
2323 * Returns whether mono_image_close_finish() must be called as well.
2324 * We must unload images in two steps because clearing the domain in
2325 * SGen requires the class metadata to be intact, but we need to free
2326 * the mono_g_hash_tables in case a collection occurs during domain
2327 * unloading and the roots would trip up the GC.
2330 mono_image_close_except_pools (MonoImage
*image
)
2334 g_return_val_if_fail (image
!= NULL
, FALSE
);
2337 if (!mono_loaded_images_remove_image (image
))
2341 if (m_image_is_module_handle (image
) && m_image_has_entry_point (image
)) {
2342 mono_images_lock ();
2343 if (image
->ref_count
== 0) {
2344 /* Image will be closed by _CorDllMain. */
2345 FreeLibrary ((HMODULE
) image
->raw_data
);
2346 mono_images_unlock ();
2349 mono_images_unlock ();
2353 MONO_PROFILER_RAISE (image_unloading
, (image
));
2355 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading image %s [%p].", image
->name
, image
);
2357 mono_image_invoke_unload_hook (image
);
2359 mono_metadata_clean_for_image (image
);
2362 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2363 * assemblies, so we can't release these references in mono_assembly_close () since the
2364 * MonoImage might outlive its associated MonoAssembly.
2366 if (image
->references
&& !image_is_dynamic (image
)) {
2367 for (i
= 0; i
< image
->nreferences
; i
++) {
2368 if (image
->references
[i
] && image
->references
[i
] != REFERENCE_MISSING
) {
2369 if (!mono_assembly_close_except_image_pools (image
->references
[i
]))
2370 image
->references
[i
] = NULL
;
2374 if (image
->references
) {
2375 g_free (image
->references
);
2376 image
->references
= NULL
;
2380 /* a MonoDynamicImage doesn't have any storage */
2381 g_assert (image_is_dynamic (image
) || image
->storage
!= NULL
);
2383 if (image
->storage
&& m_image_is_raw_data_allocated (image
)) {
2384 /* FIXME: do we need this? (image is disposed anyway) */
2385 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2386 MonoCLIImageInfo
*ii
= image
->image_info
;
2388 if ((image
->raw_metadata
> image
->raw_data
) &&
2389 (image
->raw_metadata
<= (image
->raw_data
+ image
->raw_data_len
)))
2390 image
->raw_metadata
= NULL
;
2392 for (i
= 0; i
< ii
->cli_section_count
; i
++)
2393 if (((char*)(ii
->cli_sections
[i
]) > image
->raw_data
) &&
2394 ((char*)(ii
->cli_sections
[i
]) <= ((char*)image
->raw_data
+ image
->raw_data_len
)))
2395 ii
->cli_sections
[i
] = NULL
;
2400 mono_image_storage_close (image
->storage
);
2402 if (debug_assembly_unload
) {
2403 char *old_name
= image
->name
;
2404 image
->name
= g_strdup_printf ("%s - UNLOADED", old_name
);
2407 g_free (image
->name
);
2408 g_free (image
->filename
);
2409 g_free (image
->guid
);
2410 g_free (image
->version
);
2413 if (image
->method_cache
)
2414 g_hash_table_destroy (image
->method_cache
);
2415 if (image
->methodref_cache
)
2416 g_hash_table_destroy (image
->methodref_cache
);
2417 mono_internal_hash_table_destroy (&image
->class_cache
);
2418 mono_conc_hashtable_destroy (image
->field_cache
);
2419 if (image
->array_cache
) {
2420 g_hash_table_foreach (image
->array_cache
, free_array_cache_entry
, NULL
);
2421 g_hash_table_destroy (image
->array_cache
);
2423 if (image
->szarray_cache
)
2424 g_hash_table_destroy (image
->szarray_cache
);
2425 if (image
->ptr_cache
)
2426 g_hash_table_destroy (image
->ptr_cache
);
2427 if (image
->name_cache
) {
2428 g_hash_table_foreach (image
->name_cache
, free_hash_table
, NULL
);
2429 g_hash_table_destroy (image
->name_cache
);
2432 free_hash (image
->delegate_bound_static_invoke_cache
);
2433 free_hash (image
->ldfld_wrapper_cache
);
2434 free_hash (image
->ldflda_wrapper_cache
);
2435 free_hash (image
->stfld_wrapper_cache
);
2436 free_hash (image
->isinst_cache
);
2437 free_hash (image
->castclass_cache
);
2438 free_hash (image
->icall_wrapper_cache
);
2439 free_hash (image
->proxy_isinst_cache
);
2440 if (image
->var_gparam_cache
)
2441 mono_conc_hashtable_destroy (image
->var_gparam_cache
);
2442 if (image
->mvar_gparam_cache
)
2443 mono_conc_hashtable_destroy (image
->mvar_gparam_cache
);
2444 free_hash (image
->wrapper_param_names
);
2445 free_hash (image
->pinvoke_scopes
);
2446 free_hash (image
->pinvoke_scope_filenames
);
2447 free_hash (image
->native_func_wrapper_cache
);
2448 mono_conc_hashtable_destroy (image
->typespec_cache
);
2449 free_hash (image
->weak_field_indexes
);
2451 mono_wrapper_caches_free (&image
->wrapper_caches
);
2453 for (i
= 0; i
< image
->gshared_types_len
; ++i
)
2454 free_hash (image
->gshared_types
[i
]);
2455 g_free (image
->gshared_types
);
2457 /* The ownership of signatures is not well defined */
2458 g_hash_table_destroy (image
->memberref_signatures
);
2459 g_hash_table_destroy (image
->method_signatures
);
2461 if (image
->rgctx_template_hash
)
2462 g_hash_table_destroy (image
->rgctx_template_hash
);
2464 if (image
->property_hash
)
2465 mono_property_hash_destroy (image
->property_hash
);
2468 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2469 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2471 g_assert (!image
->reflection_info_unregister_classes
|| mono_runtime_is_shutting_down ());
2472 image
->reflection_info_unregister_classes
= NULL
;
2474 if (image
->interface_bitset
) {
2475 mono_unload_interface_ids (image
->interface_bitset
);
2476 mono_bitset_free (image
->interface_bitset
);
2478 if (image
->image_info
){
2479 MonoCLIImageInfo
*ii
= image
->image_info
;
2481 g_free (ii
->cli_section_tables
);
2482 g_free (ii
->cli_sections
);
2483 g_free (image
->image_info
);
2486 mono_image_close_except_pools_all (image
->files
, image
->file_count
);
2487 mono_image_close_except_pools_all (image
->modules
, image
->module_count
);
2488 g_free (image
->modules_loaded
);
2490 mono_os_mutex_destroy (&image
->szarray_cache_lock
);
2491 mono_os_mutex_destroy (&image
->lock
);
2493 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2494 if (image_is_dynamic (image
)) {
2495 /* Dynamic images are GC_MALLOCed */
2496 g_free ((char*)image
->module_name
);
2497 mono_dynamic_image_free ((MonoDynamicImage
*)image
);
2500 MONO_PROFILER_RAISE (image_unloaded
, (image
));
2506 mono_image_close_all (MonoImage
**images
, int image_count
)
2508 for (int i
= 0; i
< image_count
; ++i
) {
2510 mono_image_close_finish (images
[i
]);
2517 mono_image_close_finish (MonoImage
*image
)
2521 if (image
->references
&& !image_is_dynamic (image
)) {
2522 for (i
= 0; i
< image
->nreferences
; i
++) {
2523 if (image
->references
[i
] && image
->references
[i
] != REFERENCE_MISSING
)
2524 mono_assembly_close_finish (image
->references
[i
]);
2527 g_free (image
->references
);
2528 image
->references
= NULL
;
2531 mono_image_close_all (image
->files
, image
->file_count
);
2532 mono_image_close_all (image
->modules
, image
->module_count
);
2534 #ifndef DISABLE_PERFCOUNTERS
2535 /* FIXME: use an explicit subtraction method as soon as it's available */
2536 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, -1 * mono_mempool_get_allocated (image
->mempool
));
2539 if (!image_is_dynamic (image
)) {
2540 if (debug_assembly_unload
)
2541 mono_mempool_invalidate (image
->mempool
);
2543 mono_mempool_destroy (image
->mempool
);
2547 if (debug_assembly_unload
)
2548 mono_mempool_invalidate (image
->mempool
);
2550 mono_mempool_destroy (image
->mempool
);
2551 mono_dynamic_image_free_image ((MonoDynamicImage
*)image
);
2558 * \param image The image file we wish to close
2559 * Closes an image file, deallocates all memory consumed and
2560 * unmaps all possible sections of the file
2563 mono_image_close (MonoImage
*image
)
2565 if (mono_image_close_except_pools (image
))
2566 mono_image_close_finish (image
);
2570 * mono_image_strerror:
2571 * \param status an code indicating the result from a recent operation
2572 * \returns a string describing the error
2575 mono_image_strerror (MonoImageOpenStatus status
)
2580 case MONO_IMAGE_ERROR_ERRNO
:
2581 return strerror (errno
);
2582 case MONO_IMAGE_IMAGE_INVALID
:
2583 return "File does not contain a valid CIL image";
2584 case MONO_IMAGE_MISSING_ASSEMBLYREF
:
2585 return "An assembly was referenced, but could not be found";
2587 return "Internal error";
2591 mono_image_walk_resource_tree (MonoCLIImageInfo
*info
, guint32 res_id
,
2592 guint32 lang_id
, gunichar2
*name
,
2593 MonoPEResourceDirEntry
*entry
,
2594 MonoPEResourceDir
*root
, guint32 level
)
2596 gboolean is_string
, is_dir
;
2597 guint32 name_offset
, dir_offset
;
2599 /* Level 0 holds a directory entry for each type of resource
2600 * (identified by ID or name).
2602 * Level 1 holds a directory entry for each named resource
2603 * item, and each "anonymous" item of a particular type of
2606 * Level 2 holds a directory entry for each language pointing to
2609 is_string
= MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry
);
2610 name_offset
= MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry
);
2612 is_dir
= MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry
);
2613 dir_offset
= MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry
);
2618 } else if (level
==1) {
2619 if (res_id
!= name_offset
)
2623 is_string
==TRUE
&& name
!=lookup (name_offset
)) {
2627 } else if (level
==2) {
2628 if (is_string
|| (lang_id
!= 0 && name_offset
!= lang_id
))
2631 g_assert_not_reached ();
2635 MonoPEResourceDir
*res_dir
=(MonoPEResourceDir
*)(((char *)root
)+dir_offset
);
2636 MonoPEResourceDirEntry
*sub_entries
=(MonoPEResourceDirEntry
*)(res_dir
+1);
2639 entries
= GUINT16_FROM_LE (res_dir
->res_named_entries
) + GUINT16_FROM_LE (res_dir
->res_id_entries
);
2641 for(i
=0; i
<entries
; i
++) {
2642 MonoPEResourceDirEntry
*sub_entry
=&sub_entries
[i
];
2645 ret
=mono_image_walk_resource_tree (info
, res_id
,
2656 MonoPEResourceDataEntry
*data_entry
=(MonoPEResourceDataEntry
*)((char *)(root
)+dir_offset
);
2657 MonoPEResourceDataEntry
*res
;
2659 res
= g_new0 (MonoPEResourceDataEntry
, 1);
2661 res
->rde_data_offset
= GUINT32_TO_LE (data_entry
->rde_data_offset
);
2662 res
->rde_size
= GUINT32_TO_LE (data_entry
->rde_size
);
2663 res
->rde_codepage
= GUINT32_TO_LE (data_entry
->rde_codepage
);
2664 res
->rde_reserved
= GUINT32_TO_LE (data_entry
->rde_reserved
);
2671 * mono_image_lookup_resource:
2672 * \param image the image to look up the resource in
2673 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2674 * \param lang_id The language id.
2675 * \param name the resource name to lookup.
2676 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2677 * of the given resource. The caller should free it using \c g_free when no longer
2681 mono_image_lookup_resource (MonoImage
*image
, guint32 res_id
, guint32 lang_id
, gunichar2
*name
)
2683 MonoCLIImageInfo
*info
;
2684 MonoDotNetHeader
*header
;
2685 MonoPEDatadir
*datadir
;
2686 MonoPEDirEntry
*rsrc
;
2687 MonoPEResourceDir
*resource_dir
;
2688 MonoPEResourceDirEntry
*res_entries
;
2695 mono_image_ensure_section_idx (image
, MONO_SECTION_RSRC
);
2697 info
= (MonoCLIImageInfo
*)image
->image_info
;
2702 header
=&info
->cli_header
;
2707 datadir
=&header
->datadir
;
2712 rsrc
=&datadir
->pe_resource_table
;
2717 resource_dir
=(MonoPEResourceDir
*)mono_image_rva_map (image
, rsrc
->rva
);
2718 if(resource_dir
==NULL
) {
2722 entries
= GUINT16_FROM_LE (resource_dir
->res_named_entries
) + GUINT16_FROM_LE (resource_dir
->res_id_entries
);
2723 res_entries
=(MonoPEResourceDirEntry
*)(resource_dir
+1);
2725 for(i
=0; i
<entries
; i
++) {
2726 MonoPEResourceDirEntry
*entry
=&res_entries
[i
];
2729 ret
=mono_image_walk_resource_tree (info
, res_id
, lang_id
,
2730 name
, entry
, resource_dir
,
2741 * mono_image_get_entry_point:
2742 * \param image the image where the entry point will be looked up.
2743 * Use this routine to determine the metadata token for method that
2744 * has been flagged as the entry point.
2745 * \returns the token for the entry point method in the image
2748 mono_image_get_entry_point (MonoImage
*image
)
2750 return image
->image_info
->cli_cli_header
.ch_entry_point
;
2754 * mono_image_get_resource:
2755 * \param image the image where the resource will be looked up.
2756 * \param offset The offset to add to the resource
2757 * \param size a pointer to an int where the size of the resource will be stored
2759 * This is a low-level routine that fetches a resource from the
2760 * metadata that starts at a given \p offset. The \p size parameter is
2761 * filled with the data field as encoded in the metadata.
2763 * \returns the pointer to the resource whose offset is \p offset.
2766 mono_image_get_resource (MonoImage
*image
, guint32 offset
, guint32
*size
)
2768 MonoCLIImageInfo
*iinfo
= image
->image_info
;
2769 MonoCLIHeader
*ch
= &iinfo
->cli_cli_header
;
2772 if (!ch
->ch_resources
.rva
|| offset
+ 4 > ch
->ch_resources
.size
)
2775 data
= mono_image_rva_map (image
, ch
->ch_resources
.rva
);
2780 *size
= read32 (data
);
2785 // Returning NULL with no error set will be interpeted as "not found"
2787 mono_image_load_file_for_image_checked (MonoImage
*image
, int fileidx
, MonoError
*error
)
2789 char *base_dir
, *name
;
2791 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_FILE
];
2797 if (fileidx
< 1 || fileidx
> t
->rows
)
2800 mono_image_lock (image
);
2801 if (image
->files
&& image
->files
[fileidx
- 1]) {
2802 mono_image_unlock (image
);
2803 return image
->files
[fileidx
- 1];
2805 mono_image_unlock (image
);
2807 fname_id
= mono_metadata_decode_row_col (t
, fileidx
- 1, MONO_FILE_NAME
);
2808 fname
= mono_metadata_string_heap (image
, fname_id
);
2809 base_dir
= g_path_get_dirname (image
->name
);
2810 name
= g_build_filename (base_dir
, fname
, (const char*)NULL
);
2811 res
= mono_image_open (name
, NULL
);
2815 mono_image_lock (image
);
2816 if (image
->files
&& image
->files
[fileidx
- 1]) {
2817 MonoImage
*old
= res
;
2818 res
= image
->files
[fileidx
- 1];
2819 mono_image_unlock (image
);
2820 mono_image_close (old
);
2823 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2824 if (!assign_assembly_parent_for_netmodule (res
, image
, error
)) {
2825 mono_image_unlock (image
);
2826 mono_image_close (res
);
2830 for (i
= 0; i
< res
->module_count
; ++i
) {
2831 if (res
->modules
[i
] && !res
->modules
[i
]->assembly
)
2832 res
->modules
[i
]->assembly
= image
->assembly
;
2835 if (!image
->files
) {
2836 image
->files
= g_new0 (MonoImage
*, t
->rows
);
2837 image
->file_count
= t
->rows
;
2839 image
->files
[fileidx
- 1] = res
;
2840 mono_image_unlock (image
);
2841 /* vtable fixup can't happen with the image lock held */
2843 if (m_image_is_module_handle (res
))
2844 mono_image_fixup_vtable (res
);
2855 * mono_image_load_file_for_image:
2858 mono_image_load_file_for_image (MonoImage
*image
, int fileidx
)
2861 MonoImage
*result
= mono_image_load_file_for_image_checked (image
, fileidx
, error
);
2862 mono_error_assert_ok (error
);
2867 * mono_image_get_strong_name:
2868 * \param image a MonoImage
2869 * \param size a \c guint32 pointer, or NULL.
2871 * If the image has a strong name, and \p size is not NULL, the value
2872 * pointed to by size will have the size of the strong name.
2874 * \returns NULL if the image does not have a strong name, or a
2875 * pointer to the public key.
2878 mono_image_get_strong_name (MonoImage
*image
, guint32
*size
)
2880 MonoCLIImageInfo
*iinfo
= image
->image_info
;
2881 MonoPEDirEntry
*de
= &iinfo
->cli_cli_header
.ch_strong_name
;
2884 if (!de
->size
|| !de
->rva
)
2886 data
= mono_image_rva_map (image
, de
->rva
);
2895 * mono_image_strong_name_position:
2896 * \param image a \c MonoImage
2897 * \param size a \c guint32 pointer, or NULL.
2899 * If the image has a strong name, and \p size is not NULL, the value
2900 * pointed to by size will have the size of the strong name.
2902 * \returns the position within the image file where the strong name
2906 mono_image_strong_name_position (MonoImage
*image
, guint32
*size
)
2908 MonoCLIImageInfo
*iinfo
= image
->image_info
;
2909 MonoPEDirEntry
*de
= &iinfo
->cli_cli_header
.ch_strong_name
;
2914 if (!de
->size
|| !de
->rva
)
2916 pos
= mono_cli_rva_image_map (image
, de
->rva
);
2917 return pos
== INVALID_ADDRESS
? 0 : pos
;
2921 * mono_image_get_public_key:
2922 * \param image a \c MonoImage
2923 * \param size a \c guint32 pointer, or NULL.
2925 * This is used to obtain the public key in the \p image.
2927 * If the image has a public key, and \p size is not NULL, the value
2928 * pointed to by size will have the size of the public key.
2930 * \returns NULL if the image does not have a public key, or a pointer
2931 * to the public key.
2934 mono_image_get_public_key (MonoImage
*image
, guint32
*size
)
2939 if (image_is_dynamic (image
)) {
2941 *size
= ((MonoDynamicImage
*)image
)->public_key_len
;
2942 return (char*)((MonoDynamicImage
*)image
)->public_key
;
2944 if (image
->tables
[MONO_TABLE_ASSEMBLY
].rows
!= 1)
2946 tok
= mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_ASSEMBLY
], 0, MONO_ASSEMBLY_PUBLIC_KEY
);
2949 pubkey
= mono_metadata_blob_heap (image
, tok
);
2950 len
= mono_metadata_decode_blob_size (pubkey
, &pubkey
);
2957 * mono_image_get_name:
2958 * \param name a \c MonoImage
2959 * \returns the name of the assembly.
2962 mono_image_get_name (MonoImage
*image
)
2964 return image
->assembly_name
;
2968 * mono_image_get_filename:
2969 * \param image a \c MonoImage
2970 * Used to get the filename that hold the actual \c MonoImage
2971 * \returns the filename.
2974 mono_image_get_filename (MonoImage
*image
)
2980 * mono_image_get_guid:
2983 mono_image_get_guid (MonoImage
*image
)
2989 * mono_image_get_table_info:
2991 const MonoTableInfo
*
2992 mono_image_get_table_info (MonoImage
*image
, int table_id
)
2994 if (table_id
< 0 || table_id
>= MONO_TABLE_NUM
)
2996 return &image
->tables
[table_id
];
3000 * mono_image_get_table_rows:
3003 mono_image_get_table_rows (MonoImage
*image
, int table_id
)
3005 if (table_id
< 0 || table_id
>= MONO_TABLE_NUM
)
3007 return image
->tables
[table_id
].rows
;
3011 * mono_table_info_get_rows:
3014 mono_table_info_get_rows (const MonoTableInfo
*table
)
3020 * mono_image_get_assembly:
3021 * \param image the \c MonoImage .
3022 * Use this routine to get the assembly that owns this image.
3023 * \returns the assembly that holds this image.
3026 mono_image_get_assembly (MonoImage
*image
)
3028 return image
->assembly
;
3032 * mono_image_is_dynamic:
3033 * \param image the \c MonoImage
3035 * Determines if the given image was created dynamically through the
3036 * \c System.Reflection.Emit API
3037 * \returns TRUE if the image was created dynamically, FALSE if not.
3040 mono_image_is_dynamic (MonoImage
*image
)
3042 return image_is_dynamic (image
);
3046 * mono_image_has_authenticode_entry:
3047 * \param image the \c MonoImage
3048 * Use this routine to determine if the image has a Authenticode
3049 * Certificate Table.
3050 * \returns TRUE if the image contains an authenticode entry in the PE
3054 mono_image_has_authenticode_entry (MonoImage
*image
)
3056 MonoCLIImageInfo
*iinfo
= image
->image_info
;
3057 MonoDotNetHeader
*header
= &iinfo
->cli_header
;
3060 MonoPEDirEntry
*de
= &header
->datadir
.pe_certificate_table
;
3061 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
3062 return ((de
->rva
!= 0) && (de
->size
> 8));
3066 mono_image_alloc (MonoImage
*image
, guint size
)
3070 #ifndef DISABLE_PERFCOUNTERS
3071 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, size
);
3073 mono_image_lock (image
);
3074 res
= mono_mempool_alloc (image
->mempool
, size
);
3075 mono_image_unlock (image
);
3081 mono_image_alloc0 (MonoImage
*image
, guint size
)
3085 #ifndef DISABLE_PERFCOUNTERS
3086 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, size
);
3088 mono_image_lock (image
);
3089 res
= mono_mempool_alloc0 (image
->mempool
, size
);
3090 mono_image_unlock (image
);
3096 mono_image_strdup (MonoImage
*image
, const char *s
)
3100 #ifndef DISABLE_PERFCOUNTERS
3101 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, (gint32
)strlen (s
));
3103 mono_image_lock (image
);
3104 res
= mono_mempool_strdup (image
->mempool
, s
);
3105 mono_image_unlock (image
);
3111 mono_image_strdup_vprintf (MonoImage
*image
, const char *format
, va_list args
)
3114 mono_image_lock (image
);
3115 buf
= mono_mempool_strdup_vprintf (image
->mempool
, format
, args
);
3116 mono_image_unlock (image
);
3117 #ifndef DISABLE_PERFCOUNTERS
3118 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, (gint32
)strlen (buf
));
3124 mono_image_strdup_printf (MonoImage
*image
, const char *format
, ...)
3129 va_start (args
, format
);
3130 buf
= mono_image_strdup_vprintf (image
, format
, args
);
3136 mono_g_list_prepend_image (MonoImage
*image
, GList
*list
, gpointer data
)
3140 new_list
= (GList
*)mono_image_alloc (image
, sizeof (GList
));
3141 new_list
->data
= data
;
3142 new_list
->prev
= list
? list
->prev
: NULL
;
3143 new_list
->next
= list
;
3146 new_list
->prev
->next
= new_list
;
3148 list
->prev
= new_list
;
3154 mono_g_slist_append_image (MonoImage
*image
, GSList
*list
, gpointer data
)
3158 new_list
= (GSList
*)mono_image_alloc (image
, sizeof (GSList
));
3159 new_list
->data
= data
;
3160 new_list
->next
= NULL
;
3162 return g_slist_concat (list
, new_list
);
3166 mono_image_lock (MonoImage
*image
)
3168 mono_locks_os_acquire (&image
->lock
, ImageDataLock
);
3172 mono_image_unlock (MonoImage
*image
)
3174 mono_locks_os_release (&image
->lock
, ImageDataLock
);
3179 * mono_image_property_lookup:
3180 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
3182 * LOCKING: Takes the image lock
3185 mono_image_property_lookup (MonoImage
*image
, gpointer subject
, guint32 property
)
3189 mono_image_lock (image
);
3190 res
= mono_property_hash_lookup (image
->property_hash
, subject
, property
);
3191 mono_image_unlock (image
);
3197 * mono_image_property_insert:
3198 * Insert a new property \p property with value \p value on \p subject in \p
3199 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
3201 * LOCKING: Takes the image lock
3204 mono_image_property_insert (MonoImage
*image
, gpointer subject
, guint32 property
, gpointer value
)
3206 CHECKED_METADATA_STORE_LOCAL (image
->mempool
, value
);
3207 mono_image_lock (image
);
3208 mono_property_hash_insert (image
->property_hash
, subject
, property
, value
);
3209 mono_image_unlock (image
);
3213 * mono_image_property_remove:
3214 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
3216 * LOCKING: Takes the image lock
3219 mono_image_property_remove (MonoImage
*image
, gpointer subject
)
3221 mono_image_lock (image
);
3222 mono_property_hash_remove_object (image
->property_hash
, subject
);
3223 mono_image_unlock (image
);
3227 mono_image_append_class_to_reflection_info_set (MonoClass
*klass
)
3229 MonoImage
*image
= m_class_get_image (klass
);
3230 g_assert (image_is_dynamic (image
));
3231 mono_image_lock (image
);
3232 image
->reflection_info_unregister_classes
= g_slist_prepend_mempool (image
->mempool
, image
->reflection_info_unregister_classes
, klass
);
3233 mono_image_unlock (image
);