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/w32process-internals.h>
48 #include <sys/types.h>
53 #include <mono/metadata/w32error.h>
55 #define INVALID_ADDRESS 0xffffffff
57 // Amount initially reserved in each image's mempool.
58 // FIXME: This number is arbitrary, a more practical number should be found
59 #define INITIAL_IMAGE_SIZE 512
62 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
63 * There are four, for all combinations of [look up by path or assembly name?]
64 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
68 IMAGES_HASH_PATH_REFONLY
= 1,
70 IMAGES_HASH_NAME_REFONLY
= 3,
73 static GHashTable
*loaded_images_hashes
[4] = {NULL
, NULL
, NULL
, NULL
};
76 get_loaded_images_hash (gboolean refonly
)
78 int idx
= refonly
? IMAGES_HASH_PATH_REFONLY
: IMAGES_HASH_PATH
;
79 return loaded_images_hashes
[idx
];
83 get_loaded_images_by_name_hash (gboolean refonly
)
85 int idx
= refonly
? IMAGES_HASH_NAME_REFONLY
: IMAGES_HASH_NAME
;
86 return loaded_images_hashes
[idx
];
89 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
90 // Can be used on modules loaded through either the "file" or "module" mechanism
92 assign_assembly_parent_for_netmodule (MonoImage
*image
, MonoImage
*assemblyImage
, MonoError
*error
)
95 MonoAssembly
*assembly
= assemblyImage
->assembly
;
98 // Assembly currently assigned
99 MonoAssembly
*assemblyOld
= image
->assembly
;
101 if (assemblyOld
== assembly
)
103 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
);
106 gpointer result
= mono_atomic_xchg_ptr((gpointer
*)&image
->assembly
, assembly
);
107 if (result
== assembly
)
112 static gboolean debug_assembly_unload
= FALSE
;
114 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
115 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
116 #define mono_images_storage_lock() do { if (mutex_inited) mono_os_mutex_lock (&images_storage_mutex); } while (0)
117 #define mono_images_storage_unlock() do { if (mutex_inited) mono_os_mutex_unlock (&images_storage_mutex); } while (0)
118 static gboolean mutex_inited
;
119 static mono_mutex_t images_mutex
;
120 static mono_mutex_t images_storage_mutex
;
122 /* Maps string keys to MonoImageStorage values.
124 * The MonoImageStorage in the hash owns the key.
126 static GHashTable
*images_storage_hash
;
128 static void install_pe_loader (void);
130 typedef struct ImageUnloadHook ImageUnloadHook
;
131 struct ImageUnloadHook
{
132 MonoImageUnloadFunc func
;
136 static GSList
*image_unload_hooks
;
139 mono_install_image_unload_hook (MonoImageUnloadFunc func
, gpointer user_data
)
141 ImageUnloadHook
*hook
;
143 g_return_if_fail (func
!= NULL
);
145 hook
= g_new0 (ImageUnloadHook
, 1);
147 hook
->user_data
= user_data
;
148 image_unload_hooks
= g_slist_prepend (image_unload_hooks
, hook
);
152 mono_remove_image_unload_hook (MonoImageUnloadFunc func
, gpointer user_data
)
155 ImageUnloadHook
*hook
;
157 for (l
= image_unload_hooks
; l
; l
= l
->next
) {
158 hook
= (ImageUnloadHook
*)l
->data
;
160 if (hook
->func
== func
&& hook
->user_data
== user_data
) {
162 image_unload_hooks
= g_slist_delete_link (image_unload_hooks
, l
);
169 mono_image_invoke_unload_hook (MonoImage
*image
)
172 ImageUnloadHook
*hook
;
174 for (l
= image_unload_hooks
; l
; l
= l
->next
) {
175 hook
= (ImageUnloadHook
*)l
->data
;
177 hook
->func (image
, hook
->user_data
);
181 static GSList
*image_loaders
;
184 mono_install_image_loader (const MonoImageLoader
*loader
)
186 image_loaders
= g_slist_prepend (image_loaders
, (MonoImageLoader
*)loader
);
189 /* returns offset relative to image->raw_data */
191 mono_cli_rva_image_map (MonoImage
*image
, guint32 addr
)
193 MonoCLIImageInfo
*iinfo
= image
->image_info
;
194 const int top
= iinfo
->cli_section_count
;
195 MonoSectionTable
*tables
= iinfo
->cli_section_tables
;
198 if (image
->metadata_only
)
201 for (i
= 0; i
< top
; i
++){
202 if ((addr
>= tables
->st_virtual_address
) &&
203 (addr
< tables
->st_virtual_address
+ tables
->st_raw_data_size
)){
205 if (m_image_is_module_handle (image
))
208 return addr
- tables
->st_virtual_address
+ tables
->st_raw_data_ptr
;
212 return INVALID_ADDRESS
;
216 * mono_image_rva_map:
217 * \param image a \c MonoImage
218 * \param addr relative virtual address (RVA)
220 * This is a low-level routine used by the runtime to map relative
221 * virtual address (RVA) into their location in memory.
223 * \returns the address in memory for the given RVA, or NULL if the
224 * RVA is not valid for this image.
227 mono_image_rva_map (MonoImage
*image
, guint32 addr
)
229 MonoCLIImageInfo
*iinfo
= image
->image_info
;
230 const int top
= iinfo
->cli_section_count
;
231 MonoSectionTable
*tables
= iinfo
->cli_section_tables
;
235 if (m_image_is_module_handle (image
)) {
236 if (addr
&& addr
< image
->raw_data_len
)
237 return image
->raw_data
+ addr
;
243 for (i
= 0; i
< top
; i
++){
244 if ((addr
>= tables
->st_virtual_address
) &&
245 (addr
< tables
->st_virtual_address
+ tables
->st_raw_data_size
)){
246 if (!iinfo
->cli_sections
[i
]) {
247 if (!mono_image_ensure_section_idx (image
, i
))
250 return (char*)iinfo
->cli_sections
[i
] +
251 (addr
- tables
->st_virtual_address
);
261 * Initialize the global variables used by this module.
264 mono_images_init (void)
266 mono_os_mutex_init (&images_storage_mutex
);
267 mono_os_mutex_init_recursive (&images_mutex
);
269 images_storage_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
272 for(hash_idx
= 0; hash_idx
< IMAGES_HASH_COUNT
; hash_idx
++)
273 loaded_images_hashes
[hash_idx
] = g_hash_table_new (g_str_hash
, g_str_equal
);
275 debug_assembly_unload
= g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
277 install_pe_loader ();
283 * mono_images_cleanup:
285 * Free all resources used by this module.
288 mono_images_cleanup (void)
293 mono_os_mutex_destroy (&images_mutex
);
295 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
296 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
297 g_hash_table_iter_init (&iter
, get_loaded_images_hash (FALSE
));
298 while (g_hash_table_iter_next (&iter
, NULL
, (void**)&image
))
299 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Assembly image '%s' still loaded at shutdown.", image
->name
);
302 for(hash_idx
= 0; hash_idx
< IMAGES_HASH_COUNT
; hash_idx
++)
303 g_hash_table_destroy (loaded_images_hashes
[hash_idx
]);
305 g_hash_table_destroy (images_storage_hash
);
307 mono_os_mutex_destroy (&images_storage_mutex
);
309 mutex_inited
= FALSE
;
313 * mono_image_ensure_section_idx:
314 * \param image The image we are operating on
315 * \param section section number that we will load/map into memory
317 * This routine makes sure that we have an in-memory copy of
318 * an image section (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
320 * \returns TRUE on success
323 mono_image_ensure_section_idx (MonoImage
*image
, int section
)
325 MonoCLIImageInfo
*iinfo
= image
->image_info
;
326 MonoSectionTable
*sect
;
328 g_return_val_if_fail (section
< iinfo
->cli_section_count
, FALSE
);
330 if (iinfo
->cli_sections
[section
] != NULL
)
333 sect
= &iinfo
->cli_section_tables
[section
];
335 if (sect
->st_raw_data_ptr
+ sect
->st_raw_data_size
> image
->raw_data_len
)
338 if (m_image_is_module_handle (image
))
339 iinfo
->cli_sections
[section
] = image
->raw_data
+ sect
->st_virtual_address
;
342 /* FIXME: we ignore the writable flag since we don't patch the binary */
343 iinfo
->cli_sections
[section
] = image
->raw_data
+ sect
->st_raw_data_ptr
;
348 * mono_image_ensure_section:
349 * \param image The image we are operating on
350 * \param section section name that we will load/map into memory
352 * This routine makes sure that we have an in-memory copy of
353 * an image section (.text, .rsrc, .data).
355 * \returns TRUE on success
358 mono_image_ensure_section (MonoImage
*image
, const char *section
)
360 MonoCLIImageInfo
*ii
= image
->image_info
;
363 for (i
= 0; i
< ii
->cli_section_count
; i
++){
364 if (strncmp (ii
->cli_section_tables
[i
].st_name
, section
, 8) != 0)
367 return mono_image_ensure_section_idx (image
, i
);
373 load_section_tables (MonoImage
*image
, MonoCLIImageInfo
*iinfo
, guint32 offset
)
375 const int top
= iinfo
->cli_header
.coff
.coff_sections
;
378 iinfo
->cli_section_count
= top
;
379 iinfo
->cli_section_tables
= g_new0 (MonoSectionTable
, top
);
380 iinfo
->cli_sections
= g_new0 (void *, top
);
382 for (i
= 0; i
< top
; i
++){
383 MonoSectionTable
*t
= &iinfo
->cli_section_tables
[i
];
385 if (offset
+ sizeof (MonoSectionTable
) > image
->raw_data_len
)
387 memcpy (t
, image
->raw_data
+ offset
, sizeof (MonoSectionTable
));
388 offset
+= sizeof (MonoSectionTable
);
390 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
391 t
->st_virtual_size
= GUINT32_FROM_LE (t
->st_virtual_size
);
392 t
->st_virtual_address
= GUINT32_FROM_LE (t
->st_virtual_address
);
393 t
->st_raw_data_size
= GUINT32_FROM_LE (t
->st_raw_data_size
);
394 t
->st_raw_data_ptr
= GUINT32_FROM_LE (t
->st_raw_data_ptr
);
395 t
->st_reloc_ptr
= GUINT32_FROM_LE (t
->st_reloc_ptr
);
396 t
->st_lineno_ptr
= GUINT32_FROM_LE (t
->st_lineno_ptr
);
397 t
->st_reloc_count
= GUINT16_FROM_LE (t
->st_reloc_count
);
398 t
->st_line_count
= GUINT16_FROM_LE (t
->st_line_count
);
399 t
->st_flags
= GUINT32_FROM_LE (t
->st_flags
);
401 /* consistency checks here */
408 mono_image_load_cli_header (MonoImage
*image
, MonoCLIImageInfo
*iinfo
)
412 offset
= mono_cli_rva_image_map (image
, iinfo
->cli_header
.datadir
.pe_cli_header
.rva
);
413 if (offset
== INVALID_ADDRESS
)
416 if (offset
+ sizeof (MonoCLIHeader
) > image
->raw_data_len
)
418 memcpy (&iinfo
->cli_cli_header
, image
->raw_data
+ offset
, sizeof (MonoCLIHeader
));
420 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
421 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
422 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
423 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
424 SWAP32 (iinfo
->cli_cli_header
.ch_size
);
425 SWAP32 (iinfo
->cli_cli_header
.ch_flags
);
426 SWAP32 (iinfo
->cli_cli_header
.ch_entry_point
);
427 SWAP16 (iinfo
->cli_cli_header
.ch_runtime_major
);
428 SWAP16 (iinfo
->cli_cli_header
.ch_runtime_minor
);
429 SWAPPDE (iinfo
->cli_cli_header
.ch_metadata
);
430 SWAPPDE (iinfo
->cli_cli_header
.ch_resources
);
431 SWAPPDE (iinfo
->cli_cli_header
.ch_strong_name
);
432 SWAPPDE (iinfo
->cli_cli_header
.ch_code_manager_table
);
433 SWAPPDE (iinfo
->cli_cli_header
.ch_vtable_fixups
);
434 SWAPPDE (iinfo
->cli_cli_header
.ch_export_address_table_jumps
);
435 SWAPPDE (iinfo
->cli_cli_header
.ch_eeinfo_table
);
436 SWAPPDE (iinfo
->cli_cli_header
.ch_helper_table
);
437 SWAPPDE (iinfo
->cli_cli_header
.ch_dynamic_info
);
438 SWAPPDE (iinfo
->cli_cli_header
.ch_delay_load_info
);
439 SWAPPDE (iinfo
->cli_cli_header
.ch_module_image
);
440 SWAPPDE (iinfo
->cli_cli_header
.ch_external_fixups
);
441 SWAPPDE (iinfo
->cli_cli_header
.ch_ridmap
);
442 SWAPPDE (iinfo
->cli_cli_header
.ch_debug_map
);
443 SWAPPDE (iinfo
->cli_cli_header
.ch_ip_map
);
448 /* Catch new uses of the fields that are supposed to be zero */
450 if ((iinfo
->cli_cli_header
.ch_eeinfo_table
.rva
!= 0) ||
451 (iinfo
->cli_cli_header
.ch_helper_table
.rva
!= 0) ||
452 (iinfo
->cli_cli_header
.ch_dynamic_info
.rva
!= 0) ||
453 (iinfo
->cli_cli_header
.ch_delay_load_info
.rva
!= 0) ||
454 (iinfo
->cli_cli_header
.ch_module_image
.rva
!= 0) ||
455 (iinfo
->cli_cli_header
.ch_external_fixups
.rva
!= 0) ||
456 (iinfo
->cli_cli_header
.ch_ridmap
.rva
!= 0) ||
457 (iinfo
->cli_cli_header
.ch_debug_map
.rva
!= 0) ||
458 (iinfo
->cli_cli_header
.ch_ip_map
.rva
!= 0)){
461 * No need to scare people who are testing this, I am just
462 * labelling this as a LAMESPEC
464 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
472 load_metadata_ptrs (MonoImage
*image
, MonoCLIImageInfo
*iinfo
)
474 guint32 offset
, size
;
480 offset
= mono_cli_rva_image_map (image
, iinfo
->cli_cli_header
.ch_metadata
.rva
);
481 if (offset
== INVALID_ADDRESS
)
484 size
= iinfo
->cli_cli_header
.ch_metadata
.size
;
486 if (offset
+ size
> image
->raw_data_len
)
488 image
->raw_metadata
= image
->raw_data
+ offset
;
490 /* 24.2.1: Metadata root starts here */
491 ptr
= image
->raw_metadata
;
493 if (strncmp (ptr
, "BSJB", 4) == 0){
494 guint32 version_string_len
;
497 image
->md_version_major
= read16 (ptr
);
499 image
->md_version_minor
= read16 (ptr
);
502 version_string_len
= read32 (ptr
);
504 image
->version
= g_strndup (ptr
, version_string_len
);
505 ptr
+= version_string_len
;
506 pad
= ptr
- image
->raw_metadata
;
508 ptr
+= 4 - (pad
% 4);
512 /* skip over flags */
515 streams
= read16 (ptr
);
518 for (i
= 0; i
< streams
; i
++){
519 if (strncmp (ptr
+ 8, "#~", 3) == 0){
520 image
->heap_tables
.data
= image
->raw_metadata
+ read32 (ptr
);
521 image
->heap_tables
.size
= read32 (ptr
+ 4);
523 } else if (strncmp (ptr
+ 8, "#Strings", 9) == 0){
524 image
->heap_strings
.data
= image
->raw_metadata
+ read32 (ptr
);
525 image
->heap_strings
.size
= read32 (ptr
+ 4);
527 } else if (strncmp (ptr
+ 8, "#US", 4) == 0){
528 image
->heap_us
.data
= image
->raw_metadata
+ read32 (ptr
);
529 image
->heap_us
.size
= read32 (ptr
+ 4);
531 } else if (strncmp (ptr
+ 8, "#Blob", 6) == 0){
532 image
->heap_blob
.data
= image
->raw_metadata
+ read32 (ptr
);
533 image
->heap_blob
.size
= read32 (ptr
+ 4);
535 } else if (strncmp (ptr
+ 8, "#GUID", 6) == 0){
536 image
->heap_guid
.data
= image
->raw_metadata
+ read32 (ptr
);
537 image
->heap_guid
.size
= read32 (ptr
+ 4);
539 } else if (strncmp (ptr
+ 8, "#-", 3) == 0) {
540 image
->heap_tables
.data
= image
->raw_metadata
+ read32 (ptr
);
541 image
->heap_tables
.size
= read32 (ptr
+ 4);
543 image
->uncompressed_metadata
= TRUE
;
544 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
);
545 } else if (strncmp (ptr
+ 8, "#Pdb", 5) == 0) {
546 image
->heap_pdb
.data
= image
->raw_metadata
+ read32 (ptr
);
547 image
->heap_pdb
.size
= read32 (ptr
+ 4);
550 g_message ("Unknown heap type: %s\n", ptr
+ 8);
551 ptr
+= 8 + strlen (ptr
+ 8) + 1;
553 pad
= ptr
- image
->raw_metadata
;
555 ptr
+= 4 - (pad
% 4);
558 i
= ((MonoImageLoader
*)image
->loader
)->load_tables (image
);
560 if (!image
->metadata_only
) {
561 g_assert (image
->heap_guid
.data
);
562 g_assert (image
->heap_guid
.size
>= 16);
564 image
->guid
= mono_guid_to_string ((guint8
*)image
->heap_guid
.data
);
566 /* PPDB files have no guid */
567 guint8 empty_guid
[16];
569 memset (empty_guid
, 0, sizeof (empty_guid
));
571 image
->guid
= mono_guid_to_string (empty_guid
);
578 * Load representation of logical metadata tables, from the "#~" stream
581 load_tables (MonoImage
*image
)
583 const char *heap_tables
= image
->heap_tables
.data
;
586 int valid
= 0, table
;
589 heap_sizes
= heap_tables
[6];
590 image
->idx_string_wide
= ((heap_sizes
& 0x01) == 1);
591 image
->idx_guid_wide
= ((heap_sizes
& 0x02) == 2);
592 image
->idx_blob_wide
= ((heap_sizes
& 0x04) == 4);
594 valid_mask
= read64 (heap_tables
+ 8);
595 rows
= (const guint32
*) (heap_tables
+ 24);
597 for (table
= 0; table
< 64; table
++){
598 if ((valid_mask
& ((guint64
) 1 << table
)) == 0){
599 if (table
> MONO_TABLE_LAST
)
601 image
->tables
[table
].rows
= 0;
604 if (table
> MONO_TABLE_LAST
) {
605 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
607 image
->tables
[table
].rows
= read32 (rows
);
613 image
->tables_base
= (heap_tables
+ 24) + (4 * valid
);
615 /* They must be the same */
616 g_assert ((const void *) image
->tables_base
== (const void *) rows
);
618 if (image
->heap_pdb
.size
) {
620 * Obtain token sizes from the pdb stream.
622 /* 24 = guid + entry point */
624 image
->referenced_tables
= read64 (image
->heap_pdb
.data
+ pos
);
626 image
->referenced_table_rows
= g_new0 (int, 64);
627 for (int i
= 0; i
< 64; ++i
) {
628 if (image
->referenced_tables
& ((guint64
)1 << i
)) {
629 image
->referenced_table_rows
[i
] = read32 (image
->heap_pdb
.data
+ pos
);
635 mono_metadata_compute_table_bases (image
);
640 mono_image_load_metadata (MonoImage
*image
, MonoCLIImageInfo
*iinfo
)
642 if (!load_metadata_ptrs (image
, iinfo
))
645 return load_tables (image
);
649 mono_image_check_for_module_cctor (MonoImage
*image
)
651 MonoTableInfo
*t
, *mt
;
652 t
= &image
->tables
[MONO_TABLE_TYPEDEF
];
653 mt
= &image
->tables
[MONO_TABLE_METHOD
];
654 if (image_is_dynamic (image
)) {
656 image
->checked_module_cctor
= TRUE
;
660 guint32 nameidx
= mono_metadata_decode_row_col (t
, 0, MONO_TYPEDEF_NAME
);
661 const char *name
= mono_metadata_string_heap (image
, nameidx
);
662 if (strcmp (name
, "<Module>") == 0) {
663 guint32 first_method
= mono_metadata_decode_row_col (t
, 0, MONO_TYPEDEF_METHOD_LIST
) - 1;
666 last_method
= mono_metadata_decode_row_col (t
, 1, MONO_TYPEDEF_METHOD_LIST
) - 1;
668 last_method
= mt
->rows
;
669 for (; first_method
< last_method
; first_method
++) {
670 nameidx
= mono_metadata_decode_row_col (mt
, first_method
, MONO_METHOD_NAME
);
671 name
= mono_metadata_string_heap (image
, nameidx
);
672 if (strcmp (name
, ".cctor") == 0) {
673 image
->has_module_cctor
= TRUE
;
674 image
->checked_module_cctor
= TRUE
;
680 image
->has_module_cctor
= FALSE
;
681 image
->checked_module_cctor
= TRUE
;
685 load_modules (MonoImage
*image
)
692 t
= &image
->tables
[MONO_TABLE_MODULEREF
];
693 image
->modules
= g_new0 (MonoImage
*, t
->rows
);
694 image
->modules_loaded
= g_new0 (gboolean
, t
->rows
);
695 image
->module_count
= t
->rows
;
699 * mono_image_load_module_checked:
701 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
702 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
705 mono_image_load_module_checked (MonoImage
*image
, int idx
, MonoError
*error
)
708 MonoTableInfo
*file_table
;
711 gboolean refonly
= image
->ref_only
;
712 GList
*list_iter
, *valid_modules
= NULL
;
713 MonoImageOpenStatus status
;
717 if ((image
->module_count
== 0) || (idx
> image
->module_count
|| idx
<= 0))
719 if (image
->modules_loaded
[idx
- 1])
720 return image
->modules
[idx
- 1];
722 file_table
= &image
->tables
[MONO_TABLE_FILE
];
723 for (i
= 0; i
< file_table
->rows
; i
++) {
724 guint32 cols
[MONO_FILE_SIZE
];
725 mono_metadata_decode_row (file_table
, i
, cols
, MONO_FILE_SIZE
);
726 if (cols
[MONO_FILE_FLAGS
] == FILE_CONTAINS_NO_METADATA
)
728 valid_modules
= g_list_prepend (valid_modules
, (char*)mono_metadata_string_heap (image
, cols
[MONO_FILE_NAME
]));
731 t
= &image
->tables
[MONO_TABLE_MODULEREF
];
732 base_dir
= g_path_get_dirname (image
->name
);
737 guint32 cols
[MONO_MODULEREF_SIZE
];
738 /* if there is no file table, we try to load the module... */
739 int valid
= file_table
->rows
== 0;
741 mono_metadata_decode_row (t
, idx
- 1, cols
, MONO_MODULEREF_SIZE
);
742 name
= mono_metadata_string_heap (image
, cols
[MONO_MODULEREF_NAME
]);
743 for (list_iter
= valid_modules
; list_iter
; list_iter
= list_iter
->next
) {
744 /* be safe with string dups, but we could just compare string indexes */
745 if (strcmp ((const char*)list_iter
->data
, name
) == 0) {
751 module_ref
= g_build_filename (base_dir
, name
, NULL
);
752 MonoImage
*moduleImage
= mono_image_open_full (module_ref
, &status
, refonly
);
754 if (!assign_assembly_parent_for_netmodule (moduleImage
, image
, error
)) {
755 mono_image_close (moduleImage
);
758 g_list_free (valid_modules
);
762 image
->modules
[idx
- 1] = moduleImage
;
765 if (m_image_is_module_handle (image
->modules
[idx
- 1]))
766 mono_image_fixup_vtable (image
->modules
[idx
- 1]);
768 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
774 image
->modules_loaded
[idx
- 1] = TRUE
;
777 g_list_free (valid_modules
);
779 return image
->modules
[idx
- 1];
783 * mono_image_load_module:
786 mono_image_load_module (MonoImage
*image
, int idx
)
789 MonoImage
*result
= mono_image_load_module_checked (image
, idx
, error
);
790 mono_error_assert_ok (error
);
795 class_key_extract (gpointer value
)
797 MonoClass
*klass
= (MonoClass
*)value
;
799 return GUINT_TO_POINTER (m_class_get_type_token (klass
));
803 class_next_value (gpointer value
)
805 MonoClassDef
*klass
= (MonoClassDef
*)value
;
807 return (gpointer
*)m_classdef_get_next_class_cache (klass
);
814 mono_image_init (MonoImage
*image
)
816 mono_os_mutex_init_recursive (&image
->lock
);
817 mono_os_mutex_init_recursive (&image
->szarray_cache_lock
);
819 image
->mempool
= mono_mempool_new_size (INITIAL_IMAGE_SIZE
);
820 mono_internal_hash_table_init (&image
->class_cache
,
824 image
->field_cache
= mono_conc_hashtable_new (NULL
, NULL
);
826 image
->typespec_cache
= mono_conc_hashtable_new (NULL
, NULL
);
827 image
->memberref_signatures
= g_hash_table_new (NULL
, NULL
);
828 image
->method_signatures
= g_hash_table_new (NULL
, NULL
);
830 image
->property_hash
= mono_property_hash_new ();
833 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
834 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
835 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
836 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
837 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
846 * Returns < 0 to indicate an error.
849 do_load_header (MonoImage
*image
, MonoDotNetHeader
*header
, int offset
)
851 MonoDotNetHeader64 header64
;
854 if (!m_image_is_module_handle (image
))
856 if (offset
+ sizeof (MonoDotNetHeader32
) > image
->raw_data_len
)
859 memcpy (header
, image
->raw_data
+ offset
, sizeof (MonoDotNetHeader
));
861 if (header
->pesig
[0] != 'P' || header
->pesig
[1] != 'E' || header
->pesig
[2] || header
->pesig
[3])
864 /* endian swap the fields common between PE and PE+ */
865 SWAP32 (header
->coff
.coff_time
);
866 SWAP32 (header
->coff
.coff_symptr
);
867 SWAP32 (header
->coff
.coff_symcount
);
868 SWAP16 (header
->coff
.coff_machine
);
869 SWAP16 (header
->coff
.coff_sections
);
870 SWAP16 (header
->coff
.coff_opt_header_size
);
871 SWAP16 (header
->coff
.coff_attributes
);
873 SWAP32 (header
->pe
.pe_code_size
);
874 SWAP32 (header
->pe
.pe_uninit_data_size
);
875 SWAP32 (header
->pe
.pe_rva_entry_point
);
876 SWAP32 (header
->pe
.pe_rva_code_base
);
877 SWAP32 (header
->pe
.pe_rva_data_base
);
878 SWAP16 (header
->pe
.pe_magic
);
880 /* now we are ready for the basic tests */
882 if (header
->pe
.pe_magic
== 0x10B) {
883 offset
+= sizeof (MonoDotNetHeader
);
884 SWAP32 (header
->pe
.pe_data_size
);
885 if (header
->coff
.coff_opt_header_size
!= (sizeof (MonoDotNetHeader
) - sizeof (MonoCOFFHeader
) - 4))
888 SWAP32 (header
->nt
.pe_image_base
); /* must be 0x400000 */
889 SWAP32 (header
->nt
.pe_stack_reserve
);
890 SWAP32 (header
->nt
.pe_stack_commit
);
891 SWAP32 (header
->nt
.pe_heap_reserve
);
892 SWAP32 (header
->nt
.pe_heap_commit
);
893 } else if (header
->pe
.pe_magic
== 0x20B) {
894 /* PE32+ file format */
895 if (header
->coff
.coff_opt_header_size
!= (sizeof (MonoDotNetHeader64
) - sizeof (MonoCOFFHeader
) - 4))
897 memcpy (&header64
, image
->raw_data
+ offset
, sizeof (MonoDotNetHeader64
));
898 offset
+= sizeof (MonoDotNetHeader64
);
899 /* copy the fields already swapped. the last field, pe_data_size, is missing */
900 memcpy (&header64
, header
, sizeof (MonoDotNetHeader
) - 4);
901 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
902 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
904 SWAP64 (header64
.nt
.pe_image_base
);
905 header
->nt
.pe_image_base
= header64
.nt
.pe_image_base
;
906 SWAP64 (header64
.nt
.pe_stack_reserve
);
907 header
->nt
.pe_stack_reserve
= header64
.nt
.pe_stack_reserve
;
908 SWAP64 (header64
.nt
.pe_stack_commit
);
909 header
->nt
.pe_stack_commit
= header64
.nt
.pe_stack_commit
;
910 SWAP64 (header64
.nt
.pe_heap_reserve
);
911 header
->nt
.pe_heap_reserve
= header64
.nt
.pe_heap_reserve
;
912 SWAP64 (header64
.nt
.pe_heap_commit
);
913 header
->nt
.pe_heap_commit
= header64
.nt
.pe_heap_commit
;
915 header
->nt
.pe_section_align
= header64
.nt
.pe_section_align
;
916 header
->nt
.pe_file_alignment
= header64
.nt
.pe_file_alignment
;
917 header
->nt
.pe_os_major
= header64
.nt
.pe_os_major
;
918 header
->nt
.pe_os_minor
= header64
.nt
.pe_os_minor
;
919 header
->nt
.pe_user_major
= header64
.nt
.pe_user_major
;
920 header
->nt
.pe_user_minor
= header64
.nt
.pe_user_minor
;
921 header
->nt
.pe_subsys_major
= header64
.nt
.pe_subsys_major
;
922 header
->nt
.pe_subsys_minor
= header64
.nt
.pe_subsys_minor
;
923 header
->nt
.pe_reserved_1
= header64
.nt
.pe_reserved_1
;
924 header
->nt
.pe_image_size
= header64
.nt
.pe_image_size
;
925 header
->nt
.pe_header_size
= header64
.nt
.pe_header_size
;
926 header
->nt
.pe_checksum
= header64
.nt
.pe_checksum
;
927 header
->nt
.pe_subsys_required
= header64
.nt
.pe_subsys_required
;
928 header
->nt
.pe_dll_flags
= header64
.nt
.pe_dll_flags
;
929 header
->nt
.pe_loader_flags
= header64
.nt
.pe_loader_flags
;
930 header
->nt
.pe_data_dir_count
= header64
.nt
.pe_data_dir_count
;
932 /* copy the datadir */
933 memcpy (&header
->datadir
, &header64
.datadir
, sizeof (MonoPEDatadir
));
938 /* MonoPEHeaderNT: not used yet */
939 SWAP32 (header
->nt
.pe_section_align
); /* must be 8192 */
940 SWAP32 (header
->nt
.pe_file_alignment
); /* must be 512 or 4096 */
941 SWAP16 (header
->nt
.pe_os_major
); /* must be 4 */
942 SWAP16 (header
->nt
.pe_os_minor
); /* must be 0 */
943 SWAP16 (header
->nt
.pe_user_major
);
944 SWAP16 (header
->nt
.pe_user_minor
);
945 SWAP16 (header
->nt
.pe_subsys_major
);
946 SWAP16 (header
->nt
.pe_subsys_minor
);
947 SWAP32 (header
->nt
.pe_reserved_1
);
948 SWAP32 (header
->nt
.pe_image_size
);
949 SWAP32 (header
->nt
.pe_header_size
);
950 SWAP32 (header
->nt
.pe_checksum
);
951 SWAP16 (header
->nt
.pe_subsys_required
);
952 SWAP16 (header
->nt
.pe_dll_flags
);
953 SWAP32 (header
->nt
.pe_loader_flags
);
954 SWAP32 (header
->nt
.pe_data_dir_count
);
956 /* MonoDotNetHeader: mostly unused */
957 SWAPPDE (header
->datadir
.pe_export_table
);
958 SWAPPDE (header
->datadir
.pe_import_table
);
959 SWAPPDE (header
->datadir
.pe_resource_table
);
960 SWAPPDE (header
->datadir
.pe_exception_table
);
961 SWAPPDE (header
->datadir
.pe_certificate_table
);
962 SWAPPDE (header
->datadir
.pe_reloc_table
);
963 SWAPPDE (header
->datadir
.pe_debug
);
964 SWAPPDE (header
->datadir
.pe_copyright
);
965 SWAPPDE (header
->datadir
.pe_global_ptr
);
966 SWAPPDE (header
->datadir
.pe_tls_table
);
967 SWAPPDE (header
->datadir
.pe_load_config_table
);
968 SWAPPDE (header
->datadir
.pe_bound_import
);
969 SWAPPDE (header
->datadir
.pe_iat
);
970 SWAPPDE (header
->datadir
.pe_delay_import_desc
);
971 SWAPPDE (header
->datadir
.pe_cli_header
);
972 SWAPPDE (header
->datadir
.pe_reserved
);
975 if (m_image_is_module_handle (image
))
976 image
->storage
->raw_data_len
= header
->nt
.pe_image_size
;
983 mono_image_load_pe_data (MonoImage
*image
)
985 return ((MonoImageLoader
*)image
->loader
)->load_pe_data (image
);
989 pe_image_load_pe_data (MonoImage
*image
)
991 MonoCLIImageInfo
*iinfo
;
992 MonoDotNetHeader
*header
;
993 MonoMSDOSHeader msdos
;
996 iinfo
= image
->image_info
;
997 header
= &iinfo
->cli_header
;
1000 if (!m_image_is_module_handle (image
))
1002 if (offset
+ sizeof (msdos
) > image
->raw_data_len
)
1004 memcpy (&msdos
, image
->raw_data
+ offset
, sizeof (msdos
));
1006 if (!(msdos
.msdos_sig
[0] == 'M' && msdos
.msdos_sig
[1] == 'Z'))
1009 msdos
.pe_offset
= GUINT32_FROM_LE (msdos
.pe_offset
);
1011 offset
= msdos
.pe_offset
;
1013 offset
= do_load_header (image
, header
, offset
);
1018 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1019 * we skip this test.
1020 if (header->coff.coff_machine != 0x14c)
1026 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1027 * which produces binaries with 7.0. From Sergey:
1029 * The reason is that MSVC7 uses traditional compile/link
1030 * sequence for CIL executables, and VS.NET (and Framework
1031 * SDK) includes linker version 7, that puts 7.0 in this
1032 * field. That's why it's currently not possible to load VC
1033 * binaries with Mono. This field is pretty much meaningless
1034 * anyway (what linker?).
1036 if (header
->pe
.pe_major
!= 6 || header
->pe
.pe_minor
!= 0)
1041 * FIXME: byte swap all addresses here for header.
1044 if (!load_section_tables (image
, iinfo
, offset
))
1054 mono_image_load_cli_data (MonoImage
*image
)
1056 return ((MonoImageLoader
*)image
->loader
)->load_cli_data (image
);
1060 pe_image_load_cli_data (MonoImage
*image
)
1062 MonoCLIImageInfo
*iinfo
;
1063 MonoDotNetHeader
*header
;
1065 iinfo
= image
->image_info
;
1066 header
= &iinfo
->cli_header
;
1068 /* Load the CLI header */
1069 if (!mono_image_load_cli_header (image
, iinfo
))
1072 if (!mono_image_load_metadata (image
, iinfo
))
1079 mono_image_load_time_date_stamp (MonoImage
*image
)
1081 image
->time_date_stamp
= 0;
1083 if (!image
->filename
)
1086 gunichar2
*uni_name
= g_utf8_to_utf16 (image
->filename
, -1, NULL
, NULL
, NULL
);
1087 mono_pe_file_time_date_stamp (uni_name
, &image
->time_date_stamp
);
1093 mono_image_load_names (MonoImage
*image
)
1095 /* modules don't have an assembly table row */
1096 if (image
->tables
[MONO_TABLE_ASSEMBLY
].rows
) {
1097 image
->assembly_name
= mono_metadata_string_heap (image
,
1098 mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_ASSEMBLY
],
1099 0, MONO_ASSEMBLY_NAME
));
1102 /* Portable pdb images don't have a MODULE row */
1103 if (image
->tables
[MONO_TABLE_MODULE
].rows
) {
1104 image
->module_name
= mono_metadata_string_heap (image
,
1105 mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_MODULE
],
1106 0, MONO_MODULE_NAME
));
1111 pe_image_load_tables (MonoImage
*image
)
1117 pe_image_match (MonoImage
*image
)
1119 if (image
->raw_data
[0] == 'M' && image
->raw_data
[1] == 'Z')
1124 static const MonoImageLoader pe_loader
= {
1126 pe_image_load_pe_data
,
1127 pe_image_load_cli_data
,
1128 pe_image_load_tables
,
1132 install_pe_loader (void)
1134 mono_install_image_loader (&pe_loader
);
1140 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1141 Mono provides its own implementation of those assemblies so it's safe to do so.
1143 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1145 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1147 This is to be removed once a proper fix is shipped through nuget.
1149 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1150 If any assemblies are added/removed, then this should be regenerated with:
1152 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1157 SYS_RT_INTEROP_RUNTIME_INFO
= 0, //System.Runtime.InteropServices.RuntimeInformation
1158 SYS_GLOBALIZATION_EXT
= 1, //System.Globalization.Extensions
1159 SYS_IO_COMPRESSION
= 2, //System.IO.Compression
1160 SYS_NET_HTTP
= 3, //System.Net.Http
1161 SYS_TEXT_ENC_CODEPAGES
= 4, //System.Text.Encoding.CodePages
1162 SYS_THREADING_OVERLAPPED
= 5, //System.Threading.Overlapped
1163 } IgnoredAssemblyNames
;
1168 const char guid
[40];
1173 guint16 major
, minor
, build
, revision
;
1174 } IgnoredAssemblyVersion
;
1176 static const char *ignored_assemblies_file_names
[] = {
1177 "System.Runtime.InteropServices.RuntimeInformation.dll",
1178 "System.Globalization.Extensions.dll",
1179 "System.IO.Compression.dll",
1180 "System.Net.Http.dll",
1181 "System.Text.Encoding.CodePages.dll",
1182 "System.Threading.Overlapped.dll"
1185 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { (int)HASH, NAME, GUID }
1187 static const IgnoredAssembly ignored_assemblies
[] = {
1188 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP
, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1189 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT
, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1190 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO
, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1191 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO
, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1192 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO
, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1193 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION
, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1194 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION
, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1195 IGNORED_ASSEMBLY (0x1FB3F8E8, SYS_GLOBALIZATION_EXT
, "B9BA8638-25D2-4A3B-B91F-16B3D3799861", "2.1.100-preview-62617-01 net461"),
1196 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP
, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1197 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP
, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1198 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED
, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1199 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT
, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1200 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT
, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1201 IGNORED_ASSEMBLY (0x3E21E75A, SYS_TEXT_ENC_CODEPAGES
, "67D3A14A-8F55-4C9F-9699-EDD0876369DA", "4.5.0 net461"),
1202 IGNORED_ASSEMBLY (0x420963C4, SYS_NET_HTTP
, "084B071E-1637-4B3F-B7CD-6CEF28A6E4AE", "4.3.4 net46"),
1203 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT
, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1204 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO
, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1205 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP
, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1206 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT
, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1207 IGNORED_ASSEMBLY (0x4E906129, SYS_NET_HTTP
, "27BBDD4C-EAF0-4A95-B172-EE502D76A725", "2.1.100-preview-62617-01 net461"),
1208 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION
, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1209 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION
, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1210 IGNORED_ASSEMBLY (0x66CEDA9, SYS_THREADING_OVERLAPPED
, "A0439CB6-A5E6-4813-A76C-13F92ADDDED5", "2.1.100-preview-62617-01 net461"),
1211 IGNORED_ASSEMBLY (0x6AE7C015, SYS_IO_COMPRESSION
, "35DD20B5-8766-476B-B5D2-0EA16EF0A946", "2.1.100-preview-62617-01 net461"),
1212 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED
, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46"),
1213 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO
, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1214 IGNORED_ASSEMBLY (0x765A8E04, SYS_RT_INTEROP_RUNTIME_INFO
, "E46BA45E-6A63-47CD-AF70-2C3016AFF75A", "2.1.100-preview-62617-01 net461"),
1215 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO
, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1216 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED
, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1217 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED
, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1218 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP
, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1219 IGNORED_ASSEMBLY (0x8BFCB05D, SYS_THREADING_OVERLAPPED
, "82D565AC-E41C-4E29-9939-C031C88EDBDD", "2.1.100-preview-62617-01 net471"),
1220 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO
, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1221 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED
, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1222 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES
, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1223 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP
, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1224 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP
, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1225 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO
, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1226 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO
, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1227 IGNORED_ASSEMBLY (0xA99E866F, SYS_NET_HTTP
, "41ACE450-8F44-455A-97AC-0679E5462071", "2.1.100-preview-62617-01 net471"),
1228 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED
, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1229 IGNORED_ASSEMBLY (0xAF2093B8, SYS_TEXT_ENC_CODEPAGES
, "D2B4F262-31A4-4E80-9CFB-26A2249A735E", "4.5.1 net461"),
1230 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION
, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1231 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION
, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1232 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO
, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1233 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED
, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1234 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO
, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1235 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP
, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1236 IGNORED_ASSEMBLY (0xD3ABE53A, SYS_RT_INTEROP_RUNTIME_INFO
, "488CE209-4E5D-40E7-BE8C-F81F2B99F13A", "2.1.100-preview-62617-01 net462"),
1237 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP
, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1238 IGNORED_ASSEMBLY (0xE16ECCCD, SYS_GLOBALIZATION_EXT
, "1A2B9B2A-02F5-4C78-AB0C-7C6D2795CE2B", "2.1.100-preview-62617-01 net471"),
1239 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT
, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1240 IGNORED_ASSEMBLY (0xE758DAD4, SYS_IO_COMPRESSION
, "8DBD1669-97BC-4190-9BD8-738561193741", "2.1.100-preview-62617-01 net471"),
1241 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES
, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1242 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT
, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1243 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES
, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1244 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP
, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1245 IGNORED_ASSEMBLY (0xFC67D3A7, SYS_RT_INTEROP_RUNTIME_INFO
, "FD6C8616-C1D8-43F9-AC17-A1C48A45FDA2", "2.1.100-preview-62617-01 net47")
1249 static const char *ignored_assemblies_names
[] = {
1250 "System.Runtime.InteropServices.RuntimeInformation",
1251 "System.Globalization.Extensions",
1252 "System.IO.Compression",
1254 "System.Text.Encoding.CodePages",
1255 "System.Threading.Overlapped"
1258 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { NAME, MAJOR, MINOR, BUILD, REVISION }
1260 static const IgnoredAssemblyVersion ignored_assembly_versions
[] = {
1261 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 0, 0, 0),
1262 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 0, 1, 0),
1263 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 0, 2, 0),
1264 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT
, 4, 1, 0, 0),
1265 IGNORED_ASM_VER (SYS_IO_COMPRESSION
, 4, 1, 0, 0),
1266 IGNORED_ASM_VER (SYS_IO_COMPRESSION
, 4, 1, 2, 0),
1267 IGNORED_ASM_VER (SYS_IO_COMPRESSION
, 4, 2, 0, 0),
1268 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 0, 0),
1269 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 0, 1),
1270 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 0),
1271 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 1),
1272 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 2),
1273 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 1, 1, 3),
1274 IGNORED_ASM_VER (SYS_NET_HTTP
, 4, 2, 0, 0),
1275 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO
, 4, 0, 0, 0),
1276 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO
, 4, 0, 1, 0),
1277 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO
, 4, 0, 2, 0),
1278 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 0, 1, 0),
1279 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 0, 2, 0),
1280 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 1, 0, 0),
1281 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES
, 4, 1, 1, 0),
1282 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 0, 0, 0),
1283 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 0, 1, 0),
1284 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 0, 2, 0),
1285 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED
, 4, 1, 0, 0)
1289 mono_assembly_is_problematic_version (const char *name
, guint16 major
, guint16 minor
, guint16 build
, guint16 revision
)
1291 for (int i
= 0; i
< G_N_ELEMENTS (ignored_assembly_versions
); ++i
) {
1292 if (ignored_assembly_versions
[i
].major
!= major
||
1293 ignored_assembly_versions
[i
].minor
!= minor
||
1294 ignored_assembly_versions
[i
].build
!= build
||
1295 ignored_assembly_versions
[i
].revision
!= revision
)
1297 if (!strcmp (ignored_assemblies_names
[ignored_assembly_versions
[i
].assembly_name
], name
))
1305 static void Main () {
1308 for (int i = 0; i < str.Length; ++i)
1309 h = ((h << 5) + h) ^ str[i];
1311 Console.WriteLine ("{0:X}", h);
1315 hash_guid (const char *str
)
1319 h
= ((h
<< 5) + h
) ^ *str
;
1327 mono_is_problematic_image (MonoImage
*image
)
1329 int h
= hash_guid (image
->guid
);
1331 //TODO make this more cache effiecient.
1332 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1333 for (int i
= 0; i
< G_N_ELEMENTS (ignored_assemblies
); ++i
) {
1334 if (ignored_assemblies
[i
].hash
== h
&& !strcmp (image
->guid
, ignored_assemblies
[i
].guid
)) {
1335 const char *needle
= ignored_assemblies_file_names
[ignored_assemblies
[i
].assembly_name
];
1336 size_t needle_len
= strlen (needle
);
1337 size_t asm_len
= strlen (image
->name
);
1338 if (asm_len
> needle_len
&& !g_ascii_strcasecmp (image
->name
+ (asm_len
- needle_len
), needle
))
1346 do_mono_image_load (MonoImage
*image
, MonoImageOpenStatus
*status
,
1347 gboolean care_about_cli
, gboolean care_about_pecoff
)
1350 MonoCLIImageInfo
*iinfo
;
1351 MonoDotNetHeader
*header
;
1354 MONO_PROFILER_RAISE (image_loading
, (image
));
1356 mono_image_init (image
);
1358 iinfo
= image
->image_info
;
1359 header
= &iinfo
->cli_header
;
1361 if (!image
->metadata_only
) {
1362 for (l
= image_loaders
; l
; l
= l
->next
) {
1363 MonoImageLoader
*loader
= (MonoImageLoader
*)l
->data
;
1364 if (loader
->match (image
)) {
1365 image
->loader
= loader
;
1369 if (!image
->loader
) {
1371 *status
= MONO_IMAGE_IMAGE_INVALID
;
1376 *status
= MONO_IMAGE_IMAGE_INVALID
;
1378 if (care_about_pecoff
== FALSE
)
1381 if (image
->loader
== &pe_loader
&& !mono_verifier_verify_pe_data (image
, error
))
1384 if (!mono_image_load_pe_data (image
))
1387 image
->loader
= (MonoImageLoader
*)&pe_loader
;
1390 if (care_about_cli
== FALSE
) {
1394 if (image
->loader
== &pe_loader
&& !image
->metadata_only
&& !mono_verifier_verify_cli_data (image
, error
))
1397 if (!mono_image_load_cli_data (image
))
1400 if (!image
->ref_only
&& mono_is_problematic_image (image
)) {
1401 if (image
->load_from_context
) {
1402 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Loading problematic image %s", image
->name
);
1404 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Denying load of problematic image %s", image
->name
);
1406 *status
= MONO_IMAGE_IMAGE_INVALID
;
1411 if (image
->loader
== &pe_loader
&& !image
->metadata_only
&& !mono_verifier_verify_table_data (image
, error
))
1414 mono_image_load_names (image
);
1416 mono_image_load_time_date_stamp (image
);
1418 load_modules (image
);
1421 MONO_PROFILER_RAISE (image_loaded
, (image
));
1423 *status
= MONO_IMAGE_OK
;
1428 if (!is_ok (error
)) {
1429 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Could not load image %s due to %s", image
->name
, mono_error_get_message (error
));
1430 mono_error_cleanup (error
);
1432 MONO_PROFILER_RAISE (image_failed
, (image
));
1433 mono_image_close (image
);
1438 mono_image_storage_trypublish (MonoImageStorage
*candidate
, MonoImageStorage
**out_storage
)
1441 mono_images_storage_lock ();
1442 MonoImageStorage
*val
= (MonoImageStorage
*)g_hash_table_lookup (images_storage_hash
, candidate
->key
);
1444 mono_refcount_inc (val
);
1448 g_hash_table_insert (images_storage_hash
, candidate
->key
, candidate
);
1451 mono_images_storage_unlock ();
1456 mono_image_storage_unpublish (MonoImageStorage
*storage
)
1458 mono_images_storage_lock ();
1459 g_assert (storage
->ref
.ref
== 0);
1461 MonoImageStorage
*published
= (MonoImageStorage
*)g_hash_table_lookup (images_storage_hash
, storage
->key
);
1462 if (published
== storage
) {
1463 g_hash_table_remove (images_storage_hash
, storage
->key
);
1466 mono_images_storage_unlock ();
1470 mono_image_storage_tryaddref (const char *key
, MonoImageStorage
**found
)
1472 gboolean result
= FALSE
;
1473 mono_images_storage_lock ();
1474 MonoImageStorage
*val
= (MonoImageStorage
*)g_hash_table_lookup (images_storage_hash
, key
);
1476 mono_refcount_inc (val
);
1480 mono_images_storage_unlock ();
1485 mono_image_storage_dtor (gpointer self
)
1487 MonoImageStorage
*storage
= (MonoImageStorage
*)self
;
1489 mono_image_storage_unpublish (storage
);
1492 if (storage
->is_module_handle
&& !storage
->has_entry_point
) {
1493 mono_images_lock ();
1494 FreeLibrary ((HMODULE
) storage
->raw_data
);
1495 mono_images_unlock ();
1499 if (storage
->raw_buffer_used
) {
1500 if (storage
->raw_data
!= NULL
) {
1502 if (storage
->fileio_used
)
1503 mono_file_unmap_fileio (storage
->raw_data
, storage
->raw_data_handle
);
1506 mono_file_unmap (storage
->raw_data
, storage
->raw_data_handle
);
1509 if (storage
->raw_data_allocated
) {
1510 g_free (storage
->raw_data
);
1513 g_free (storage
->key
);
1519 mono_image_storage_close (MonoImageStorage
*storage
)
1521 mono_refcount_dec (storage
);
1525 mono_image_init_raw_data (MonoImage
*image
, const MonoImageStorage
*storage
)
1529 image
->raw_data
= storage
->raw_data
;
1530 image
->raw_data_len
= storage
->raw_data_len
;
1534 static MonoImageStorage
*
1535 mono_image_storage_open (const char *fname
)
1539 key
= mono_path_resolve_symlinks (fname
);
1540 MonoImageStorage
*published_storage
= NULL
;
1541 if (mono_image_storage_tryaddref (key
, &published_storage
)) {
1543 return published_storage
;
1547 if ((filed
= mono_file_map_open (fname
)) == NULL
){
1548 if (IS_PORTABILITY_SET
) {
1549 gchar
*ffname
= mono_portability_find_file (fname
, TRUE
);
1551 filed
= mono_file_map_open (ffname
);
1556 if (filed
== NULL
) {
1562 MonoImageStorage
*storage
= g_new0 (MonoImageStorage
, 1);
1563 mono_refcount_init (storage
, mono_image_storage_dtor
);
1564 storage
->raw_buffer_used
= TRUE
;
1565 storage
->raw_data_len
= mono_file_map_size (filed
);
1566 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
);
1567 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1568 if (!storage
->raw_data
) {
1569 storage
->fileio_used
= TRUE
;
1570 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
);
1573 mono_file_map_close (filed
);
1577 MonoImageStorage
*other_storage
= NULL
;
1578 if (!mono_image_storage_trypublish (storage
, &other_storage
)) {
1579 mono_image_storage_close (storage
);
1580 storage
= other_storage
;
1585 static MonoImageStorage
*
1586 mono_image_storage_new_raw_data (char *datac
, guint32 data_len
, gboolean raw_data_allocated
, const char *name
)
1588 char *key
= (name
== NULL
) ? g_strdup_printf ("data-%p", datac
) : g_strdup (name
);
1589 MonoImageStorage
*published_storage
= NULL
;
1590 if (mono_image_storage_tryaddref (key
, &published_storage
)) {
1592 return published_storage
;
1595 MonoImageStorage
*storage
= g_new0 (MonoImageStorage
, 1);
1596 mono_refcount_init (storage
, mono_image_storage_dtor
);
1598 storage
->raw_data
= datac
;
1599 storage
->raw_data_len
= data_len
;
1600 storage
->raw_data_allocated
= raw_data_allocated
;
1603 MonoImageStorage
*other_storage
= NULL
;
1604 if (!mono_image_storage_trypublish (storage
, &other_storage
)) {
1605 mono_image_storage_close (storage
);
1606 storage
= other_storage
;
1612 do_mono_image_open (const char *fname
, MonoImageOpenStatus
*status
,
1613 gboolean care_about_cli
, gboolean care_about_pecoff
, gboolean refonly
, gboolean metadata_only
, gboolean load_from_context
)
1615 MonoCLIImageInfo
*iinfo
;
1618 MonoImageStorage
*storage
= mono_image_storage_open (fname
);
1622 *status
= MONO_IMAGE_ERROR_ERRNO
;
1626 image
= g_new0 (MonoImage
, 1);
1627 image
->storage
= storage
;
1628 mono_image_init_raw_data (image
, storage
);
1629 if (!image
->raw_data
) {
1630 mono_image_storage_close (image
->storage
);
1633 *status
= MONO_IMAGE_IMAGE_INVALID
;
1636 iinfo
= g_new0 (MonoCLIImageInfo
, 1);
1637 image
->image_info
= iinfo
;
1638 image
->name
= mono_path_resolve_symlinks (fname
);
1639 image
->filename
= g_strdup (image
->name
);
1640 image
->ref_only
= refonly
;
1641 image
->metadata_only
= metadata_only
;
1642 image
->load_from_context
= load_from_context
;
1643 image
->ref_count
= 1;
1644 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1645 image
->core_clr_platform_code
= mono_security_core_clr_determine_platform_image (image
);
1647 return do_mono_image_load (image
, status
, care_about_cli
, care_about_pecoff
);
1651 * mono_image_loaded_full:
1652 * \param name path or assembly name of the image to load
1653 * \param refonly Check with respect to reflection-only loads?
1655 * This routine verifies that the given image is loaded.
1656 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1658 * \returns the loaded \c MonoImage, or NULL on failure.
1661 mono_image_loaded_full (const char *name
, gboolean refonly
)
1664 MONO_ENTER_GC_UNSAFE
;
1665 result
= mono_image_loaded_internal (name
, refonly
);
1666 MONO_EXIT_GC_UNSAFE
;
1671 * mono_image_loaded_internal:
1672 * \param name path or assembly name of the image to load
1673 * \param refonly Check with respect to reflection-only loads?
1675 * This routine verifies that the given image is loaded.
1676 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1678 * \returns the loaded \c MonoImage, or NULL on failure.
1681 mono_image_loaded_internal (const char *name
, gboolean refonly
)
1685 mono_images_lock ();
1686 res
= (MonoImage
*)g_hash_table_lookup (get_loaded_images_hash (refonly
), name
);
1688 res
= (MonoImage
*)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly
), name
);
1689 mono_images_unlock ();
1695 * mono_image_loaded:
1696 * \param name path or assembly name of the image to load
1697 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1698 * \returns the loaded \c MonoImage, or NULL on failure.
1701 mono_image_loaded (const char *name
)
1704 MONO_ENTER_GC_UNSAFE
;
1705 result
= mono_image_loaded_internal (name
, FALSE
);
1706 MONO_EXIT_GC_UNSAFE
;
1716 find_by_guid (gpointer key
, gpointer val
, gpointer user_data
)
1718 GuidData
*data
= (GuidData
*)user_data
;
1723 image
= (MonoImage
*)val
;
1724 if (strcmp (data
->guid
, mono_image_get_guid (image
)) == 0)
1729 * mono_image_loaded_by_guid_full:
1732 mono_image_loaded_by_guid_full (const char *guid
, gboolean refonly
)
1735 GHashTable
*loaded_images
= get_loaded_images_hash (refonly
);
1739 mono_images_lock ();
1740 g_hash_table_foreach (loaded_images
, find_by_guid
, &data
);
1741 mono_images_unlock ();
1746 * mono_image_loaded_by_guid:
1749 mono_image_loaded_by_guid (const char *guid
)
1751 return mono_image_loaded_by_guid_full (guid
, FALSE
);
1755 register_image (MonoImage
*image
)
1758 GHashTable
*loaded_images
= get_loaded_images_hash (image
->ref_only
);
1760 mono_images_lock ();
1761 image2
= (MonoImage
*)g_hash_table_lookup (loaded_images
, image
->name
);
1764 /* Somebody else beat us to it */
1765 mono_image_addref (image2
);
1766 mono_images_unlock ();
1767 mono_image_close (image
);
1771 GHashTable
*loaded_images_by_name
= get_loaded_images_by_name_hash (image
->ref_only
);
1772 g_hash_table_insert (loaded_images
, image
->name
, image
);
1773 if (image
->assembly_name
&& (g_hash_table_lookup (loaded_images_by_name
, image
->assembly_name
) == NULL
))
1774 g_hash_table_insert (loaded_images_by_name
, (char *) image
->assembly_name
, image
);
1775 mono_images_unlock ();
1777 if (mono_is_problematic_image (image
)) {
1778 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Registering %s, problematic image '%s'", image
->ref_only
? "REFONLY" : "default", image
->name
);
1784 mono_image_open_from_data_internal (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean metadata_only
, const char *name
)
1786 MonoCLIImageInfo
*iinfo
;
1790 if (!data
|| !data_len
) {
1792 *status
= MONO_IMAGE_IMAGE_INVALID
;
1797 datac
= (char *)g_try_malloc (data_len
);
1800 *status
= MONO_IMAGE_ERROR_ERRNO
;
1803 memcpy (datac
, data
, data_len
);
1806 MonoImageStorage
*storage
= mono_image_storage_new_raw_data (datac
, data_len
, need_copy
, name
);
1807 image
= g_new0 (MonoImage
, 1);
1808 image
->storage
= storage
;
1809 mono_image_init_raw_data (image
, storage
);
1810 image
->name
= (name
== NULL
) ? g_strdup_printf ("data-%p", datac
) : g_strdup(name
);
1811 iinfo
= g_new0 (MonoCLIImageInfo
, 1);
1812 image
->image_info
= iinfo
;
1813 image
->ref_only
= refonly
;
1814 image
->metadata_only
= metadata_only
;
1815 image
->ref_count
= 1;
1817 image
= do_mono_image_load (image
, status
, TRUE
, TRUE
);
1821 return register_image (image
);
1825 * mono_image_open_from_data_with_name:
1828 mono_image_open_from_data_with_name (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
, gboolean refonly
, const char *name
)
1831 MONO_ENTER_GC_UNSAFE
;
1832 result
= mono_image_open_from_data_internal (data
, data_len
, need_copy
, status
, refonly
, FALSE
, name
);
1833 MONO_EXIT_GC_UNSAFE
;
1838 * mono_image_open_from_data_full:
1841 mono_image_open_from_data_full (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
, gboolean refonly
)
1844 MONO_ENTER_GC_UNSAFE
;
1845 result
= mono_image_open_from_data_internal (data
, data_len
, need_copy
, status
, refonly
, FALSE
, NULL
);
1846 MONO_EXIT_GC_UNSAFE
;
1851 * mono_image_open_from_data:
1854 mono_image_open_from_data (char *data
, guint32 data_len
, gboolean need_copy
, MonoImageOpenStatus
*status
)
1857 MONO_ENTER_GC_UNSAFE
;
1858 result
= mono_image_open_from_data_internal (data
, data_len
, need_copy
, status
, FALSE
, FALSE
, NULL
);
1859 MONO_EXIT_GC_UNSAFE
;
1864 static MonoImageStorage
*
1865 mono_image_storage_open_from_module_handle (HMODULE module_handle
, const char *fname
, gboolean has_entry_point
)
1867 char *key
= g_strdup (fname
);
1868 MonoImageStorage
*published_storage
= NULL
;
1869 if (mono_image_storage_tryaddref (key
, &published_storage
)) {
1871 return published_storage
;
1874 MonoImageStorage
*storage
= g_new0 (MonoImageStorage
, 1);
1875 mono_refcount_init (storage
, mono_image_storage_dtor
);
1876 storage
->raw_data
= (char*) module_handle
;
1877 storage
->is_module_handle
= TRUE
;
1878 storage
->has_entry_point
= has_entry_point
;
1882 MonoImageStorage
*other_storage
= NULL
;
1883 if (!mono_image_storage_trypublish (storage
, &other_storage
)) {
1884 mono_image_storage_close (storage
);
1885 storage
= other_storage
;
1890 /* fname is not duplicated. */
1892 mono_image_open_from_module_handle (HMODULE module_handle
, char* fname
, gboolean has_entry_point
, MonoImageOpenStatus
* status
)
1895 MonoCLIImageInfo
* iinfo
;
1897 MonoImageStorage
*storage
= mono_image_storage_open_from_module_handle (module_handle
, fname
, has_entry_point
);
1898 image
= g_new0 (MonoImage
, 1);
1899 image
->storage
= storage
;
1900 mono_image_init_raw_data (image
, storage
);
1901 iinfo
= g_new0 (MonoCLIImageInfo
, 1);
1902 image
->image_info
= iinfo
;
1903 image
->name
= fname
;
1904 image
->ref_count
= has_entry_point
? 0 : 1;
1906 image
= do_mono_image_load (image
, status
, TRUE
, TRUE
);
1910 return register_image (image
);
1915 * mono_image_open_full:
1918 mono_image_open_full (const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
)
1920 return mono_image_open_a_lot (fname
, status
, refonly
, FALSE
);
1924 mono_image_open_a_lot_parameterized (const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean load_from_context
, gboolean
*problematic
)
1927 GHashTable
*loaded_images
= get_loaded_images_hash (refonly
);
1930 g_return_val_if_fail (fname
!= NULL
, NULL
);
1933 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1934 // then assemblies need to be loaded with LoadLibrary:
1935 if (!refonly
&& coree_module_handle
) {
1936 HMODULE module_handle
;
1937 gunichar2
*fname_utf16
;
1940 absfname
= mono_path_resolve_symlinks (fname
);
1943 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1944 mono_images_lock ();
1945 image
= (MonoImage
*)g_hash_table_lookup (loaded_images
, absfname
);
1946 if (image
) { // Image already loaded
1947 if (!load_from_context
&& mono_is_problematic_image (image
)) {
1948 // If we previously loaded a problematic image, don't
1949 // return it if we're not in LoadFrom context.
1951 // Note: this has an interaction with
1952 // mono_problematic_image_reprobe - at that point we
1953 // have a problematic image opened, but we don't want
1954 // to see it again when we go searching for an image
1956 mono_images_unlock ();
1959 g_assert (m_image_is_module_handle (image
));
1960 if (m_image_has_entry_point (image
) && image
->ref_count
== 0) {
1961 /* Increment reference count on images loaded outside of the runtime. */
1962 fname_utf16
= g_utf8_to_utf16 (absfname
, -1, NULL
, NULL
, NULL
);
1963 /* The image is already loaded because _CorDllMain removes images from the hash. */
1964 module_handle
= LoadLibrary (fname_utf16
);
1965 g_assert (module_handle
== (HMODULE
) image
->raw_data
);
1967 mono_image_addref (image
);
1968 mono_images_unlock ();
1970 g_free (fname_utf16
);
1975 // Image not loaded, load it now
1976 fname_utf16
= g_utf8_to_utf16 (absfname
, -1, NULL
, NULL
, NULL
);
1977 module_handle
= MonoLoadImage (fname_utf16
);
1978 if (status
&& module_handle
== NULL
)
1979 last_error
= mono_w32error_get_last ();
1981 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1982 image
= (MonoImage
*)g_hash_table_lookup (loaded_images
, absfname
);
1984 mono_image_addref (image
);
1985 mono_images_unlock ();
1987 g_free (fname_utf16
);
1989 if (module_handle
== NULL
) {
1993 if (last_error
== ERROR_BAD_EXE_FORMAT
|| last_error
== STATUS_INVALID_IMAGE_FORMAT
) {
1995 *status
= MONO_IMAGE_IMAGE_INVALID
;
1997 if (last_error
== ERROR_FILE_NOT_FOUND
|| last_error
== ERROR_PATH_NOT_FOUND
)
1998 mono_set_errno (ENOENT
);
2007 g_assert (m_image_is_module_handle (image
));
2008 g_assert (m_image_has_entry_point (image
));
2013 return mono_image_open_from_module_handle (module_handle
, absfname
, FALSE
, status
);
2017 absfname
= mono_path_resolve_symlinks (fname
);
2020 * The easiest solution would be to do all the loading inside the mutex,
2021 * but that would lead to scalability problems. So we let the loading
2022 * happen outside the mutex, and if multiple threads happen to load
2023 * the same image, we discard all but the first copy.
2025 mono_images_lock ();
2026 image
= (MonoImage
*)g_hash_table_lookup (loaded_images
, absfname
);
2029 if (image
) { // Image already loaded
2030 if (!refonly
&& !load_from_context
&& mono_is_problematic_image (image
)) {
2031 // If we previously loaded a problematic image, don't
2032 // return it if we're not in LoadFrom context.
2034 // Note: this has an interaction with
2035 // mono_problematic_image_reprobe - at that point we
2036 // have a problematic image opened, but we don't want
2037 // to see it again when we go searching for an image
2039 mono_images_unlock ();
2040 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_ASSEMBLY
, "Not returning problematic image '%s' refcount=%d", image
->name
, image
->ref_count
);
2042 *problematic
= TRUE
;
2045 mono_image_addref (image
);
2046 mono_images_unlock ();
2049 mono_images_unlock ();
2051 // Image not loaded, load it now
2052 image
= do_mono_image_open (fname
, status
, TRUE
, TRUE
, refonly
, FALSE
, load_from_context
);
2054 *problematic
= TRUE
;
2058 return register_image (image
);
2062 mono_image_open_a_lot (const char *fname
, MonoImageOpenStatus
*status
, gboolean refonly
, gboolean load_from_context
)
2064 return mono_image_open_a_lot_parameterized (fname
, status
, refonly
, load_from_context
, NULL
);
2068 mono_is_problematic_file (const char *fname
)
2070 MonoImageOpenStatus status
;
2071 gboolean problematic
= FALSE
;
2073 MonoImage
*opened
= mono_image_open_a_lot_parameterized (fname
, &status
, FALSE
, FALSE
, &problematic
);
2075 mono_image_close (opened
);
2083 * \param fname filename that points to the module we want to open
2084 * \param status An error condition is returned in this field
2085 * \returns An open image of type \c MonoImage or NULL on error.
2086 * The caller holds a temporary reference to the returned image which should be cleared
2087 * when no longer needed by calling \c mono_image_close.
2088 * if NULL, then check the value of \p status for details on the error
2091 mono_image_open (const char *fname
, MonoImageOpenStatus
*status
)
2093 return mono_image_open_full (fname
, status
, FALSE
);
2097 * mono_pe_file_open:
2098 * \param fname filename that points to the module we want to open
2099 * \param status An error condition is returned in this field
2100 * \returns An open image of type \c MonoImage or NULL on error. if
2101 * NULL, then check the value of \p status for details on the error.
2102 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
2103 * It's just a PE file loader, used for \c FileVersionInfo. It also does
2104 * not use the image cache.
2107 mono_pe_file_open (const char *fname
, MonoImageOpenStatus
*status
)
2109 g_return_val_if_fail (fname
!= NULL
, NULL
);
2111 return do_mono_image_open (fname
, status
, FALSE
, TRUE
, FALSE
, FALSE
, FALSE
);
2115 * mono_image_open_raw
2116 * \param fname filename that points to the module we want to open
2117 * \param status An error condition is returned in this field
2118 * \returns an image without loading neither pe or cli data.
2119 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
2122 mono_image_open_raw (const char *fname
, MonoImageOpenStatus
*status
)
2124 g_return_val_if_fail (fname
!= NULL
, NULL
);
2126 return do_mono_image_open (fname
, status
, FALSE
, FALSE
, FALSE
, FALSE
, FALSE
);
2130 * mono_image_open_metadata_only:
2132 * Open an image which contains metadata only without a PE header.
2135 mono_image_open_metadata_only (const char *fname
, MonoImageOpenStatus
*status
)
2137 return do_mono_image_open (fname
, status
, TRUE
, TRUE
, FALSE
, TRUE
, FALSE
);
2141 * mono_image_fixup_vtable:
2144 mono_image_fixup_vtable (MonoImage
*image
)
2147 MonoCLIImageInfo
*iinfo
;
2149 MonoVTableFixup
*vtfixup
;
2155 g_assert (m_image_is_module_handle (image
));
2157 iinfo
= image
->image_info
;
2158 de
= &iinfo
->cli_cli_header
.ch_vtable_fixups
;
2159 if (!de
->rva
|| !de
->size
)
2161 vtfixup
= (MonoVTableFixup
*) mono_image_rva_map (image
, de
->rva
);
2165 count
= de
->size
/ sizeof (MonoVTableFixup
);
2167 if (!vtfixup
->rva
|| !vtfixup
->count
)
2170 slot
= mono_image_rva_map (image
, vtfixup
->rva
);
2172 slot_type
= vtfixup
->type
;
2173 slot_count
= vtfixup
->count
;
2174 if (slot_type
& VTFIXUP_TYPE_32BIT
)
2175 while (slot_count
--) {
2176 *((guint32
*) slot
) = (guint32
)(gsize
)mono_marshal_get_vtfixup_ftnptr (image
, *((guint32
*) slot
), slot_type
);
2177 slot
= ((guint32
*) slot
) + 1;
2179 else if (slot_type
& VTFIXUP_TYPE_64BIT
)
2180 while (slot_count
--) {
2181 *((guint64
*) slot
) = (guint64
) mono_marshal_get_vtfixup_ftnptr (image
, *((guint64
*) slot
), slot_type
);
2182 slot
= ((guint32
*) slot
) + 1;
2185 g_assert_not_reached();
2190 g_assert_not_reached();
2195 free_hash_table (gpointer key
, gpointer val
, gpointer user_data
)
2197 g_hash_table_destroy ((GHashTable
*)val
);
2202 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
2204 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
2209 free_array_cache_entry (gpointer key
, gpointer val
, gpointer user_data
)
2211 g_slist_free ((GSList
*)val
);
2215 * mono_image_addref:
2216 * \param image The image file we wish to add a reference to
2217 * Increases the reference count of an image.
2220 mono_image_addref (MonoImage
*image
)
2222 mono_atomic_inc_i32 (&image
->ref_count
);
2226 mono_dynamic_stream_reset (MonoDynamicStream
* stream
)
2228 stream
->alloc_size
= stream
->index
= stream
->offset
= 0;
2229 g_free (stream
->data
);
2230 stream
->data
= NULL
;
2232 g_hash_table_destroy (stream
->hash
);
2233 stream
->hash
= NULL
;
2238 free_hash (GHashTable
*hash
)
2241 g_hash_table_destroy (hash
);
2245 mono_wrapper_caches_free (MonoWrapperCaches
*cache
)
2247 free_hash (cache
->delegate_invoke_cache
);
2248 free_hash (cache
->delegate_begin_invoke_cache
);
2249 free_hash (cache
->delegate_end_invoke_cache
);
2250 free_hash (cache
->runtime_invoke_signature_cache
);
2252 free_hash (cache
->delegate_abstract_invoke_cache
);
2254 free_hash (cache
->runtime_invoke_method_cache
);
2255 free_hash (cache
->managed_wrapper_cache
);
2257 free_hash (cache
->native_wrapper_cache
);
2258 free_hash (cache
->native_wrapper_aot_cache
);
2259 free_hash (cache
->native_wrapper_check_cache
);
2260 free_hash (cache
->native_wrapper_aot_check_cache
);
2262 free_hash (cache
->native_func_wrapper_aot_cache
);
2263 free_hash (cache
->remoting_invoke_cache
);
2264 free_hash (cache
->synchronized_cache
);
2265 free_hash (cache
->unbox_wrapper_cache
);
2266 free_hash (cache
->cominterop_invoke_cache
);
2267 free_hash (cache
->cominterop_wrapper_cache
);
2268 free_hash (cache
->thunk_invoke_cache
);
2272 mono_image_close_except_pools_all (MonoImage
**images
, int image_count
)
2274 for (int i
= 0; i
< image_count
; ++i
) {
2276 if (!mono_image_close_except_pools (images
[i
]))
2283 * Returns whether mono_image_close_finish() must be called as well.
2284 * We must unload images in two steps because clearing the domain in
2285 * SGen requires the class metadata to be intact, but we need to free
2286 * the mono_g_hash_tables in case a collection occurs during domain
2287 * unloading and the roots would trip up the GC.
2290 mono_image_close_except_pools (MonoImage
*image
)
2293 GHashTable
*loaded_images
, *loaded_images_by_name
;
2296 g_return_val_if_fail (image
!= NULL
, FALSE
);
2299 * Atomically decrement the refcount and remove ourselves from the hash tables, so
2300 * register_image () can't grab an image which is being closed.
2302 mono_images_lock ();
2304 if (mono_atomic_dec_i32 (&image
->ref_count
) > 0) {
2305 mono_images_unlock ();
2309 loaded_images
= get_loaded_images_hash (image
->ref_only
);
2310 loaded_images_by_name
= get_loaded_images_by_name_hash (image
->ref_only
);
2311 image2
= (MonoImage
*)g_hash_table_lookup (loaded_images
, image
->name
);
2312 if (image
== image2
) {
2313 /* This is not true if we are called from mono_image_open () */
2314 g_hash_table_remove (loaded_images
, image
->name
);
2316 if (image
->assembly_name
&& (g_hash_table_lookup (loaded_images_by_name
, image
->assembly_name
) == image
))
2317 g_hash_table_remove (loaded_images_by_name
, (char *) image
->assembly_name
);
2319 mono_images_unlock ();
2322 if (m_image_is_module_handle (image
) && m_image_has_entry_point (image
)) {
2323 mono_images_lock ();
2324 if (image
->ref_count
== 0) {
2325 /* Image will be closed by _CorDllMain. */
2326 FreeLibrary ((HMODULE
) image
->raw_data
);
2327 mono_images_unlock ();
2330 mono_images_unlock ();
2334 MONO_PROFILER_RAISE (image_unloading
, (image
));
2336 mono_trace (G_LOG_LEVEL_INFO
, MONO_TRACE_ASSEMBLY
, "Unloading image %s [%p].", image
->name
, image
);
2338 mono_image_invoke_unload_hook (image
);
2340 mono_metadata_clean_for_image (image
);
2343 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2344 * assemblies, so we can't release these references in mono_assembly_close () since the
2345 * MonoImage might outlive its associated MonoAssembly.
2347 if (image
->references
&& !image_is_dynamic (image
)) {
2348 for (i
= 0; i
< image
->nreferences
; i
++) {
2349 if (image
->references
[i
] && image
->references
[i
] != REFERENCE_MISSING
) {
2350 if (!mono_assembly_close_except_image_pools (image
->references
[i
]))
2351 image
->references
[i
] = NULL
;
2355 if (image
->references
) {
2356 g_free (image
->references
);
2357 image
->references
= NULL
;
2361 /* a MonoDynamicImage doesn't have any storage */
2362 g_assert (image_is_dynamic (image
) || image
->storage
!= NULL
);
2364 if (image
->storage
&& m_image_is_raw_data_allocated (image
)) {
2365 /* FIXME: do we need this? (image is disposed anyway) */
2366 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2367 MonoCLIImageInfo
*ii
= image
->image_info
;
2369 if ((image
->raw_metadata
> image
->raw_data
) &&
2370 (image
->raw_metadata
<= (image
->raw_data
+ image
->raw_data_len
)))
2371 image
->raw_metadata
= NULL
;
2373 for (i
= 0; i
< ii
->cli_section_count
; i
++)
2374 if (((char*)(ii
->cli_sections
[i
]) > image
->raw_data
) &&
2375 ((char*)(ii
->cli_sections
[i
]) <= ((char*)image
->raw_data
+ image
->raw_data_len
)))
2376 ii
->cli_sections
[i
] = NULL
;
2381 mono_image_storage_close (image
->storage
);
2383 if (debug_assembly_unload
) {
2384 char *old_name
= image
->name
;
2385 image
->name
= g_strdup_printf ("%s - UNLOADED", old_name
);
2388 g_free (image
->name
);
2389 g_free (image
->filename
);
2390 g_free (image
->guid
);
2391 g_free (image
->version
);
2394 if (image
->method_cache
)
2395 g_hash_table_destroy (image
->method_cache
);
2396 if (image
->methodref_cache
)
2397 g_hash_table_destroy (image
->methodref_cache
);
2398 mono_internal_hash_table_destroy (&image
->class_cache
);
2399 mono_conc_hashtable_destroy (image
->field_cache
);
2400 if (image
->array_cache
) {
2401 g_hash_table_foreach (image
->array_cache
, free_array_cache_entry
, NULL
);
2402 g_hash_table_destroy (image
->array_cache
);
2404 if (image
->szarray_cache
)
2405 g_hash_table_destroy (image
->szarray_cache
);
2406 if (image
->ptr_cache
)
2407 g_hash_table_destroy (image
->ptr_cache
);
2408 if (image
->name_cache
) {
2409 g_hash_table_foreach (image
->name_cache
, free_hash_table
, NULL
);
2410 g_hash_table_destroy (image
->name_cache
);
2413 free_hash (image
->delegate_bound_static_invoke_cache
);
2414 free_hash (image
->ldfld_wrapper_cache
);
2415 free_hash (image
->ldflda_wrapper_cache
);
2416 free_hash (image
->stfld_wrapper_cache
);
2417 free_hash (image
->isinst_cache
);
2418 free_hash (image
->castclass_cache
);
2419 free_hash (image
->icall_wrapper_cache
);
2420 free_hash (image
->proxy_isinst_cache
);
2421 if (image
->var_gparam_cache
)
2422 mono_conc_hashtable_destroy (image
->var_gparam_cache
);
2423 if (image
->mvar_gparam_cache
)
2424 mono_conc_hashtable_destroy (image
->mvar_gparam_cache
);
2425 free_hash (image
->wrapper_param_names
);
2426 free_hash (image
->pinvoke_scopes
);
2427 free_hash (image
->pinvoke_scope_filenames
);
2428 free_hash (image
->native_func_wrapper_cache
);
2429 mono_conc_hashtable_destroy (image
->typespec_cache
);
2430 free_hash (image
->weak_field_indexes
);
2432 mono_wrapper_caches_free (&image
->wrapper_caches
);
2434 for (i
= 0; i
< image
->gshared_types_len
; ++i
)
2435 free_hash (image
->gshared_types
[i
]);
2436 g_free (image
->gshared_types
);
2438 /* The ownership of signatures is not well defined */
2439 g_hash_table_destroy (image
->memberref_signatures
);
2440 g_hash_table_destroy (image
->method_signatures
);
2442 if (image
->rgctx_template_hash
)
2443 g_hash_table_destroy (image
->rgctx_template_hash
);
2445 if (image
->property_hash
)
2446 mono_property_hash_destroy (image
->property_hash
);
2449 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2450 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2452 g_assert (!image
->reflection_info_unregister_classes
|| mono_runtime_is_shutting_down ());
2453 image
->reflection_info_unregister_classes
= NULL
;
2455 if (image
->interface_bitset
) {
2456 mono_unload_interface_ids (image
->interface_bitset
);
2457 mono_bitset_free (image
->interface_bitset
);
2459 if (image
->image_info
){
2460 MonoCLIImageInfo
*ii
= image
->image_info
;
2462 g_free (ii
->cli_section_tables
);
2463 g_free (ii
->cli_sections
);
2464 g_free (image
->image_info
);
2467 mono_image_close_except_pools_all (image
->files
, image
->file_count
);
2468 mono_image_close_except_pools_all (image
->modules
, image
->module_count
);
2469 g_free (image
->modules_loaded
);
2471 mono_os_mutex_destroy (&image
->szarray_cache_lock
);
2472 mono_os_mutex_destroy (&image
->lock
);
2474 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2475 if (image_is_dynamic (image
)) {
2476 /* Dynamic images are GC_MALLOCed */
2477 g_free ((char*)image
->module_name
);
2478 mono_dynamic_image_free ((MonoDynamicImage
*)image
);
2481 MONO_PROFILER_RAISE (image_unloaded
, (image
));
2487 mono_image_close_all (MonoImage
**images
, int image_count
)
2489 for (int i
= 0; i
< image_count
; ++i
) {
2491 mono_image_close_finish (images
[i
]);
2498 mono_image_close_finish (MonoImage
*image
)
2502 if (image
->references
&& !image_is_dynamic (image
)) {
2503 for (i
= 0; i
< image
->nreferences
; i
++) {
2504 if (image
->references
[i
] && image
->references
[i
] != REFERENCE_MISSING
)
2505 mono_assembly_close_finish (image
->references
[i
]);
2508 g_free (image
->references
);
2509 image
->references
= NULL
;
2512 mono_image_close_all (image
->files
, image
->file_count
);
2513 mono_image_close_all (image
->modules
, image
->module_count
);
2515 #ifndef DISABLE_PERFCOUNTERS
2516 /* FIXME: use an explicit subtraction method as soon as it's available */
2517 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, -1 * mono_mempool_get_allocated (image
->mempool
));
2520 if (!image_is_dynamic (image
)) {
2521 if (debug_assembly_unload
)
2522 mono_mempool_invalidate (image
->mempool
);
2524 mono_mempool_destroy (image
->mempool
);
2528 if (debug_assembly_unload
)
2529 mono_mempool_invalidate (image
->mempool
);
2531 mono_mempool_destroy (image
->mempool
);
2532 mono_dynamic_image_free_image ((MonoDynamicImage
*)image
);
2539 * \param image The image file we wish to close
2540 * Closes an image file, deallocates all memory consumed and
2541 * unmaps all possible sections of the file
2544 mono_image_close (MonoImage
*image
)
2546 if (mono_image_close_except_pools (image
))
2547 mono_image_close_finish (image
);
2551 * mono_image_strerror:
2552 * \param status an code indicating the result from a recent operation
2553 * \returns a string describing the error
2556 mono_image_strerror (MonoImageOpenStatus status
)
2561 case MONO_IMAGE_ERROR_ERRNO
:
2562 return strerror (errno
);
2563 case MONO_IMAGE_IMAGE_INVALID
:
2564 return "File does not contain a valid CIL image";
2565 case MONO_IMAGE_MISSING_ASSEMBLYREF
:
2566 return "An assembly was referenced, but could not be found";
2568 return "Internal error";
2572 mono_image_walk_resource_tree (MonoCLIImageInfo
*info
, guint32 res_id
,
2573 guint32 lang_id
, gunichar2
*name
,
2574 MonoPEResourceDirEntry
*entry
,
2575 MonoPEResourceDir
*root
, guint32 level
)
2577 gboolean is_string
, is_dir
;
2578 guint32 name_offset
, dir_offset
;
2580 /* Level 0 holds a directory entry for each type of resource
2581 * (identified by ID or name).
2583 * Level 1 holds a directory entry for each named resource
2584 * item, and each "anonymous" item of a particular type of
2587 * Level 2 holds a directory entry for each language pointing to
2590 is_string
= MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry
);
2591 name_offset
= MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry
);
2593 is_dir
= MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry
);
2594 dir_offset
= MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry
);
2599 } else if (level
==1) {
2600 if (res_id
!= name_offset
)
2604 is_string
==TRUE
&& name
!=lookup (name_offset
)) {
2608 } else if (level
==2) {
2609 if (is_string
|| (lang_id
!= 0 && name_offset
!= lang_id
))
2612 g_assert_not_reached ();
2616 MonoPEResourceDir
*res_dir
=(MonoPEResourceDir
*)(((char *)root
)+dir_offset
);
2617 MonoPEResourceDirEntry
*sub_entries
=(MonoPEResourceDirEntry
*)(res_dir
+1);
2620 entries
= GUINT16_FROM_LE (res_dir
->res_named_entries
) + GUINT16_FROM_LE (res_dir
->res_id_entries
);
2622 for(i
=0; i
<entries
; i
++) {
2623 MonoPEResourceDirEntry
*sub_entry
=&sub_entries
[i
];
2626 ret
=mono_image_walk_resource_tree (info
, res_id
,
2637 MonoPEResourceDataEntry
*data_entry
=(MonoPEResourceDataEntry
*)((char *)(root
)+dir_offset
);
2638 MonoPEResourceDataEntry
*res
;
2640 res
= g_new0 (MonoPEResourceDataEntry
, 1);
2642 res
->rde_data_offset
= GUINT32_TO_LE (data_entry
->rde_data_offset
);
2643 res
->rde_size
= GUINT32_TO_LE (data_entry
->rde_size
);
2644 res
->rde_codepage
= GUINT32_TO_LE (data_entry
->rde_codepage
);
2645 res
->rde_reserved
= GUINT32_TO_LE (data_entry
->rde_reserved
);
2652 * mono_image_lookup_resource:
2653 * \param image the image to look up the resource in
2654 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2655 * \param lang_id The language id.
2656 * \param name the resource name to lookup.
2657 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2658 * of the given resource. The caller should free it using \c g_free when no longer
2662 mono_image_lookup_resource (MonoImage
*image
, guint32 res_id
, guint32 lang_id
, gunichar2
*name
)
2664 MonoCLIImageInfo
*info
;
2665 MonoDotNetHeader
*header
;
2666 MonoPEDatadir
*datadir
;
2667 MonoPEDirEntry
*rsrc
;
2668 MonoPEResourceDir
*resource_dir
;
2669 MonoPEResourceDirEntry
*res_entries
;
2676 mono_image_ensure_section_idx (image
, MONO_SECTION_RSRC
);
2678 info
= (MonoCLIImageInfo
*)image
->image_info
;
2683 header
=&info
->cli_header
;
2688 datadir
=&header
->datadir
;
2693 rsrc
=&datadir
->pe_resource_table
;
2698 resource_dir
=(MonoPEResourceDir
*)mono_image_rva_map (image
, rsrc
->rva
);
2699 if(resource_dir
==NULL
) {
2703 entries
= GUINT16_FROM_LE (resource_dir
->res_named_entries
) + GUINT16_FROM_LE (resource_dir
->res_id_entries
);
2704 res_entries
=(MonoPEResourceDirEntry
*)(resource_dir
+1);
2706 for(i
=0; i
<entries
; i
++) {
2707 MonoPEResourceDirEntry
*entry
=&res_entries
[i
];
2710 ret
=mono_image_walk_resource_tree (info
, res_id
, lang_id
,
2711 name
, entry
, resource_dir
,
2722 * mono_image_get_entry_point:
2723 * \param image the image where the entry point will be looked up.
2724 * Use this routine to determine the metadata token for method that
2725 * has been flagged as the entry point.
2726 * \returns the token for the entry point method in the image
2729 mono_image_get_entry_point (MonoImage
*image
)
2731 return image
->image_info
->cli_cli_header
.ch_entry_point
;
2735 * mono_image_get_resource:
2736 * \param image the image where the resource will be looked up.
2737 * \param offset The offset to add to the resource
2738 * \param size a pointer to an int where the size of the resource will be stored
2740 * This is a low-level routine that fetches a resource from the
2741 * metadata that starts at a given \p offset. The \p size parameter is
2742 * filled with the data field as encoded in the metadata.
2744 * \returns the pointer to the resource whose offset is \p offset.
2747 mono_image_get_resource (MonoImage
*image
, guint32 offset
, guint32
*size
)
2749 MonoCLIImageInfo
*iinfo
= image
->image_info
;
2750 MonoCLIHeader
*ch
= &iinfo
->cli_cli_header
;
2753 if (!ch
->ch_resources
.rva
|| offset
+ 4 > ch
->ch_resources
.size
)
2756 data
= mono_image_rva_map (image
, ch
->ch_resources
.rva
);
2761 *size
= read32 (data
);
2766 // Returning NULL with no error set will be interpeted as "not found"
2768 mono_image_load_file_for_image_checked (MonoImage
*image
, int fileidx
, MonoError
*error
)
2770 char *base_dir
, *name
;
2772 MonoTableInfo
*t
= &image
->tables
[MONO_TABLE_FILE
];
2778 if (fileidx
< 1 || fileidx
> t
->rows
)
2781 mono_image_lock (image
);
2782 if (image
->files
&& image
->files
[fileidx
- 1]) {
2783 mono_image_unlock (image
);
2784 return image
->files
[fileidx
- 1];
2786 mono_image_unlock (image
);
2788 fname_id
= mono_metadata_decode_row_col (t
, fileidx
- 1, MONO_FILE_NAME
);
2789 fname
= mono_metadata_string_heap (image
, fname_id
);
2790 base_dir
= g_path_get_dirname (image
->name
);
2791 name
= g_build_filename (base_dir
, fname
, NULL
);
2792 res
= mono_image_open (name
, NULL
);
2796 mono_image_lock (image
);
2797 if (image
->files
&& image
->files
[fileidx
- 1]) {
2798 MonoImage
*old
= res
;
2799 res
= image
->files
[fileidx
- 1];
2800 mono_image_unlock (image
);
2801 mono_image_close (old
);
2804 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2805 if (!assign_assembly_parent_for_netmodule (res
, image
, error
)) {
2806 mono_image_unlock (image
);
2807 mono_image_close (res
);
2811 for (i
= 0; i
< res
->module_count
; ++i
) {
2812 if (res
->modules
[i
] && !res
->modules
[i
]->assembly
)
2813 res
->modules
[i
]->assembly
= image
->assembly
;
2816 if (!image
->files
) {
2817 image
->files
= g_new0 (MonoImage
*, t
->rows
);
2818 image
->file_count
= t
->rows
;
2820 image
->files
[fileidx
- 1] = res
;
2821 mono_image_unlock (image
);
2822 /* vtable fixup can't happen with the image lock held */
2824 if (m_image_is_module_handle (res
))
2825 mono_image_fixup_vtable (res
);
2836 * mono_image_load_file_for_image:
2839 mono_image_load_file_for_image (MonoImage
*image
, int fileidx
)
2842 MonoImage
*result
= mono_image_load_file_for_image_checked (image
, fileidx
, error
);
2843 mono_error_assert_ok (error
);
2848 * mono_image_get_strong_name:
2849 * \param image a MonoImage
2850 * \param size a \c guint32 pointer, or NULL.
2852 * If the image has a strong name, and \p size is not NULL, the value
2853 * pointed to by size will have the size of the strong name.
2855 * \returns NULL if the image does not have a strong name, or a
2856 * pointer to the public key.
2859 mono_image_get_strong_name (MonoImage
*image
, guint32
*size
)
2861 MonoCLIImageInfo
*iinfo
= image
->image_info
;
2862 MonoPEDirEntry
*de
= &iinfo
->cli_cli_header
.ch_strong_name
;
2865 if (!de
->size
|| !de
->rva
)
2867 data
= mono_image_rva_map (image
, de
->rva
);
2876 * mono_image_strong_name_position:
2877 * \param image a \c MonoImage
2878 * \param size a \c guint32 pointer, or NULL.
2880 * If the image has a strong name, and \p size is not NULL, the value
2881 * pointed to by size will have the size of the strong name.
2883 * \returns the position within the image file where the strong name
2887 mono_image_strong_name_position (MonoImage
*image
, guint32
*size
)
2889 MonoCLIImageInfo
*iinfo
= image
->image_info
;
2890 MonoPEDirEntry
*de
= &iinfo
->cli_cli_header
.ch_strong_name
;
2895 if (!de
->size
|| !de
->rva
)
2897 pos
= mono_cli_rva_image_map (image
, de
->rva
);
2898 return pos
== INVALID_ADDRESS
? 0 : pos
;
2902 * mono_image_get_public_key:
2903 * \param image a \c MonoImage
2904 * \param size a \c guint32 pointer, or NULL.
2906 * This is used to obtain the public key in the \p image.
2908 * If the image has a public key, and \p size is not NULL, the value
2909 * pointed to by size will have the size of the public key.
2911 * \returns NULL if the image does not have a public key, or a pointer
2912 * to the public key.
2915 mono_image_get_public_key (MonoImage
*image
, guint32
*size
)
2920 if (image_is_dynamic (image
)) {
2922 *size
= ((MonoDynamicImage
*)image
)->public_key_len
;
2923 return (char*)((MonoDynamicImage
*)image
)->public_key
;
2925 if (image
->tables
[MONO_TABLE_ASSEMBLY
].rows
!= 1)
2927 tok
= mono_metadata_decode_row_col (&image
->tables
[MONO_TABLE_ASSEMBLY
], 0, MONO_ASSEMBLY_PUBLIC_KEY
);
2930 pubkey
= mono_metadata_blob_heap (image
, tok
);
2931 len
= mono_metadata_decode_blob_size (pubkey
, &pubkey
);
2938 * mono_image_get_name:
2939 * \param name a \c MonoImage
2940 * \returns the name of the assembly.
2943 mono_image_get_name (MonoImage
*image
)
2945 return image
->assembly_name
;
2949 * mono_image_get_filename:
2950 * \param image a \c MonoImage
2951 * Used to get the filename that hold the actual \c MonoImage
2952 * \returns the filename.
2955 mono_image_get_filename (MonoImage
*image
)
2961 * mono_image_get_guid:
2964 mono_image_get_guid (MonoImage
*image
)
2970 * mono_image_get_table_info:
2972 const MonoTableInfo
*
2973 mono_image_get_table_info (MonoImage
*image
, int table_id
)
2975 if (table_id
< 0 || table_id
>= MONO_TABLE_NUM
)
2977 return &image
->tables
[table_id
];
2981 * mono_image_get_table_rows:
2984 mono_image_get_table_rows (MonoImage
*image
, int table_id
)
2986 if (table_id
< 0 || table_id
>= MONO_TABLE_NUM
)
2988 return image
->tables
[table_id
].rows
;
2992 * mono_table_info_get_rows:
2995 mono_table_info_get_rows (const MonoTableInfo
*table
)
3001 * mono_image_get_assembly:
3002 * \param image the \c MonoImage .
3003 * Use this routine to get the assembly that owns this image.
3004 * \returns the assembly that holds this image.
3007 mono_image_get_assembly (MonoImage
*image
)
3009 return image
->assembly
;
3013 * mono_image_is_dynamic:
3014 * \param image the \c MonoImage
3016 * Determines if the given image was created dynamically through the
3017 * \c System.Reflection.Emit API
3018 * \returns TRUE if the image was created dynamically, FALSE if not.
3021 mono_image_is_dynamic (MonoImage
*image
)
3023 return image_is_dynamic (image
);
3027 * mono_image_has_authenticode_entry:
3028 * \param image the \c MonoImage
3029 * Use this routine to determine if the image has a Authenticode
3030 * Certificate Table.
3031 * \returns TRUE if the image contains an authenticode entry in the PE
3035 mono_image_has_authenticode_entry (MonoImage
*image
)
3037 MonoCLIImageInfo
*iinfo
= image
->image_info
;
3038 MonoDotNetHeader
*header
= &iinfo
->cli_header
;
3041 MonoPEDirEntry
*de
= &header
->datadir
.pe_certificate_table
;
3042 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
3043 return ((de
->rva
!= 0) && (de
->size
> 8));
3047 mono_image_alloc (MonoImage
*image
, guint size
)
3051 #ifndef DISABLE_PERFCOUNTERS
3052 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, size
);
3054 mono_image_lock (image
);
3055 res
= mono_mempool_alloc (image
->mempool
, size
);
3056 mono_image_unlock (image
);
3062 mono_image_alloc0 (MonoImage
*image
, guint size
)
3066 #ifndef DISABLE_PERFCOUNTERS
3067 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, size
);
3069 mono_image_lock (image
);
3070 res
= mono_mempool_alloc0 (image
->mempool
, size
);
3071 mono_image_unlock (image
);
3077 mono_image_strdup (MonoImage
*image
, const char *s
)
3081 #ifndef DISABLE_PERFCOUNTERS
3082 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, (gint32
)strlen (s
));
3084 mono_image_lock (image
);
3085 res
= mono_mempool_strdup (image
->mempool
, s
);
3086 mono_image_unlock (image
);
3092 mono_image_strdup_vprintf (MonoImage
*image
, const char *format
, va_list args
)
3095 mono_image_lock (image
);
3096 buf
= mono_mempool_strdup_vprintf (image
->mempool
, format
, args
);
3097 mono_image_unlock (image
);
3098 #ifndef DISABLE_PERFCOUNTERS
3099 mono_atomic_fetch_add_i32 (&mono_perfcounters
->loader_bytes
, (gint32
)strlen (buf
));
3105 mono_image_strdup_printf (MonoImage
*image
, const char *format
, ...)
3110 va_start (args
, format
);
3111 buf
= mono_image_strdup_vprintf (image
, format
, args
);
3117 mono_g_list_prepend_image (MonoImage
*image
, GList
*list
, gpointer data
)
3121 new_list
= (GList
*)mono_image_alloc (image
, sizeof (GList
));
3122 new_list
->data
= data
;
3123 new_list
->prev
= list
? list
->prev
: NULL
;
3124 new_list
->next
= list
;
3127 new_list
->prev
->next
= new_list
;
3129 list
->prev
= new_list
;
3135 mono_g_slist_append_image (MonoImage
*image
, GSList
*list
, gpointer data
)
3139 new_list
= (GSList
*)mono_image_alloc (image
, sizeof (GSList
));
3140 new_list
->data
= data
;
3141 new_list
->next
= NULL
;
3143 return g_slist_concat (list
, new_list
);
3147 mono_image_lock (MonoImage
*image
)
3149 mono_locks_os_acquire (&image
->lock
, ImageDataLock
);
3153 mono_image_unlock (MonoImage
*image
)
3155 mono_locks_os_release (&image
->lock
, ImageDataLock
);
3160 * mono_image_property_lookup:
3161 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
3163 * LOCKING: Takes the image lock
3166 mono_image_property_lookup (MonoImage
*image
, gpointer subject
, guint32 property
)
3170 mono_image_lock (image
);
3171 res
= mono_property_hash_lookup (image
->property_hash
, subject
, property
);
3172 mono_image_unlock (image
);
3178 * mono_image_property_insert:
3179 * Insert a new property \p property with value \p value on \p subject in \p
3180 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
3182 * LOCKING: Takes the image lock
3185 mono_image_property_insert (MonoImage
*image
, gpointer subject
, guint32 property
, gpointer value
)
3187 CHECKED_METADATA_STORE_LOCAL (image
->mempool
, value
);
3188 mono_image_lock (image
);
3189 mono_property_hash_insert (image
->property_hash
, subject
, property
, value
);
3190 mono_image_unlock (image
);
3194 * mono_image_property_remove:
3195 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
3197 * LOCKING: Takes the image lock
3200 mono_image_property_remove (MonoImage
*image
, gpointer subject
)
3202 mono_image_lock (image
);
3203 mono_property_hash_remove_object (image
->property_hash
, subject
);
3204 mono_image_unlock (image
);
3208 mono_image_append_class_to_reflection_info_set (MonoClass
*klass
)
3210 MonoImage
*image
= m_class_get_image (klass
);
3211 g_assert (image_is_dynamic (image
));
3212 mono_image_lock (image
);
3213 image
->reflection_info_unregister_classes
= g_slist_prepend_mempool (image
->mempool
, image
->reflection_info_unregister_classes
, klass
);
3214 mono_image_unlock (image
);
3217 // This is support for the mempool reference tracking feature in checked-build, but lives in image.c due to use of static variables of this file.
3220 * mono_find_image_owner:
3222 * Find the image, if any, which a given pointer is located in the memory of.
3225 mono_find_image_owner (void *ptr
)
3227 mono_images_lock ();
3229 MonoImage
*owner
= NULL
;
3231 // Iterate over both by-path image hashes
3232 const int hash_candidates
[] = {IMAGES_HASH_PATH
, IMAGES_HASH_PATH_REFONLY
};
3234 for (hash_idx
= 0; !owner
&& hash_idx
< G_N_ELEMENTS (hash_candidates
); hash_idx
++)
3236 GHashTable
*target
= loaded_images_hashes
[hash_candidates
[hash_idx
]];
3237 GHashTableIter iter
;
3240 // Iterate over images within a hash
3241 g_hash_table_iter_init (&iter
, target
);
3242 while (!owner
&& g_hash_table_iter_next(&iter
, NULL
, (gpointer
*)&image
))
3244 mono_image_lock (image
);
3245 if (mono_mempool_contains_addr (image
->mempool
, ptr
))
3247 mono_image_unlock (image
);
3251 mono_images_unlock ();