1 /**
2 * \file
3 * Routines for manipulating an image stored in an
4 * extended PE/COFF file.
5 *
6 * Authors:
7 * Miguel de Icaza (miguel@ximian.com)
8 * Paolo Molaro (lupus@ximian.com)
9 *
10 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
11 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 *
13 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14 */
15 #include <config.h>
16 #include <stdio.h>
17 #include <glib.h>
18 #include <errno.h>
19 #include <time.h>
20 #include <string.h>
21 #include "image.h"
22 #include "cil-coff.h"
23 #include "mono-endian.h"
24 #include "tabledefs.h"
25 #include "tokentype.h"
26 #include "metadata-internals.h"
27 #include "profiler-private.h"
28 #include "loader.h"
29 #include "marshal.h"
30 #include "coree.h"
31 #include <mono/utils/checked-build.h>
32 #include <mono/utils/mono-logger-internals.h>
33 #include <mono/utils/mono-path.h>
34 #include <mono/utils/mono-mmap.h>
35 #include <mono/utils/mono-io-portability.h>
36 #include <mono/utils/atomic.h>
37 #include <mono/metadata/class-internals.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/object-internals.h>
40 #include <mono/metadata/security-core-clr.h>
41 #include <mono/metadata/verify-internals.h>
42 #include <mono/metadata/verify.h>
43 #include <mono/metadata/image-internals.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #include <mono/metadata/w32error.h>
50
51 #define INVALID_ADDRESS 0xffffffff
52
53 // Amount initially reserved in each image's mempool.
54 // FIXME: This number is arbitrary, a more practical number should be found
55 #define INITIAL_IMAGE_SIZE 512
56
57 /*
58 * The "loaded images" hashes keep track of the various assemblies and netmodules loaded
59 * There are four, for all combinations of [look up by path or assembly name?]
60 * and [normal or reflection-only load?, as in Assembly.ReflectionOnlyLoad]
61 */
62 enum {
63 IMAGES_HASH_PATH = 0,
64 IMAGES_HASH_PATH_REFONLY = 1,
65 IMAGES_HASH_NAME = 2,
66 IMAGES_HASH_NAME_REFONLY = 3,
67 IMAGES_HASH_COUNT = 4
68 };
69 static GHashTable *loaded_images_hashes [4] = {NULL, NULL, NULL, NULL};
70
71 static GHashTable *
get_loaded_images_hash(gboolean refonly)72 get_loaded_images_hash (gboolean refonly)
73 {
74 int idx = refonly ? IMAGES_HASH_PATH_REFONLY : IMAGES_HASH_PATH;
75 return loaded_images_hashes [idx];
76 }
77
78 static GHashTable *
get_loaded_images_by_name_hash(gboolean refonly)79 get_loaded_images_by_name_hash (gboolean refonly)
80 {
81 int idx = refonly ? IMAGES_HASH_NAME_REFONLY : IMAGES_HASH_NAME;
82 return loaded_images_hashes [idx];
83 }
84
85 // Change the assembly set in `image` to the assembly set in `assemblyImage`. Halt if overwriting is attempted.
86 // Can be used on modules loaded through either the "file" or "module" mechanism
87 static gboolean
assign_assembly_parent_for_netmodule(MonoImage * image,MonoImage * assemblyImage,MonoError * error)88 assign_assembly_parent_for_netmodule (MonoImage *image, MonoImage *assemblyImage, MonoError *error)
89 {
90 // Assembly to assign
91 MonoAssembly *assembly = assemblyImage->assembly;
92
93 while (1) {
94 // Assembly currently assigned
95 MonoAssembly *assemblyOld = image->assembly;
96 if (assemblyOld) {
97 if (assemblyOld == assembly)
98 return TRUE;
99 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);
100 return FALSE;
101 }
102 gpointer result = mono_atomic_xchg_ptr((gpointer *)&image->assembly, assembly);
103 if (result == assembly)
104 return TRUE;
105 }
106 }
107
108 static gboolean debug_assembly_unload = FALSE;
109
110 #define mono_images_lock() if (mutex_inited) mono_os_mutex_lock (&images_mutex)
111 #define mono_images_unlock() if (mutex_inited) mono_os_mutex_unlock (&images_mutex)
112 static gboolean mutex_inited;
113 static mono_mutex_t images_mutex;
114
115 static void install_pe_loader (void);
116
117 typedef struct ImageUnloadHook ImageUnloadHook;
118 struct ImageUnloadHook {
119 MonoImageUnloadFunc func;
120 gpointer user_data;
121 };
122
123 static GSList *image_unload_hooks;
124
125 void
mono_install_image_unload_hook(MonoImageUnloadFunc func,gpointer user_data)126 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
127 {
128 ImageUnloadHook *hook;
129
130 g_return_if_fail (func != NULL);
131
132 hook = g_new0 (ImageUnloadHook, 1);
133 hook->func = func;
134 hook->user_data = user_data;
135 image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
136 }
137
138 void
mono_remove_image_unload_hook(MonoImageUnloadFunc func,gpointer user_data)139 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
140 {
141 GSList *l;
142 ImageUnloadHook *hook;
143
144 for (l = image_unload_hooks; l; l = l->next) {
145 hook = (ImageUnloadHook *)l->data;
146
147 if (hook->func == func && hook->user_data == user_data) {
148 g_free (hook);
149 image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
150 break;
151 }
152 }
153 }
154
155 static void
mono_image_invoke_unload_hook(MonoImage * image)156 mono_image_invoke_unload_hook (MonoImage *image)
157 {
158 GSList *l;
159 ImageUnloadHook *hook;
160
161 for (l = image_unload_hooks; l; l = l->next) {
162 hook = (ImageUnloadHook *)l->data;
163
164 hook->func (image, hook->user_data);
165 }
166 }
167
168 static GSList *image_loaders;
169
170 void
mono_install_image_loader(const MonoImageLoader * loader)171 mono_install_image_loader (const MonoImageLoader *loader)
172 {
173 image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
174 }
175
176 /* returns offset relative to image->raw_data */
177 guint32
mono_cli_rva_image_map(MonoImage * image,guint32 addr)178 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
179 {
180 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
181 const int top = iinfo->cli_section_count;
182 MonoSectionTable *tables = iinfo->cli_section_tables;
183 int i;
184
185 if (image->metadata_only)
186 return addr;
187
188 for (i = 0; i < top; i++){
189 if ((addr >= tables->st_virtual_address) &&
190 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
191 #ifdef HOST_WIN32
192 if (image->is_module_handle)
193 return addr;
194 #endif
195 return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
196 }
197 tables++;
198 }
199 return INVALID_ADDRESS;
200 }
201
202 /**
203 * mono_image_rva_map:
204 * \param image a \c MonoImage
205 * \param addr relative virtual address (RVA)
206 *
207 * This is a low-level routine used by the runtime to map relative
208 * virtual address (RVA) into their location in memory.
209 *
210 * \returns the address in memory for the given RVA, or NULL if the
211 * RVA is not valid for this image.
212 */
213 char *
mono_image_rva_map(MonoImage * image,guint32 addr)214 mono_image_rva_map (MonoImage *image, guint32 addr)
215 {
216 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
217 const int top = iinfo->cli_section_count;
218 MonoSectionTable *tables = iinfo->cli_section_tables;
219 int i;
220
221 #ifdef HOST_WIN32
222 if (image->is_module_handle) {
223 if (addr && addr < image->raw_data_len)
224 return image->raw_data + addr;
225 else
226 return NULL;
227 }
228 #endif
229
230 for (i = 0; i < top; i++){
231 if ((addr >= tables->st_virtual_address) &&
232 (addr < tables->st_virtual_address + tables->st_raw_data_size)){
233 if (!iinfo->cli_sections [i]) {
234 if (!mono_image_ensure_section_idx (image, i))
235 return NULL;
236 }
237 return (char*)iinfo->cli_sections [i] +
238 (addr - tables->st_virtual_address);
239 }
240 tables++;
241 }
242 return NULL;
243 }
244
245 /**
246 * mono_images_init:
247 *
248 * Initialize the global variables used by this module.
249 */
250 void
mono_images_init(void)251 mono_images_init (void)
252 {
253 mono_os_mutex_init_recursive (&images_mutex);
254
255 int hash_idx;
256 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
257 loaded_images_hashes [hash_idx] = g_hash_table_new (g_str_hash, g_str_equal);
258
259 debug_assembly_unload = g_hasenv ("MONO_DEBUG_ASSEMBLY_UNLOAD");
260
261 install_pe_loader ();
262
263 mutex_inited = TRUE;
264 }
265
266 /**
267 * mono_images_cleanup:
268 *
269 * Free all resources used by this module.
270 */
271 void
mono_images_cleanup(void)272 mono_images_cleanup (void)
273 {
274 GHashTableIter iter;
275 MonoImage *image;
276
277 mono_os_mutex_destroy (&images_mutex);
278
279 // If an assembly image is still loaded at shutdown, this could indicate managed code is still running.
280 // Reflection-only images being still loaded doesn't indicate anything as harmful, so we don't check for it.
281 g_hash_table_iter_init (&iter, get_loaded_images_hash (FALSE));
282 while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
283 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
284
285 int hash_idx;
286 for(hash_idx = 0; hash_idx < IMAGES_HASH_COUNT; hash_idx++)
287 g_hash_table_destroy (loaded_images_hashes [hash_idx]);
288
289 mutex_inited = FALSE;
290 }
291
292 /**
293 * mono_image_ensure_section_idx:
294 * \param image The image we are operating on
295 * \param section section number that we will load/map into memory
296 *
297 * This routine makes sure that we have an in-memory copy of
298 * an image section (<code>.text</code>, <code>.rsrc</code>, <code>.data</code>).
299 *
300 * \returns TRUE on success
301 */
302 int
mono_image_ensure_section_idx(MonoImage * image,int section)303 mono_image_ensure_section_idx (MonoImage *image, int section)
304 {
305 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
306 MonoSectionTable *sect;
307
308 g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
309
310 if (iinfo->cli_sections [section] != NULL)
311 return TRUE;
312
313 sect = &iinfo->cli_section_tables [section];
314
315 if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
316 return FALSE;
317 #ifdef HOST_WIN32
318 if (image->is_module_handle)
319 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
320 else
321 #endif
322 /* FIXME: we ignore the writable flag since we don't patch the binary */
323 iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
324 return TRUE;
325 }
326
327 /**
328 * mono_image_ensure_section:
329 * \param image The image we are operating on
330 * \param section section name that we will load/map into memory
331 *
332 * This routine makes sure that we have an in-memory copy of
333 * an image section (.text, .rsrc, .data).
334 *
335 * \returns TRUE on success
336 */
337 int
mono_image_ensure_section(MonoImage * image,const char * section)338 mono_image_ensure_section (MonoImage *image, const char *section)
339 {
340 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
341 int i;
342
343 for (i = 0; i < ii->cli_section_count; i++){
344 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
345 continue;
346
347 return mono_image_ensure_section_idx (image, i);
348 }
349 return FALSE;
350 }
351
352 static int
load_section_tables(MonoImage * image,MonoCLIImageInfo * iinfo,guint32 offset)353 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
354 {
355 const int top = iinfo->cli_header.coff.coff_sections;
356 int i;
357
358 iinfo->cli_section_count = top;
359 iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
360 iinfo->cli_sections = g_new0 (void *, top);
361
362 for (i = 0; i < top; i++){
363 MonoSectionTable *t = &iinfo->cli_section_tables [i];
364
365 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
366 return FALSE;
367 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
368 offset += sizeof (MonoSectionTable);
369
370 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
371 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
372 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
373 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
374 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
375 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
376 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
377 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
378 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
379 t->st_flags = GUINT32_FROM_LE (t->st_flags);
380 #endif
381 /* consistency checks here */
382 }
383
384 return TRUE;
385 }
386
387 gboolean
mono_image_load_cli_header(MonoImage * image,MonoCLIImageInfo * iinfo)388 mono_image_load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
389 {
390 guint32 offset;
391
392 offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
393 if (offset == INVALID_ADDRESS)
394 return FALSE;
395
396 if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
397 return FALSE;
398 memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
399
400 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
401 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
402 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
403 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
404 SWAP32 (iinfo->cli_cli_header.ch_size);
405 SWAP32 (iinfo->cli_cli_header.ch_flags);
406 SWAP32 (iinfo->cli_cli_header.ch_entry_point);
407 SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
408 SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
409 SWAPPDE (iinfo->cli_cli_header.ch_metadata);
410 SWAPPDE (iinfo->cli_cli_header.ch_resources);
411 SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
412 SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
413 SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
414 SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
415 SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
416 SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
417 SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
418 SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
419 SWAPPDE (iinfo->cli_cli_header.ch_module_image);
420 SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
421 SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
422 SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
423 SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
424 #undef SWAP32
425 #undef SWAP16
426 #undef SWAPPDE
427 #endif
428 /* Catch new uses of the fields that are supposed to be zero */
429
430 if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
431 (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
432 (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
433 (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
434 (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
435 (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
436 (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
437 (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
438 (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
439
440 /*
441 * No need to scare people who are testing this, I am just
442 * labelling this as a LAMESPEC
443 */
444 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
445
446 }
447
448 return TRUE;
449 }
450
451 static gboolean
load_metadata_ptrs(MonoImage * image,MonoCLIImageInfo * iinfo)452 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
453 {
454 guint32 offset, size;
455 guint16 streams;
456 int i;
457 guint32 pad;
458 char *ptr;
459
460 offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
461 if (offset == INVALID_ADDRESS)
462 return FALSE;
463
464 size = iinfo->cli_cli_header.ch_metadata.size;
465
466 if (offset + size > image->raw_data_len)
467 return FALSE;
468 image->raw_metadata = image->raw_data + offset;
469
470 /* 24.2.1: Metadata root starts here */
471 ptr = image->raw_metadata;
472
473 if (strncmp (ptr, "BSJB", 4) == 0){
474 guint32 version_string_len;
475
476 ptr += 4;
477 image->md_version_major = read16 (ptr);
478 ptr += 2;
479 image->md_version_minor = read16 (ptr);
480 ptr += 6;
481
482 version_string_len = read32 (ptr);
483 ptr += 4;
484 image->version = g_strndup (ptr, version_string_len);
485 ptr += version_string_len;
486 pad = ptr - image->raw_metadata;
487 if (pad % 4)
488 ptr += 4 - (pad % 4);
489 } else
490 return FALSE;
491
492 /* skip over flags */
493 ptr += 2;
494
495 streams = read16 (ptr);
496 ptr += 2;
497
498 for (i = 0; i < streams; i++){
499 if (strncmp (ptr + 8, "#~", 3) == 0){
500 image->heap_tables.data = image->raw_metadata + read32 (ptr);
501 image->heap_tables.size = read32 (ptr + 4);
502 ptr += 8 + 3;
503 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
504 image->heap_strings.data = image->raw_metadata + read32 (ptr);
505 image->heap_strings.size = read32 (ptr + 4);
506 ptr += 8 + 9;
507 } else if (strncmp (ptr + 8, "#US", 4) == 0){
508 image->heap_us.data = image->raw_metadata + read32 (ptr);
509 image->heap_us.size = read32 (ptr + 4);
510 ptr += 8 + 4;
511 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
512 image->heap_blob.data = image->raw_metadata + read32 (ptr);
513 image->heap_blob.size = read32 (ptr + 4);
514 ptr += 8 + 6;
515 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
516 image->heap_guid.data = image->raw_metadata + read32 (ptr);
517 image->heap_guid.size = read32 (ptr + 4);
518 ptr += 8 + 6;
519 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
520 image->heap_tables.data = image->raw_metadata + read32 (ptr);
521 image->heap_tables.size = read32 (ptr + 4);
522 ptr += 8 + 3;
523 image->uncompressed_metadata = TRUE;
524 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);
525 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
526 image->heap_pdb.data = image->raw_metadata + read32 (ptr);
527 image->heap_pdb.size = read32 (ptr + 4);
528 ptr += 8 + 5;
529 } else {
530 g_message ("Unknown heap type: %s\n", ptr + 8);
531 ptr += 8 + strlen (ptr + 8) + 1;
532 }
533 pad = ptr - image->raw_metadata;
534 if (pad % 4)
535 ptr += 4 - (pad % 4);
536 }
537
538 i = ((MonoImageLoader*)image->loader)->load_tables (image);
539
540 if (!image->metadata_only) {
541 g_assert (image->heap_guid.data);
542 g_assert (image->heap_guid.size >= 16);
543
544 image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
545 } else {
546 /* PPDB files have no guid */
547 guint8 empty_guid [16];
548
549 memset (empty_guid, 0, sizeof (empty_guid));
550
551 image->guid = mono_guid_to_string (empty_guid);
552 }
553
554 return i;
555 }
556
557 /*
558 * Load representation of logical metadata tables, from the "#~" stream
559 */
560 static gboolean
load_tables(MonoImage * image)561 load_tables (MonoImage *image)
562 {
563 const char *heap_tables = image->heap_tables.data;
564 const guint32 *rows;
565 guint64 valid_mask;
566 int valid = 0, table;
567 int heap_sizes;
568
569 heap_sizes = heap_tables [6];
570 image->idx_string_wide = ((heap_sizes & 0x01) == 1);
571 image->idx_guid_wide = ((heap_sizes & 0x02) == 2);
572 image->idx_blob_wide = ((heap_sizes & 0x04) == 4);
573
574 valid_mask = read64 (heap_tables + 8);
575 rows = (const guint32 *) (heap_tables + 24);
576
577 for (table = 0; table < 64; table++){
578 if ((valid_mask & ((guint64) 1 << table)) == 0){
579 if (table > MONO_TABLE_LAST)
580 continue;
581 image->tables [table].rows = 0;
582 continue;
583 }
584 if (table > MONO_TABLE_LAST) {
585 g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
586 } else {
587 image->tables [table].rows = read32 (rows);
588 }
589 rows++;
590 valid++;
591 }
592
593 image->tables_base = (heap_tables + 24) + (4 * valid);
594
595 /* They must be the same */
596 g_assert ((const void *) image->tables_base == (const void *) rows);
597
598 if (image->heap_pdb.size) {
599 /*
600 * Obtain token sizes from the pdb stream.
601 */
602 /* 24 = guid + entry point */
603 int pos = 24;
604 image->referenced_tables = read64 (image->heap_pdb.data + pos);
605 pos += 8;
606 image->referenced_table_rows = g_new0 (int, 64);
607 for (int i = 0; i < 64; ++i) {
608 if (image->referenced_tables & ((guint64)1 << i)) {
609 image->referenced_table_rows [i] = read32 (image->heap_pdb.data + pos);
610 pos += 4;
611 }
612 }
613 }
614
615 mono_metadata_compute_table_bases (image);
616 return TRUE;
617 }
618
619 gboolean
mono_image_load_metadata(MonoImage * image,MonoCLIImageInfo * iinfo)620 mono_image_load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
621 {
622 if (!load_metadata_ptrs (image, iinfo))
623 return FALSE;
624
625 return load_tables (image);
626 }
627
628 void
mono_image_check_for_module_cctor(MonoImage * image)629 mono_image_check_for_module_cctor (MonoImage *image)
630 {
631 MonoTableInfo *t, *mt;
632 t = &image->tables [MONO_TABLE_TYPEDEF];
633 mt = &image->tables [MONO_TABLE_METHOD];
634 if (image_is_dynamic (image)) {
635 /* FIXME: */
636 image->checked_module_cctor = TRUE;
637 return;
638 }
639 if (t->rows >= 1) {
640 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
641 const char *name = mono_metadata_string_heap (image, nameidx);
642 if (strcmp (name, "<Module>") == 0) {
643 guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
644 guint32 last_method;
645 if (t->rows > 1)
646 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
647 else
648 last_method = mt->rows;
649 for (; first_method < last_method; first_method++) {
650 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
651 name = mono_metadata_string_heap (image, nameidx);
652 if (strcmp (name, ".cctor") == 0) {
653 image->has_module_cctor = TRUE;
654 image->checked_module_cctor = TRUE;
655 return;
656 }
657 }
658 }
659 }
660 image->has_module_cctor = FALSE;
661 image->checked_module_cctor = TRUE;
662 }
663
664 static void
load_modules(MonoImage * image)665 load_modules (MonoImage *image)
666 {
667 MonoTableInfo *t;
668
669 if (image->modules)
670 return;
671
672 t = &image->tables [MONO_TABLE_MODULEREF];
673 image->modules = g_new0 (MonoImage *, t->rows);
674 image->modules_loaded = g_new0 (gboolean, t->rows);
675 image->module_count = t->rows;
676 }
677
678 /**
679 * mono_image_load_module_checked:
680 *
681 * Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
682 * it cannot be loaded. NULL without MonoError being set will be interpreted as "not found".
683 */
684 MonoImage*
mono_image_load_module_checked(MonoImage * image,int idx,MonoError * error)685 mono_image_load_module_checked (MonoImage *image, int idx, MonoError *error)
686 {
687 MonoTableInfo *t;
688 MonoTableInfo *file_table;
689 int i;
690 char *base_dir;
691 gboolean refonly = image->ref_only;
692 GList *list_iter, *valid_modules = NULL;
693 MonoImageOpenStatus status;
694
695 error_init (error);
696
697 if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
698 return NULL;
699 if (image->modules_loaded [idx - 1])
700 return image->modules [idx - 1];
701
702 file_table = &image->tables [MONO_TABLE_FILE];
703 for (i = 0; i < file_table->rows; i++) {
704 guint32 cols [MONO_FILE_SIZE];
705 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
706 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
707 continue;
708 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
709 }
710
711 t = &image->tables [MONO_TABLE_MODULEREF];
712 base_dir = g_path_get_dirname (image->name);
713
714 {
715 char *module_ref;
716 const char *name;
717 guint32 cols [MONO_MODULEREF_SIZE];
718 /* if there is no file table, we try to load the module... */
719 int valid = file_table->rows == 0;
720
721 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
722 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
723 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
724 /* be safe with string dups, but we could just compare string indexes */
725 if (strcmp (list_iter->data, name) == 0) {
726 valid = TRUE;
727 break;
728 }
729 }
730 if (valid) {
731 module_ref = g_build_filename (base_dir, name, NULL);
732 MonoImage *moduleImage = mono_image_open_full (module_ref, &status, refonly);
733 if (moduleImage) {
734 if (!assign_assembly_parent_for_netmodule (moduleImage, image, error)) {
735 mono_image_close (moduleImage);
736 g_free (module_ref);
737 g_free (base_dir);
738 g_list_free (valid_modules);
739 return NULL;
740 }
741
742 image->modules [idx - 1] = moduleImage;
743
744 #ifdef HOST_WIN32
745 if (image->modules [idx - 1]->is_module_handle)
746 mono_image_fixup_vtable (image->modules [idx - 1]);
747 #endif
748 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
749 }
750 g_free (module_ref);
751 }
752 }
753
754 image->modules_loaded [idx - 1] = TRUE;
755
756 g_free (base_dir);
757 g_list_free (valid_modules);
758
759 return image->modules [idx - 1];
760 }
761
762 /**
763 * mono_image_load_module:
764 */
765 MonoImage*
mono_image_load_module(MonoImage * image,int idx)766 mono_image_load_module (MonoImage *image, int idx)
767 {
768 MonoError error;
769 MonoImage *result = mono_image_load_module_checked (image, idx, &error);
770 mono_error_assert_ok (&error);
771 return result;
772 }
773
774 static gpointer
class_key_extract(gpointer value)775 class_key_extract (gpointer value)
776 {
777 MonoClass *klass = (MonoClass *)value;
778
779 return GUINT_TO_POINTER (klass->type_token);
780 }
781
782 static gpointer*
class_next_value(gpointer value)783 class_next_value (gpointer value)
784 {
785 MonoClassDef *klass = (MonoClassDef *)value;
786
787 return (gpointer*)&klass->next_class_cache;
788 }
789
790 /**
791 * mono_image_init:
792 */
793 void
mono_image_init(MonoImage * image)794 mono_image_init (MonoImage *image)
795 {
796 mono_os_mutex_init_recursive (&image->lock);
797 mono_os_mutex_init_recursive (&image->szarray_cache_lock);
798
799 image->mempool = mono_mempool_new_size (INITIAL_IMAGE_SIZE);
800 mono_internal_hash_table_init (&image->class_cache,
801 g_direct_hash,
802 class_key_extract,
803 class_next_value);
804 image->field_cache = mono_conc_hashtable_new (NULL, NULL);
805
806 image->typespec_cache = mono_conc_hashtable_new (NULL, NULL);
807 image->memberref_signatures = g_hash_table_new (NULL, NULL);
808 image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
809 image->method_signatures = g_hash_table_new (NULL, NULL);
810
811 image->property_hash = mono_property_hash_new ();
812 }
813
814 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
815 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
816 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
817 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
818 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
819 #else
820 #define SWAP64(x)
821 #define SWAP32(x)
822 #define SWAP16(x)
823 #define SWAPPDE(x)
824 #endif
825
826 /*
827 * Returns < 0 to indicate an error.
828 */
829 static int
do_load_header(MonoImage * image,MonoDotNetHeader * header,int offset)830 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
831 {
832 MonoDotNetHeader64 header64;
833
834 #ifdef HOST_WIN32
835 if (!image->is_module_handle)
836 #endif
837 if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
838 return -1;
839
840 memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
841
842 if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
843 return -1;
844
845 /* endian swap the fields common between PE and PE+ */
846 SWAP32 (header->coff.coff_time);
847 SWAP32 (header->coff.coff_symptr);
848 SWAP32 (header->coff.coff_symcount);
849 SWAP16 (header->coff.coff_machine);
850 SWAP16 (header->coff.coff_sections);
851 SWAP16 (header->coff.coff_opt_header_size);
852 SWAP16 (header->coff.coff_attributes);
853 /* MonoPEHeader */
854 SWAP32 (header->pe.pe_code_size);
855 SWAP32 (header->pe.pe_uninit_data_size);
856 SWAP32 (header->pe.pe_rva_entry_point);
857 SWAP32 (header->pe.pe_rva_code_base);
858 SWAP32 (header->pe.pe_rva_data_base);
859 SWAP16 (header->pe.pe_magic);
860
861 /* now we are ready for the basic tests */
862
863 if (header->pe.pe_magic == 0x10B) {
864 offset += sizeof (MonoDotNetHeader);
865 SWAP32 (header->pe.pe_data_size);
866 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
867 return -1;
868
869 SWAP32 (header->nt.pe_image_base); /* must be 0x400000 */
870 SWAP32 (header->nt.pe_stack_reserve);
871 SWAP32 (header->nt.pe_stack_commit);
872 SWAP32 (header->nt.pe_heap_reserve);
873 SWAP32 (header->nt.pe_heap_commit);
874 } else if (header->pe.pe_magic == 0x20B) {
875 /* PE32+ file format */
876 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
877 return -1;
878 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
879 offset += sizeof (MonoDotNetHeader64);
880 /* copy the fields already swapped. the last field, pe_data_size, is missing */
881 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
882 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
883 * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
884 */
885 SWAP64 (header64.nt.pe_image_base);
886 header->nt.pe_image_base = header64.nt.pe_image_base;
887 SWAP64 (header64.nt.pe_stack_reserve);
888 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
889 SWAP64 (header64.nt.pe_stack_commit);
890 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
891 SWAP64 (header64.nt.pe_heap_reserve);
892 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
893 SWAP64 (header64.nt.pe_heap_commit);
894 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
895
896 header->nt.pe_section_align = header64.nt.pe_section_align;
897 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
898 header->nt.pe_os_major = header64.nt.pe_os_major;
899 header->nt.pe_os_minor = header64.nt.pe_os_minor;
900 header->nt.pe_user_major = header64.nt.pe_user_major;
901 header->nt.pe_user_minor = header64.nt.pe_user_minor;
902 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
903 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
904 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
905 header->nt.pe_image_size = header64.nt.pe_image_size;
906 header->nt.pe_header_size = header64.nt.pe_header_size;
907 header->nt.pe_checksum = header64.nt.pe_checksum;
908 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
909 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
910 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
911 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
912
913 /* copy the datadir */
914 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
915 } else {
916 return -1;
917 }
918
919 /* MonoPEHeaderNT: not used yet */
920 SWAP32 (header->nt.pe_section_align); /* must be 8192 */
921 SWAP32 (header->nt.pe_file_alignment); /* must be 512 or 4096 */
922 SWAP16 (header->nt.pe_os_major); /* must be 4 */
923 SWAP16 (header->nt.pe_os_minor); /* must be 0 */
924 SWAP16 (header->nt.pe_user_major);
925 SWAP16 (header->nt.pe_user_minor);
926 SWAP16 (header->nt.pe_subsys_major);
927 SWAP16 (header->nt.pe_subsys_minor);
928 SWAP32 (header->nt.pe_reserved_1);
929 SWAP32 (header->nt.pe_image_size);
930 SWAP32 (header->nt.pe_header_size);
931 SWAP32 (header->nt.pe_checksum);
932 SWAP16 (header->nt.pe_subsys_required);
933 SWAP16 (header->nt.pe_dll_flags);
934 SWAP32 (header->nt.pe_loader_flags);
935 SWAP32 (header->nt.pe_data_dir_count);
936
937 /* MonoDotNetHeader: mostly unused */
938 SWAPPDE (header->datadir.pe_export_table);
939 SWAPPDE (header->datadir.pe_import_table);
940 SWAPPDE (header->datadir.pe_resource_table);
941 SWAPPDE (header->datadir.pe_exception_table);
942 SWAPPDE (header->datadir.pe_certificate_table);
943 SWAPPDE (header->datadir.pe_reloc_table);
944 SWAPPDE (header->datadir.pe_debug);
945 SWAPPDE (header->datadir.pe_copyright);
946 SWAPPDE (header->datadir.pe_global_ptr);
947 SWAPPDE (header->datadir.pe_tls_table);
948 SWAPPDE (header->datadir.pe_load_config_table);
949 SWAPPDE (header->datadir.pe_bound_import);
950 SWAPPDE (header->datadir.pe_iat);
951 SWAPPDE (header->datadir.pe_delay_import_desc);
952 SWAPPDE (header->datadir.pe_cli_header);
953 SWAPPDE (header->datadir.pe_reserved);
954
955 #ifdef HOST_WIN32
956 if (image->is_module_handle)
957 image->raw_data_len = header->nt.pe_image_size;
958 #endif
959
960 return offset;
961 }
962
963 gboolean
mono_image_load_pe_data(MonoImage * image)964 mono_image_load_pe_data (MonoImage *image)
965 {
966 return ((MonoImageLoader*)image->loader)->load_pe_data (image);
967 }
968
969 static gboolean
pe_image_load_pe_data(MonoImage * image)970 pe_image_load_pe_data (MonoImage *image)
971 {
972 MonoCLIImageInfo *iinfo;
973 MonoDotNetHeader *header;
974 MonoMSDOSHeader msdos;
975 gint32 offset = 0;
976
977 iinfo = (MonoCLIImageInfo *)image->image_info;
978 header = &iinfo->cli_header;
979
980 #ifdef HOST_WIN32
981 if (!image->is_module_handle)
982 #endif
983 if (offset + sizeof (msdos) > image->raw_data_len)
984 goto invalid_image;
985 memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
986
987 if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
988 goto invalid_image;
989
990 msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
991
992 offset = msdos.pe_offset;
993
994 offset = do_load_header (image, header, offset);
995 if (offset < 0)
996 goto invalid_image;
997
998 /*
999 * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
1000 * we skip this test.
1001 if (header->coff.coff_machine != 0x14c)
1002 goto invalid_image;
1003 */
1004
1005 #if 0
1006 /*
1007 * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
1008 * which produces binaries with 7.0. From Sergey:
1009 *
1010 * The reason is that MSVC7 uses traditional compile/link
1011 * sequence for CIL executables, and VS.NET (and Framework
1012 * SDK) includes linker version 7, that puts 7.0 in this
1013 * field. That's why it's currently not possible to load VC
1014 * binaries with Mono. This field is pretty much meaningless
1015 * anyway (what linker?).
1016 */
1017 if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
1018 goto invalid_image;
1019 #endif
1020
1021 /*
1022 * FIXME: byte swap all addresses here for header.
1023 */
1024
1025 if (!load_section_tables (image, iinfo, offset))
1026 goto invalid_image;
1027
1028 return TRUE;
1029
1030 invalid_image:
1031 return FALSE;
1032 }
1033
1034 gboolean
mono_image_load_cli_data(MonoImage * image)1035 mono_image_load_cli_data (MonoImage *image)
1036 {
1037 return ((MonoImageLoader*)image->loader)->load_cli_data (image);
1038 }
1039
1040 static gboolean
pe_image_load_cli_data(MonoImage * image)1041 pe_image_load_cli_data (MonoImage *image)
1042 {
1043 MonoCLIImageInfo *iinfo;
1044 MonoDotNetHeader *header;
1045
1046 iinfo = (MonoCLIImageInfo *)image->image_info;
1047 header = &iinfo->cli_header;
1048
1049 /* Load the CLI header */
1050 if (!mono_image_load_cli_header (image, iinfo))
1051 return FALSE;
1052
1053 if (!mono_image_load_metadata (image, iinfo))
1054 return FALSE;
1055
1056 return TRUE;
1057 }
1058
1059 void
mono_image_load_names(MonoImage * image)1060 mono_image_load_names (MonoImage *image)
1061 {
1062 /* modules don't have an assembly table row */
1063 if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
1064 image->assembly_name = mono_metadata_string_heap (image,
1065 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
1066 0, MONO_ASSEMBLY_NAME));
1067 }
1068
1069 /* Portable pdb images don't have a MODULE row */
1070 if (image->tables [MONO_TABLE_MODULE].rows) {
1071 image->module_name = mono_metadata_string_heap (image,
1072 mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
1073 0, MONO_MODULE_NAME));
1074 }
1075 }
1076
1077 static gboolean
pe_image_load_tables(MonoImage * image)1078 pe_image_load_tables (MonoImage *image)
1079 {
1080 return TRUE;
1081 }
1082
1083 static gboolean
pe_image_match(MonoImage * image)1084 pe_image_match (MonoImage *image)
1085 {
1086 if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
1087 return TRUE;
1088 return FALSE;
1089 }
1090
1091 static const MonoImageLoader pe_loader = {
1092 pe_image_match,
1093 pe_image_load_pe_data,
1094 pe_image_load_cli_data,
1095 pe_image_load_tables,
1096 };
1097
1098 static void
install_pe_loader(void)1099 install_pe_loader (void)
1100 {
1101 mono_install_image_loader (&pe_loader);
1102 }
1103
1104 /*
1105 Ignored assemblies.
1106
1107 There are some assemblies we need to ignore because they include an implementation that doesn't work under mono.
1108 Mono provides its own implementation of those assemblies so it's safe to do so.
1109
1110 The ignored_assemblies list is generated using tools/nuget-hash-extractor and feeding the problematic nugets to it.
1111
1112 Right now the list of nugets are the ones that provide the assemblies in $ignored_assemblies_file_names.
1113
1114 This is to be removed once a proper fix is shipped through nuget.
1115
1116 Please keep this in sync with mcs/tools/xbuild/data/deniedAssembliesList.txt
1117 If any assemblies are added/removed, then this should be regenerated with:
1118
1119 $ mono tools/nuget-hash-extractor/nuget-hash-extractor.exe nugets guids_for_msbuild > mcs/tools/xbuild/data/deniedAssembliesList.txt
1120
1121 */
1122
1123 typedef enum {
1124 SYS_RT_INTEROP_RUNTIME_INFO = 0, //System.Runtime.InteropServices.RuntimeInformation
1125 SYS_GLOBALIZATION_EXT = 1, //System.Globalization.Extensions
1126 SYS_IO_COMPRESSION = 2, //System.IO.Compression
1127 SYS_NET_HTTP = 3, //System.Net.Http
1128 SYS_TEXT_ENC_CODEPAGES = 4, //System.Text.Encoding.CodePages
1129 SYS_THREADING_OVERLAPPED = 5, //System.Threading.Overlapped
1130 } IgnoredAssemblyNames;
1131
1132 typedef struct {
1133 int hash;
1134 int assembly_name;
1135 const char guid [40];
1136 } IgnoredAssembly;
1137
1138 typedef struct {
1139 int assembly_name;
1140 guint16 major, minor, build, revision;
1141 } IgnoredAssemblyVersion;
1142
1143 const char *ignored_assemblies_file_names[] = {
1144 "System.Runtime.InteropServices.RuntimeInformation.dll",
1145 "System.Globalization.Extensions.dll",
1146 "System.IO.Compression.dll",
1147 "System.Net.Http.dll",
1148 "System.Text.Encoding.CodePages.dll",
1149 "System.Threading.Overlapped.dll"
1150 };
1151
1152 #define IGNORED_ASSEMBLY(HASH, NAME, GUID, VER_STR) { .hash = HASH, .assembly_name = NAME, .guid = GUID }
1153
1154 static const IgnoredAssembly ignored_assemblies [] = {
1155 IGNORED_ASSEMBLY (0xE4016B17, SYS_GLOBALIZATION_EXT, "50F4163A-D692-452F-90ED-2F8024BB5319", "15.5.0-preview-20171027-2 net461"),
1156 IGNORED_ASSEMBLY (0xC69BED92, SYS_IO_COMPRESSION, "33AD8174-7781-46FA-A110-33821CCBE810", "15.5.0-preview-20171027-2 net461"),
1157 IGNORED_ASSEMBLY (0xD08A991A, SYS_NET_HTTP, "82C79759-CB3C-4EB6-A17C-BDE85AF00A9B", "15.5.0-preview-20171027-2 net461"),
1158 IGNORED_ASSEMBLY (0x1438EAE0, SYS_RT_INTEROP_RUNTIME_INFO, "F580BAAC-12BD-4716-B486-C0A5E3EE6EEA", "15.5.0-preview-20171027-2 net461"),
1159 IGNORED_ASSEMBLY (0x79F6E37F, SYS_THREADING_OVERLAPPED, "212BEDF2-E3F5-4D59-8C1A-F4D1C58B46CD", "15.5.0-preview-20171027-2 net461"),
1160 IGNORED_ASSEMBLY (0xA3BFE786, SYS_RT_INTEROP_RUNTIME_INFO, "33D296D9-EE6D-404E-BF9F-432A429FF5DA", "15.5.0-preview-20171027-2 net462"),
1161 IGNORED_ASSEMBLY (0x74EA304F, SYS_RT_INTEROP_RUNTIME_INFO, "E5AE3324-2100-4F77-9E41-AEEF226C9649", "15.5.0-preview-20171027-2 net47"),
1162 IGNORED_ASSEMBLY (0x4CC79B26, SYS_GLOBALIZATION_EXT, "28006E9A-74DB-45AC-8A8D-030CEBAA272A", "2.0.0-preview3-20170622-1 net461"),
1163 IGNORED_ASSEMBLY (0xC8D00759, SYS_IO_COMPRESSION, "1332CE2F-1517-4BD7-93FD-7D4BCFBAED66", "2.0.0-preview3-20170622-1 net461"),
1164 IGNORED_ASSEMBLY (0x2706B80, SYS_NET_HTTP, "8E2F55F3-D010-417B-A742-21386EDDD388", "2.0.0-preview3-20170622-1 net461"),
1165 IGNORED_ASSEMBLY (0xA2E8EC53, SYS_RT_INTEROP_RUNTIME_INFO, "6D334D4D-0149-4D07-9DEF-CC52213145CE", "2.0.0-preview3-20170622-1 net461"),
1166 IGNORED_ASSEMBLY (0x90772EB6, SYS_THREADING_OVERLAPPED, "F4FFC4A6-E694-49D9-81B2-12F2C9A29652", "2.0.0-preview3-20170622-1 net461"),
1167 IGNORED_ASSEMBLY (0x16BCA997, SYS_RT_INTEROP_RUNTIME_INFO, "CA2D23DE-55E1-45D8-9720-0EBE3EEC1DF2", "2.0.0-preview3-20170622-1 net462"),
1168 IGNORED_ASSEMBLY (0x786145B9, SYS_RT_INTEROP_RUNTIME_INFO, "0C4BCFB3-F609-4631-93A6-17B19C69D9B6", "2.0.0-preview3-20170622-1 net47"),
1169 IGNORED_ASSEMBLY (0xF9D06E1E, SYS_GLOBALIZATION_EXT, "FC1439FC-C1B8-4DB1-914D-165CCFA77002", "2.1.0-preview1-62414-02 net461"),
1170 IGNORED_ASSEMBLY (0x1EA951BB, SYS_IO_COMPRESSION, "05C07BD4-AFF1-4B12-900B-F0A5EB88DDB4", "2.1.0-preview1-62414-02 net461"),
1171 IGNORED_ASSEMBLY (0x96B5F0BA, SYS_NET_HTTP, "DB06A592-E332-44A1-8B85-20CAB3C3C147", "2.1.0-preview1-62414-02 net461"),
1172 IGNORED_ASSEMBLY (0xCA951D5B, SYS_RT_INTEROP_RUNTIME_INFO, "1F37581E-4589-4C71-A465-05C6B9AE966E", "2.1.0-preview1-62414-02 net461"),
1173 IGNORED_ASSEMBLY (0x284ECF63, SYS_THREADING_OVERLAPPED, "E933407E-C846-4413-82C5-09F4BCFA67F1", "2.1.0-preview1-62414-02 net461"),
1174 IGNORED_ASSEMBLY (0x8CCF2469, SYS_RT_INTEROP_RUNTIME_INFO, "9A3724BF-DF8F-4955-8CFA-41D45F11B586", "2.1.0-preview1-62414-02 net462"),
1175 IGNORED_ASSEMBLY (0x39C3575D, SYS_GLOBALIZATION_EXT, "3B30D67C-B16B-47BC-B949-9500B5AAAAFB", "2.1.0-preview1-62414-02 net471"),
1176 IGNORED_ASSEMBLY (0x662BC58F, SYS_IO_COMPRESSION, "C786B28D-0850-4D4C-AED9-FE6B86EE7C31", "2.1.0-preview1-62414-02 net471"),
1177 IGNORED_ASSEMBLY (0x9DBB28A2, SYS_NET_HTTP, "903A137B-BB3F-464A-94D4-780B89EE5580", "2.1.0-preview1-62414-02 net471"),
1178 IGNORED_ASSEMBLY (0xD00F7419, SYS_THREADING_OVERLAPPED, "3336A2A3-1772-4EF9-A74B-AFDC80A8B21E", "2.1.0-preview1-62414-02 net471"),
1179 IGNORED_ASSEMBLY (0x17A113, SYS_RT_INTEROP_RUNTIME_INFO, "D87389D8-6E9C-48CF-B128-3637018577AF", "2.1.0-preview1-62414-02 net47"),
1180 IGNORED_ASSEMBLY (0x1136045D, SYS_GLOBALIZATION_EXT, "475DBF02-9F68-44F1-8FB5-C9F69F1BD2B1", "4.0.0 net46"),
1181 IGNORED_ASSEMBLY (0x358C9723, SYS_GLOBALIZATION_EXT, "5FCD54F0-4B97-4259-875D-30E481F02EA2", "4.0.1 net46"),
1182 IGNORED_ASSEMBLY (0x450A096A, SYS_GLOBALIZATION_EXT, "E9FCFF5B-4DE1-4BDC-9CE8-08C640FC78CC", "4.3.0 net46"),
1183 IGNORED_ASSEMBLY (0x1CBD59A2, SYS_IO_COMPRESSION, "44FCA06C-A510-4B3E-BDBF-D08D697EF65A", "4.1.0 net46"),
1184 IGNORED_ASSEMBLY (0x5E393C29, SYS_IO_COMPRESSION, "3A58A219-266B-47C3-8BE8-4E4F394147AB", "4.3.0 net46"),
1185 IGNORED_ASSEMBLY (0x27726A90, SYS_NET_HTTP, "269B562C-CC15-4736-B1B1-68D4A43CAA98", "4.1.0 net46"),
1186 IGNORED_ASSEMBLY (0x10CADA75, SYS_NET_HTTP, "EA2EC6DC-51DD-479C-BFC2-E713FB9E7E47", "4.1.1 net46"),
1187 IGNORED_ASSEMBLY (0x8437178B, SYS_NET_HTTP, "C0E04D9C-70CF-48A6-A179-FBFD8CE69FD0", "4.3.0 net46"),
1188 IGNORED_ASSEMBLY (0xFAFDA422, SYS_NET_HTTP, "817F01C3-4011-477D-890A-98232B85553D", "4.3.1 net46"),
1189 IGNORED_ASSEMBLY (0x472FA630, SYS_NET_HTTP, "09D4A140-061C-4884-9B63-22067E841931", "4.3.2 net46"),
1190 IGNORED_ASSEMBLY (0xDB9397A9, SYS_NET_HTTP, "56203551-6937-47C1-9246-346A733913EE", "4.3.3 net46"),
1191 IGNORED_ASSEMBLY (0x46A4A1C5, SYS_RT_INTEROP_RUNTIME_INFO, "F13660F8-9D0D-419F-BA4E-315693DD26EA", "4.0.0 net45"),
1192 IGNORED_ASSEMBLY (0xD07383BB, SYS_RT_INTEROP_RUNTIME_INFO, "DD91439F-3167-478E-BD2C-BF9C036A1395", "4.3.0 net45"),
1193 IGNORED_ASSEMBLY (0x911D9EC3, SYS_TEXT_ENC_CODEPAGES, "C142254F-DEB5-46A7-AE43-6F10320D1D1F", "4.0.1 net46"),
1194 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.3.0 net46"),
1195 IGNORED_ASSEMBLY (0xFA686A38, SYS_TEXT_ENC_CODEPAGES, "FD178CD4-EF4F-44D5-9C3F-812B1E25126B", "4.4.0 net46"),
1196 IGNORED_ASSEMBLY (0xF6D18A2E, SYS_TEXT_ENC_CODEPAGES, "F5CCCBEC-E1AD-4DBB-9B44-9B42C86B94B8", "4.4.0 net461"),
1197 IGNORED_ASSEMBLY (0xAA21986B, SYS_THREADING_OVERLAPPED, "9F5D4F09-787A-458A-BA08-553AA71470F1", "4.0.0 net46"),
1198 IGNORED_ASSEMBLY (0x7D927C2A, SYS_THREADING_OVERLAPPED, "FCBD003B-2BB4-4940-BAEF-63AF520C2336", "4.0.1 net46"),
1199 IGNORED_ASSEMBLY (0x6FE03EE2, SYS_THREADING_OVERLAPPED, "87697E71-D192-4F0B-BAD4-02BBC7793005", "4.3.0 net46")
1200 };
1201
1202
1203 const char *ignored_assemblies_names[] = {
1204 "System.Runtime.InteropServices.RuntimeInformation",
1205 "System.Globalization.Extensions",
1206 "System.IO.Compression",
1207 "System.Net.Http",
1208 "System.Text.Encoding.CodePages",
1209 "System.Threading.Overlapped"
1210 };
1211
1212 #define IGNORED_ASM_VER(NAME, MAJOR, MINOR, BUILD, REVISION) { .assembly_name = NAME, .major = MAJOR, .minor = MINOR, .build = BUILD, .revision = REVISION }
1213
1214 static const IgnoredAssemblyVersion ignored_assembly_versions [] = {
1215 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 0, 0),
1216 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 1, 0),
1217 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 0, 2, 0),
1218 IGNORED_ASM_VER (SYS_GLOBALIZATION_EXT, 4, 1, 0, 0),
1219 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 0, 0),
1220 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 1, 2, 0),
1221 IGNORED_ASM_VER (SYS_IO_COMPRESSION, 4, 2, 0, 0),
1222 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 0),
1223 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 0, 1),
1224 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 0),
1225 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 1),
1226 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 1, 1, 2),
1227 IGNORED_ASM_VER (SYS_NET_HTTP, 4, 2, 0, 0),
1228 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 0, 0),
1229 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 1, 0),
1230 IGNORED_ASM_VER (SYS_RT_INTEROP_RUNTIME_INFO, 4, 0, 2, 0),
1231 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 1, 0),
1232 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 0, 2, 0),
1233 IGNORED_ASM_VER (SYS_TEXT_ENC_CODEPAGES, 4, 1, 0, 0),
1234 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 0, 0),
1235 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 1, 0),
1236 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 0, 2, 0),
1237 IGNORED_ASM_VER (SYS_THREADING_OVERLAPPED, 4, 1, 0, 0)
1238 };
1239
1240 gboolean
mono_assembly_is_problematic_version(const char * name,guint16 major,guint16 minor,guint16 build,guint16 revision)1241 mono_assembly_is_problematic_version (const char *name, guint16 major, guint16 minor, guint16 build, guint16 revision)
1242 {
1243 for (int i = 0; i < G_N_ELEMENTS (ignored_assembly_versions); ++i) {
1244 if (ignored_assembly_versions [i].major != major ||
1245 ignored_assembly_versions [i].minor != minor ||
1246 ignored_assembly_versions [i].build != build ||
1247 ignored_assembly_versions [i].revision != revision)
1248 continue;
1249 if (!strcmp (ignored_assemblies_names [ignored_assembly_versions [i].assembly_name], name))
1250 return TRUE;
1251 }
1252 return FALSE;
1253 }
1254
1255 /*
1256 Equivalent C# code:
1257 static void Main () {
1258 string str = "...";
1259 int h = 5381;
1260 for (int i = 0; i < str.Length; ++i)
1261 h = ((h << 5) + h) ^ str[i];
1262
1263 Console.WriteLine ("{0:X}", h);
1264 }
1265 */
1266 static int
hash_guid(const char * str)1267 hash_guid (const char *str)
1268 {
1269 int h = 5381;
1270 while (*str) {
1271 h = ((h << 5) + h) ^ *str;
1272 ++str;
1273 }
1274
1275 return h;
1276 }
1277
1278 static gboolean
is_problematic_image(MonoImage * image)1279 is_problematic_image (MonoImage *image)
1280 {
1281 int h = hash_guid (image->guid);
1282
1283 //TODO make this more cache effiecient.
1284 // Either sort by hash and bseach or use SoA and make the linear search more cache efficient.
1285 for (int i = 0; i < G_N_ELEMENTS (ignored_assemblies); ++i) {
1286 if (ignored_assemblies [i].hash == h && !strcmp (image->guid, ignored_assemblies [i].guid)) {
1287 const char *needle = ignored_assemblies_file_names [ignored_assemblies [i].assembly_name];
1288 size_t needle_len = strlen (needle);
1289 size_t asm_len = strlen (image->name);
1290 if (asm_len > needle_len && !g_ascii_strcasecmp (image->name + (asm_len - needle_len), needle))
1291 return TRUE;
1292 }
1293 }
1294 return FALSE;
1295 }
1296
1297 static MonoImage *
do_mono_image_load(MonoImage * image,MonoImageOpenStatus * status,gboolean care_about_cli,gboolean care_about_pecoff)1298 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
1299 gboolean care_about_cli, gboolean care_about_pecoff)
1300 {
1301 MonoCLIImageInfo *iinfo;
1302 MonoDotNetHeader *header;
1303 GSList *errors = NULL;
1304 GSList *l;
1305
1306 MONO_PROFILER_RAISE (image_loading, (image));
1307
1308 mono_image_init (image);
1309
1310 iinfo = (MonoCLIImageInfo *)image->image_info;
1311 header = &iinfo->cli_header;
1312
1313 if (!image->metadata_only) {
1314 for (l = image_loaders; l; l = l->next) {
1315 MonoImageLoader *loader = (MonoImageLoader *)l->data;
1316 if (loader->match (image)) {
1317 image->loader = loader;
1318 break;
1319 }
1320 }
1321 if (!image->loader) {
1322 if (status)
1323 *status = MONO_IMAGE_IMAGE_INVALID;
1324 goto invalid_image;
1325 }
1326
1327 if (status)
1328 *status = MONO_IMAGE_IMAGE_INVALID;
1329
1330 if (care_about_pecoff == FALSE)
1331 goto done;
1332
1333 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1334 goto invalid_image;
1335
1336 if (!mono_image_load_pe_data (image))
1337 goto invalid_image;
1338 } else {
1339 image->loader = (MonoImageLoader*)&pe_loader;
1340 }
1341
1342 if (care_about_cli == FALSE) {
1343 goto done;
1344 }
1345
1346 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
1347 goto invalid_image;
1348
1349 if (!mono_image_load_cli_data (image))
1350 goto invalid_image;
1351
1352 if (!image->ref_only && is_problematic_image (image)) {
1353 if (image->load_from_context) {
1354 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Loading problematic image %s", image->name);
1355 } else {
1356 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Denying load of problematic image %s", image->name);
1357 *status = MONO_IMAGE_IMAGE_INVALID;
1358 goto invalid_image;
1359 }
1360 }
1361
1362 if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
1363 goto invalid_image;
1364
1365 mono_image_load_names (image);
1366
1367 load_modules (image);
1368
1369 done:
1370 MONO_PROFILER_RAISE (image_loaded, (image));
1371 if (status)
1372 *status = MONO_IMAGE_OK;
1373
1374 return image;
1375
1376 invalid_image:
1377 if (errors) {
1378 MonoVerifyInfo *info = (MonoVerifyInfo *)errors->data;
1379 g_warning ("Could not load image %s due to %s", image->name, info->message);
1380 mono_free_verify_list (errors);
1381 }
1382 MONO_PROFILER_RAISE (image_failed, (image));
1383 mono_image_close (image);
1384 return NULL;
1385 }
1386
1387 static MonoImage *
do_mono_image_open(const char * fname,MonoImageOpenStatus * status,gboolean care_about_cli,gboolean care_about_pecoff,gboolean refonly,gboolean metadata_only,gboolean load_from_context)1388 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1389 gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only, gboolean load_from_context)
1390 {
1391 MonoCLIImageInfo *iinfo;
1392 MonoImage *image;
1393 MonoFileMap *filed;
1394
1395 if ((filed = mono_file_map_open (fname)) == NULL){
1396 if (IS_PORTABILITY_SET) {
1397 gchar *ffname = mono_portability_find_file (fname, TRUE);
1398 if (ffname) {
1399 filed = mono_file_map_open (ffname);
1400 g_free (ffname);
1401 }
1402 }
1403
1404 if (filed == NULL) {
1405 if (status)
1406 *status = MONO_IMAGE_ERROR_ERRNO;
1407 return NULL;
1408 }
1409 }
1410
1411 image = g_new0 (MonoImage, 1);
1412 image->raw_buffer_used = TRUE;
1413 image->raw_data_len = mono_file_map_size (filed);
1414 image->raw_data = (char *)mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1415 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1416 if (!image->raw_data) {
1417 image->fileio_used = TRUE;
1418 image->raw_data = (char *)mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1419 }
1420 #endif
1421 if (!image->raw_data) {
1422 mono_file_map_close (filed);
1423 g_free (image);
1424 if (status)
1425 *status = MONO_IMAGE_IMAGE_INVALID;
1426 return NULL;
1427 }
1428 iinfo = g_new0 (MonoCLIImageInfo, 1);
1429 image->image_info = iinfo;
1430 image->name = mono_path_resolve_symlinks (fname);
1431 image->ref_only = refonly;
1432 image->metadata_only = metadata_only;
1433 image->load_from_context = load_from_context;
1434 image->ref_count = 1;
1435 /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1436 image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1437
1438 mono_file_map_close (filed);
1439 return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1440 }
1441
1442 /**
1443 * mono_image_loaded_full:
1444 * \param name path or assembly name of the image to load
1445 * \param refonly Check with respect to reflection-only loads?
1446 *
1447 * This routine verifies that the given image is loaded.
1448 * It checks either reflection-only loads only, or normal loads only, as specified by parameter.
1449 *
1450 * \returns the loaded \c MonoImage, or NULL on failure.
1451 */
1452 MonoImage *
mono_image_loaded_full(const char * name,gboolean refonly)1453 mono_image_loaded_full (const char *name, gboolean refonly)
1454 {
1455 MonoImage *res;
1456
1457 mono_images_lock ();
1458 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_hash (refonly), name);
1459 if (!res)
1460 res = (MonoImage *)g_hash_table_lookup (get_loaded_images_by_name_hash (refonly), name);
1461 mono_images_unlock ();
1462
1463 return res;
1464 }
1465
1466 /**
1467 * mono_image_loaded:
1468 * \param name path or assembly name of the image to load
1469 * This routine verifies that the given image is loaded. Reflection-only loads do not count.
1470 * \returns the loaded \c MonoImage, or NULL on failure.
1471 */
1472 MonoImage *
mono_image_loaded(const char * name)1473 mono_image_loaded (const char *name)
1474 {
1475 return mono_image_loaded_full (name, FALSE);
1476 }
1477
1478 typedef struct {
1479 MonoImage *res;
1480 const char* guid;
1481 } GuidData;
1482
1483 static void
find_by_guid(gpointer key,gpointer val,gpointer user_data)1484 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1485 {
1486 GuidData *data = (GuidData *)user_data;
1487 MonoImage *image;
1488
1489 if (data->res)
1490 return;
1491 image = (MonoImage *)val;
1492 if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1493 data->res = image;
1494 }
1495
1496 /**
1497 * mono_image_loaded_by_guid_full:
1498 */
1499 MonoImage *
mono_image_loaded_by_guid_full(const char * guid,gboolean refonly)1500 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1501 {
1502 GuidData data;
1503 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1504 data.res = NULL;
1505 data.guid = guid;
1506
1507 mono_images_lock ();
1508 g_hash_table_foreach (loaded_images, find_by_guid, &data);
1509 mono_images_unlock ();
1510 return data.res;
1511 }
1512
1513 /**
1514 * mono_image_loaded_by_guid:
1515 */
1516 MonoImage *
mono_image_loaded_by_guid(const char * guid)1517 mono_image_loaded_by_guid (const char *guid)
1518 {
1519 return mono_image_loaded_by_guid_full (guid, FALSE);
1520 }
1521
1522 static MonoImage *
register_image(MonoImage * image)1523 register_image (MonoImage *image)
1524 {
1525 MonoImage *image2;
1526 GHashTable *loaded_images = get_loaded_images_hash (image->ref_only);
1527
1528 mono_images_lock ();
1529 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1530
1531 if (image2) {
1532 /* Somebody else beat us to it */
1533 mono_image_addref (image2);
1534 mono_images_unlock ();
1535 mono_image_close (image);
1536 return image2;
1537 }
1538
1539 GHashTable *loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1540 g_hash_table_insert (loaded_images, image->name, image);
1541 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == NULL))
1542 g_hash_table_insert (loaded_images_by_name, (char *) image->assembly_name, image);
1543 mono_images_unlock ();
1544
1545 return image;
1546 }
1547
1548 MonoImage *
mono_image_open_from_data_internal(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status,gboolean refonly,gboolean metadata_only,const char * name)1549 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1550 {
1551 MonoCLIImageInfo *iinfo;
1552 MonoImage *image;
1553 char *datac;
1554
1555 if (!data || !data_len) {
1556 if (status)
1557 *status = MONO_IMAGE_IMAGE_INVALID;
1558 return NULL;
1559 }
1560 datac = data;
1561 if (need_copy) {
1562 datac = (char *)g_try_malloc (data_len);
1563 if (!datac) {
1564 if (status)
1565 *status = MONO_IMAGE_ERROR_ERRNO;
1566 return NULL;
1567 }
1568 memcpy (datac, data, data_len);
1569 }
1570
1571 image = g_new0 (MonoImage, 1);
1572 image->raw_data = datac;
1573 image->raw_data_len = data_len;
1574 image->raw_data_allocated = need_copy;
1575 image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1576 iinfo = g_new0 (MonoCLIImageInfo, 1);
1577 image->image_info = iinfo;
1578 image->ref_only = refonly;
1579 image->metadata_only = metadata_only;
1580 image->ref_count = 1;
1581
1582 image = do_mono_image_load (image, status, TRUE, TRUE);
1583 if (image == NULL)
1584 return NULL;
1585
1586 return register_image (image);
1587 }
1588
1589 /**
1590 * mono_image_open_from_data_with_name:
1591 */
1592 MonoImage *
mono_image_open_from_data_with_name(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status,gboolean refonly,const char * name)1593 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1594 {
1595 return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1596 }
1597
1598 /**
1599 * mono_image_open_from_data_full:
1600 */
1601 MonoImage *
mono_image_open_from_data_full(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status,gboolean refonly)1602 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1603 {
1604 return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1605 }
1606
1607 /**
1608 * mono_image_open_from_data:
1609 */
1610 MonoImage *
mono_image_open_from_data(char * data,guint32 data_len,gboolean need_copy,MonoImageOpenStatus * status)1611 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1612 {
1613 return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1614 }
1615
1616 #ifdef HOST_WIN32
1617 /* fname is not duplicated. */
1618 MonoImage*
mono_image_open_from_module_handle(HMODULE module_handle,char * fname,gboolean has_entry_point,MonoImageOpenStatus * status)1619 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1620 {
1621 MonoImage* image;
1622 MonoCLIImageInfo* iinfo;
1623
1624 image = g_new0 (MonoImage, 1);
1625 image->raw_data = (char*) module_handle;
1626 image->is_module_handle = TRUE;
1627 iinfo = g_new0 (MonoCLIImageInfo, 1);
1628 image->image_info = iinfo;
1629 image->name = fname;
1630 image->ref_count = has_entry_point ? 0 : 1;
1631 image->has_entry_point = has_entry_point;
1632
1633 image = do_mono_image_load (image, status, TRUE, TRUE);
1634 if (image == NULL)
1635 return NULL;
1636
1637 return register_image (image);
1638 }
1639 #endif
1640
1641 /**
1642 * mono_image_open_full:
1643 */
1644 MonoImage *
mono_image_open_full(const char * fname,MonoImageOpenStatus * status,gboolean refonly)1645 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1646 {
1647 return mono_image_open_a_lot (fname, status, refonly, FALSE);
1648 }
1649
1650 MonoImage *
mono_image_open_a_lot(const char * fname,MonoImageOpenStatus * status,gboolean refonly,gboolean load_from_context)1651 mono_image_open_a_lot (const char *fname, MonoImageOpenStatus *status, gboolean refonly, gboolean load_from_context)
1652 {
1653 MonoImage *image;
1654 GHashTable *loaded_images = get_loaded_images_hash (refonly);
1655 char *absfname;
1656
1657 g_return_val_if_fail (fname != NULL, NULL);
1658
1659 #ifdef HOST_WIN32
1660 // Win32 path: If we are running with mixed-mode assemblies enabled (ie have loaded mscoree.dll),
1661 // then assemblies need to be loaded with LoadLibrary:
1662 if (!refonly && coree_module_handle) {
1663 HMODULE module_handle;
1664 guint16 *fname_utf16;
1665 DWORD last_error;
1666
1667 absfname = mono_path_resolve_symlinks (fname);
1668 fname_utf16 = NULL;
1669
1670 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1671 mono_images_lock ();
1672 image = g_hash_table_lookup (loaded_images, absfname);
1673 if (image) { // Image already loaded
1674 g_assert (image->is_module_handle);
1675 if (image->has_entry_point && image->ref_count == 0) {
1676 /* Increment reference count on images loaded outside of the runtime. */
1677 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1678 /* The image is already loaded because _CorDllMain removes images from the hash. */
1679 module_handle = LoadLibrary (fname_utf16);
1680 g_assert (module_handle == (HMODULE) image->raw_data);
1681 }
1682 mono_image_addref (image);
1683 mono_images_unlock ();
1684 if (fname_utf16)
1685 g_free (fname_utf16);
1686 g_free (absfname);
1687 return image;
1688 }
1689
1690 // Image not loaded, load it now
1691 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1692 module_handle = MonoLoadImage (fname_utf16);
1693 if (status && module_handle == NULL)
1694 last_error = mono_w32error_get_last ();
1695
1696 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1697 image = g_hash_table_lookup (loaded_images, absfname);
1698 if (image)
1699 mono_image_addref (image);
1700 mono_images_unlock ();
1701
1702 g_free (fname_utf16);
1703
1704 if (module_handle == NULL) {
1705 g_assert (!image);
1706 g_free (absfname);
1707 if (status) {
1708 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1709 *status = MONO_IMAGE_IMAGE_INVALID;
1710 else {
1711 if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1712 errno = ENOENT;
1713 else
1714 errno = 0;
1715 }
1716 }
1717 return NULL;
1718 }
1719
1720 if (image) {
1721 g_assert (image->is_module_handle);
1722 g_assert (image->has_entry_point);
1723 g_free (absfname);
1724 return image;
1725 }
1726
1727 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1728 }
1729 #endif
1730
1731 absfname = mono_path_resolve_symlinks (fname);
1732
1733 /*
1734 * The easiest solution would be to do all the loading inside the mutex,
1735 * but that would lead to scalability problems. So we let the loading
1736 * happen outside the mutex, and if multiple threads happen to load
1737 * the same image, we discard all but the first copy.
1738 */
1739 mono_images_lock ();
1740 image = (MonoImage *)g_hash_table_lookup (loaded_images, absfname);
1741 g_free (absfname);
1742
1743 if (image) { // Image already loaded
1744 mono_image_addref (image);
1745 mono_images_unlock ();
1746 return image;
1747 }
1748 mono_images_unlock ();
1749
1750 // Image not loaded, load it now
1751 image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE, load_from_context);
1752 if (image == NULL)
1753 return NULL;
1754
1755 return register_image (image);
1756 }
1757
1758 /**
1759 * mono_image_open:
1760 * \param fname filename that points to the module we want to open
1761 * \param status An error condition is returned in this field
1762 * \returns An open image of type \c MonoImage or NULL on error.
1763 * The caller holds a temporary reference to the returned image which should be cleared
1764 * when no longer needed by calling \c mono_image_close.
1765 * if NULL, then check the value of \p status for details on the error
1766 */
1767 MonoImage *
mono_image_open(const char * fname,MonoImageOpenStatus * status)1768 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1769 {
1770 return mono_image_open_full (fname, status, FALSE);
1771 }
1772
1773 /**
1774 * mono_pe_file_open:
1775 * \param fname filename that points to the module we want to open
1776 * \param status An error condition is returned in this field
1777 * \returns An open image of type \c MonoImage or NULL on error. if
1778 * NULL, then check the value of \p status for details on the error.
1779 * This variant for \c mono_image_open DOES NOT SET UP CLI METADATA.
1780 * It's just a PE file loader, used for \c FileVersionInfo. It also does
1781 * not use the image cache.
1782 */
1783 MonoImage *
mono_pe_file_open(const char * fname,MonoImageOpenStatus * status)1784 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1785 {
1786 g_return_val_if_fail (fname != NULL, NULL);
1787
1788 return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE, FALSE);
1789 }
1790
1791 /**
1792 * mono_image_open_raw
1793 * \param fname filename that points to the module we want to open
1794 * \param status An error condition is returned in this field
1795 * \returns an image without loading neither pe or cli data.
1796 * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.
1797 */
1798 MonoImage *
mono_image_open_raw(const char * fname,MonoImageOpenStatus * status)1799 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1800 {
1801 g_return_val_if_fail (fname != NULL, NULL);
1802
1803 return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE, FALSE);
1804 }
1805
1806 /*
1807 * mono_image_open_metadata_only:
1808 *
1809 * Open an image which contains metadata only without a PE header.
1810 */
1811 MonoImage *
mono_image_open_metadata_only(const char * fname,MonoImageOpenStatus * status)1812 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1813 {
1814 return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE, FALSE);
1815 }
1816
1817 /**
1818 * mono_image_fixup_vtable:
1819 */
1820 void
mono_image_fixup_vtable(MonoImage * image)1821 mono_image_fixup_vtable (MonoImage *image)
1822 {
1823 #ifdef HOST_WIN32
1824 MonoCLIImageInfo *iinfo;
1825 MonoPEDirEntry *de;
1826 MonoVTableFixup *vtfixup;
1827 int count;
1828 gpointer slot;
1829 guint16 slot_type;
1830 int slot_count;
1831
1832 g_assert (image->is_module_handle);
1833
1834 iinfo = image->image_info;
1835 de = &iinfo->cli_cli_header.ch_vtable_fixups;
1836 if (!de->rva || !de->size)
1837 return;
1838 vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1839 if (!vtfixup)
1840 return;
1841
1842 count = de->size / sizeof (MonoVTableFixup);
1843 while (count--) {
1844 if (!vtfixup->rva || !vtfixup->count)
1845 continue;
1846
1847 slot = mono_image_rva_map (image, vtfixup->rva);
1848 g_assert (slot);
1849 slot_type = vtfixup->type;
1850 slot_count = vtfixup->count;
1851 if (slot_type & VTFIXUP_TYPE_32BIT)
1852 while (slot_count--) {
1853 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1854 slot = ((guint32*) slot) + 1;
1855 }
1856 else if (slot_type & VTFIXUP_TYPE_64BIT)
1857 while (slot_count--) {
1858 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1859 slot = ((guint32*) slot) + 1;
1860 }
1861 else
1862 g_assert_not_reached();
1863
1864 vtfixup++;
1865 }
1866 #else
1867 g_assert_not_reached();
1868 #endif
1869 }
1870
1871 static void
free_hash_table(gpointer key,gpointer val,gpointer user_data)1872 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1873 {
1874 g_hash_table_destroy ((GHashTable*)val);
1875 }
1876
1877 /*
1878 static void
1879 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1880 {
1881 mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1882 }
1883 */
1884
1885 static void
free_array_cache_entry(gpointer key,gpointer val,gpointer user_data)1886 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1887 {
1888 g_slist_free ((GSList*)val);
1889 }
1890
1891 /**
1892 * mono_image_addref:
1893 * \param image The image file we wish to add a reference to
1894 * Increases the reference count of an image.
1895 */
1896 void
mono_image_addref(MonoImage * image)1897 mono_image_addref (MonoImage *image)
1898 {
1899 mono_atomic_inc_i32 (&image->ref_count);
1900 }
1901
1902 void
mono_dynamic_stream_reset(MonoDynamicStream * stream)1903 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1904 {
1905 stream->alloc_size = stream->index = stream->offset = 0;
1906 g_free (stream->data);
1907 stream->data = NULL;
1908 if (stream->hash) {
1909 g_hash_table_destroy (stream->hash);
1910 stream->hash = NULL;
1911 }
1912 }
1913
1914 static inline void
free_hash(GHashTable * hash)1915 free_hash (GHashTable *hash)
1916 {
1917 if (hash)
1918 g_hash_table_destroy (hash);
1919 }
1920
1921 void
mono_wrapper_caches_free(MonoWrapperCaches * cache)1922 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1923 {
1924 free_hash (cache->delegate_invoke_cache);
1925 free_hash (cache->delegate_begin_invoke_cache);
1926 free_hash (cache->delegate_end_invoke_cache);
1927 free_hash (cache->runtime_invoke_cache);
1928 free_hash (cache->runtime_invoke_vtype_cache);
1929
1930 free_hash (cache->delegate_abstract_invoke_cache);
1931
1932 free_hash (cache->runtime_invoke_direct_cache);
1933 free_hash (cache->managed_wrapper_cache);
1934
1935 free_hash (cache->native_wrapper_cache);
1936 free_hash (cache->native_wrapper_aot_cache);
1937 free_hash (cache->native_wrapper_check_cache);
1938 free_hash (cache->native_wrapper_aot_check_cache);
1939
1940 free_hash (cache->native_func_wrapper_aot_cache);
1941 free_hash (cache->remoting_invoke_cache);
1942 free_hash (cache->synchronized_cache);
1943 free_hash (cache->unbox_wrapper_cache);
1944 free_hash (cache->cominterop_invoke_cache);
1945 free_hash (cache->cominterop_wrapper_cache);
1946 free_hash (cache->thunk_invoke_cache);
1947 }
1948
1949 static void
mono_image_close_except_pools_all(MonoImage ** images,int image_count)1950 mono_image_close_except_pools_all (MonoImage**images, int image_count)
1951 {
1952 for (int i = 0; i < image_count; ++i) {
1953 if (images [i]) {
1954 if (!mono_image_close_except_pools (images [i]))
1955 images [i] = NULL;
1956 }
1957 }
1958 }
1959
1960 /*
1961 * Returns whether mono_image_close_finish() must be called as well.
1962 * We must unload images in two steps because clearing the domain in
1963 * SGen requires the class metadata to be intact, but we need to free
1964 * the mono_g_hash_tables in case a collection occurs during domain
1965 * unloading and the roots would trip up the GC.
1966 */
1967 gboolean
mono_image_close_except_pools(MonoImage * image)1968 mono_image_close_except_pools (MonoImage *image)
1969 {
1970 MonoImage *image2;
1971 GHashTable *loaded_images, *loaded_images_by_name;
1972 int i;
1973
1974 g_return_val_if_fail (image != NULL, FALSE);
1975
1976 /*
1977 * Atomically decrement the refcount and remove ourselves from the hash tables, so
1978 * register_image () can't grab an image which is being closed.
1979 */
1980 mono_images_lock ();
1981
1982 if (mono_atomic_dec_i32 (&image->ref_count) > 0) {
1983 mono_images_unlock ();
1984 return FALSE;
1985 }
1986
1987 loaded_images = get_loaded_images_hash (image->ref_only);
1988 loaded_images_by_name = get_loaded_images_by_name_hash (image->ref_only);
1989 image2 = (MonoImage *)g_hash_table_lookup (loaded_images, image->name);
1990 if (image == image2) {
1991 /* This is not true if we are called from mono_image_open () */
1992 g_hash_table_remove (loaded_images, image->name);
1993 }
1994 if (image->assembly_name && (g_hash_table_lookup (loaded_images_by_name, image->assembly_name) == image))
1995 g_hash_table_remove (loaded_images_by_name, (char *) image->assembly_name);
1996
1997 mono_images_unlock ();
1998
1999 #ifdef HOST_WIN32
2000 if (image->is_module_handle && image->has_entry_point) {
2001 mono_images_lock ();
2002 if (image->ref_count == 0) {
2003 /* Image will be closed by _CorDllMain. */
2004 FreeLibrary ((HMODULE) image->raw_data);
2005 mono_images_unlock ();
2006 return FALSE;
2007 }
2008 mono_images_unlock ();
2009 }
2010 #endif
2011
2012 MONO_PROFILER_RAISE (image_unloading, (image));
2013
2014 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
2015
2016 mono_image_invoke_unload_hook (image);
2017
2018 mono_metadata_clean_for_image (image);
2019
2020 /*
2021 * The caches inside a MonoImage might refer to metadata which is stored in referenced
2022 * assemblies, so we can't release these references in mono_assembly_close () since the
2023 * MonoImage might outlive its associated MonoAssembly.
2024 */
2025 if (image->references && !image_is_dynamic (image)) {
2026 for (i = 0; i < image->nreferences; i++) {
2027 if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
2028 if (!mono_assembly_close_except_image_pools (image->references [i]))
2029 image->references [i] = NULL;
2030 }
2031 }
2032 } else {
2033 if (image->references) {
2034 g_free (image->references);
2035 image->references = NULL;
2036 }
2037 }
2038
2039 #ifdef HOST_WIN32
2040 mono_images_lock ();
2041 if (image->is_module_handle && !image->has_entry_point)
2042 FreeLibrary ((HMODULE) image->raw_data);
2043 mono_images_unlock ();
2044 #endif
2045
2046 if (image->raw_buffer_used) {
2047 if (image->raw_data != NULL) {
2048 #ifndef HOST_WIN32
2049 if (image->fileio_used)
2050 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
2051 else
2052 #endif
2053 mono_file_unmap (image->raw_data, image->raw_data_handle);
2054 }
2055 }
2056
2057 if (image->raw_data_allocated) {
2058 /* FIXME: do we need this? (image is disposed anyway) */
2059 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
2060 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2061
2062 if ((image->raw_metadata > image->raw_data) &&
2063 (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
2064 image->raw_metadata = NULL;
2065
2066 for (i = 0; i < ii->cli_section_count; i++)
2067 if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
2068 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
2069 ii->cli_sections [i] = NULL;
2070
2071 g_free (image->raw_data);
2072 }
2073
2074 if (debug_assembly_unload) {
2075 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
2076 } else {
2077 g_free (image->name);
2078 g_free (image->guid);
2079 g_free (image->version);
2080 }
2081
2082 if (image->method_cache)
2083 g_hash_table_destroy (image->method_cache);
2084 if (image->methodref_cache)
2085 g_hash_table_destroy (image->methodref_cache);
2086 mono_internal_hash_table_destroy (&image->class_cache);
2087 mono_conc_hashtable_destroy (image->field_cache);
2088 if (image->array_cache) {
2089 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
2090 g_hash_table_destroy (image->array_cache);
2091 }
2092 if (image->szarray_cache)
2093 g_hash_table_destroy (image->szarray_cache);
2094 if (image->ptr_cache)
2095 g_hash_table_destroy (image->ptr_cache);
2096 if (image->name_cache) {
2097 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
2098 g_hash_table_destroy (image->name_cache);
2099 }
2100
2101 free_hash (image->delegate_bound_static_invoke_cache);
2102 free_hash (image->runtime_invoke_vcall_cache);
2103 free_hash (image->ldfld_wrapper_cache);
2104 free_hash (image->ldflda_wrapper_cache);
2105 free_hash (image->stfld_wrapper_cache);
2106 free_hash (image->isinst_cache);
2107 free_hash (image->castclass_cache);
2108 free_hash (image->icall_wrapper_cache);
2109 free_hash (image->proxy_isinst_cache);
2110 free_hash (image->var_cache_slow);
2111 free_hash (image->mvar_cache_slow);
2112 free_hash (image->var_cache_constrained);
2113 free_hash (image->mvar_cache_constrained);
2114 free_hash (image->wrapper_param_names);
2115 free_hash (image->pinvoke_scopes);
2116 free_hash (image->pinvoke_scope_filenames);
2117 free_hash (image->native_func_wrapper_cache);
2118 mono_conc_hashtable_destroy (image->typespec_cache);
2119 free_hash (image->weak_field_indexes);
2120
2121 mono_wrapper_caches_free (&image->wrapper_caches);
2122
2123 for (i = 0; i < image->gshared_types_len; ++i)
2124 free_hash (image->gshared_types [i]);
2125 g_free (image->gshared_types);
2126
2127 /* The ownership of signatures is not well defined */
2128 g_hash_table_destroy (image->memberref_signatures);
2129 g_hash_table_destroy (image->helper_signatures);
2130 g_hash_table_destroy (image->method_signatures);
2131
2132 if (image->rgctx_template_hash)
2133 g_hash_table_destroy (image->rgctx_template_hash);
2134
2135 if (image->property_hash)
2136 mono_property_hash_destroy (image->property_hash);
2137
2138 /*
2139 reflection_info_unregister_classes is only required by dynamic images, which will not be properly
2140 cleared during shutdown as we don't perform regular appdomain unload for the root one.
2141 */
2142 g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
2143 image->reflection_info_unregister_classes = NULL;
2144
2145 if (image->interface_bitset) {
2146 mono_unload_interface_ids (image->interface_bitset);
2147 mono_bitset_free (image->interface_bitset);
2148 }
2149 if (image->image_info){
2150 MonoCLIImageInfo *ii = (MonoCLIImageInfo *)image->image_info;
2151
2152 if (ii->cli_section_tables)
2153 g_free (ii->cli_section_tables);
2154 if (ii->cli_sections)
2155 g_free (ii->cli_sections);
2156 g_free (image->image_info);
2157 }
2158
2159 mono_image_close_except_pools_all (image->files, image->file_count);
2160 mono_image_close_except_pools_all (image->modules, image->module_count);
2161 if (image->modules_loaded)
2162 g_free (image->modules_loaded);
2163
2164 mono_os_mutex_destroy (&image->szarray_cache_lock);
2165 mono_os_mutex_destroy (&image->lock);
2166
2167 /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
2168 if (image_is_dynamic (image)) {
2169 /* Dynamic images are GC_MALLOCed */
2170 g_free ((char*)image->module_name);
2171 mono_dynamic_image_free ((MonoDynamicImage*)image);
2172 }
2173
2174 MONO_PROFILER_RAISE (image_unloaded, (image));
2175
2176 return TRUE;
2177 }
2178
2179 static void
mono_image_close_all(MonoImage ** images,int image_count)2180 mono_image_close_all (MonoImage**images, int image_count)
2181 {
2182 for (int i = 0; i < image_count; ++i) {
2183 if (images [i])
2184 mono_image_close_finish (images [i]);
2185 }
2186 if (images)
2187 g_free (images);
2188 }
2189
2190 void
mono_image_close_finish(MonoImage * image)2191 mono_image_close_finish (MonoImage *image)
2192 {
2193 int i;
2194
2195 if (image->references && !image_is_dynamic (image)) {
2196 for (i = 0; i < image->nreferences; i++) {
2197 if (image->references [i] && image->references [i] != REFERENCE_MISSING)
2198 mono_assembly_close_finish (image->references [i]);
2199 }
2200
2201 g_free (image->references);
2202 image->references = NULL;
2203 }
2204
2205 mono_image_close_all (image->files, image->file_count);
2206 mono_image_close_all (image->modules, image->module_count);
2207
2208 #ifndef DISABLE_PERFCOUNTERS
2209 /* FIXME: use an explicit subtraction method as soon as it's available */
2210 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, -1 * mono_mempool_get_allocated (image->mempool));
2211 #endif
2212
2213 if (!image_is_dynamic (image)) {
2214 if (debug_assembly_unload)
2215 mono_mempool_invalidate (image->mempool);
2216 else {
2217 mono_mempool_destroy (image->mempool);
2218 g_free (image);
2219 }
2220 } else {
2221 if (debug_assembly_unload)
2222 mono_mempool_invalidate (image->mempool);
2223 else {
2224 mono_mempool_destroy (image->mempool);
2225 mono_dynamic_image_free_image ((MonoDynamicImage*)image);
2226 }
2227 }
2228 }
2229
2230 /**
2231 * mono_image_close:
2232 * \param image The image file we wish to close
2233 * Closes an image file, deallocates all memory consumed and
2234 * unmaps all possible sections of the file
2235 */
2236 void
mono_image_close(MonoImage * image)2237 mono_image_close (MonoImage *image)
2238 {
2239 if (mono_image_close_except_pools (image))
2240 mono_image_close_finish (image);
2241 }
2242
2243 /**
2244 * mono_image_strerror:
2245 * \param status an code indicating the result from a recent operation
2246 * \returns a string describing the error
2247 */
2248 const char *
mono_image_strerror(MonoImageOpenStatus status)2249 mono_image_strerror (MonoImageOpenStatus status)
2250 {
2251 switch (status){
2252 case MONO_IMAGE_OK:
2253 return "success";
2254 case MONO_IMAGE_ERROR_ERRNO:
2255 return strerror (errno);
2256 case MONO_IMAGE_IMAGE_INVALID:
2257 return "File does not contain a valid CIL image";
2258 case MONO_IMAGE_MISSING_ASSEMBLYREF:
2259 return "An assembly was referenced, but could not be found";
2260 }
2261 return "Internal error";
2262 }
2263
2264 static gpointer
mono_image_walk_resource_tree(MonoCLIImageInfo * info,guint32 res_id,guint32 lang_id,gunichar2 * name,MonoPEResourceDirEntry * entry,MonoPEResourceDir * root,guint32 level)2265 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
2266 guint32 lang_id, gunichar2 *name,
2267 MonoPEResourceDirEntry *entry,
2268 MonoPEResourceDir *root, guint32 level)
2269 {
2270 gboolean is_string, is_dir;
2271 guint32 name_offset, dir_offset;
2272
2273 /* Level 0 holds a directory entry for each type of resource
2274 * (identified by ID or name).
2275 *
2276 * Level 1 holds a directory entry for each named resource
2277 * item, and each "anonymous" item of a particular type of
2278 * resource.
2279 *
2280 * Level 2 holds a directory entry for each language pointing to
2281 * the actual data.
2282 */
2283 is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
2284 name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
2285
2286 is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
2287 dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
2288
2289 if(level==0) {
2290 if (is_string)
2291 return NULL;
2292 } else if (level==1) {
2293 if (res_id != name_offset)
2294 return NULL;
2295 #if 0
2296 if(name!=NULL &&
2297 is_string==TRUE && name!=lookup (name_offset)) {
2298 return(NULL);
2299 }
2300 #endif
2301 } else if (level==2) {
2302 if (is_string || (lang_id != 0 && name_offset != lang_id))
2303 return NULL;
2304 } else {
2305 g_assert_not_reached ();
2306 }
2307
2308 if (is_dir) {
2309 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
2310 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
2311 guint32 entries, i;
2312
2313 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
2314
2315 for(i=0; i<entries; i++) {
2316 MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
2317 gpointer ret;
2318
2319 ret=mono_image_walk_resource_tree (info, res_id,
2320 lang_id, name,
2321 sub_entry, root,
2322 level+1);
2323 if(ret!=NULL) {
2324 return(ret);
2325 }
2326 }
2327
2328 return(NULL);
2329 } else {
2330 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
2331 MonoPEResourceDataEntry *res;
2332
2333 res = g_new0 (MonoPEResourceDataEntry, 1);
2334
2335 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
2336 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
2337 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
2338 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
2339
2340 return (res);
2341 }
2342 }
2343
2344 /**
2345 * mono_image_lookup_resource:
2346 * \param image the image to look up the resource in
2347 * \param res_id A \c MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
2348 * \param lang_id The language id.
2349 * \param name the resource name to lookup.
2350 * \returns NULL if not found, otherwise a pointer to the in-memory representation
2351 * of the given resource. The caller should free it using \c g_free when no longer
2352 * needed.
2353 */
2354 gpointer
mono_image_lookup_resource(MonoImage * image,guint32 res_id,guint32 lang_id,gunichar2 * name)2355 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
2356 {
2357 MonoCLIImageInfo *info;
2358 MonoDotNetHeader *header;
2359 MonoPEDatadir *datadir;
2360 MonoPEDirEntry *rsrc;
2361 MonoPEResourceDir *resource_dir;
2362 MonoPEResourceDirEntry *res_entries;
2363 guint32 entries, i;
2364
2365 if(image==NULL) {
2366 return(NULL);
2367 }
2368
2369 mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2370
2371 info = (MonoCLIImageInfo *)image->image_info;
2372 if(info==NULL) {
2373 return(NULL);
2374 }
2375
2376 header=&info->cli_header;
2377 if(header==NULL) {
2378 return(NULL);
2379 }
2380
2381 datadir=&header->datadir;
2382 if(datadir==NULL) {
2383 return(NULL);
2384 }
2385
2386 rsrc=&datadir->pe_resource_table;
2387 if(rsrc==NULL) {
2388 return(NULL);
2389 }
2390
2391 resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2392 if(resource_dir==NULL) {
2393 return(NULL);
2394 }
2395
2396 entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2397 res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2398
2399 for(i=0; i<entries; i++) {
2400 MonoPEResourceDirEntry *entry=&res_entries[i];
2401 gpointer ret;
2402
2403 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2404 name, entry, resource_dir,
2405 0);
2406 if(ret!=NULL) {
2407 return(ret);
2408 }
2409 }
2410
2411 return(NULL);
2412 }
2413
2414 /**
2415 * mono_image_get_entry_point:
2416 * \param image the image where the entry point will be looked up.
2417 * Use this routine to determine the metadata token for method that
2418 * has been flagged as the entry point.
2419 * \returns the token for the entry point method in the image
2420 */
2421 guint32
mono_image_get_entry_point(MonoImage * image)2422 mono_image_get_entry_point (MonoImage *image)
2423 {
2424 return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2425 }
2426
2427 /**
2428 * mono_image_get_resource:
2429 * \param image the image where the resource will be looked up.
2430 * \param offset The offset to add to the resource
2431 * \param size a pointer to an int where the size of the resource will be stored
2432 *
2433 * This is a low-level routine that fetches a resource from the
2434 * metadata that starts at a given \p offset. The \p size parameter is
2435 * filled with the data field as encoded in the metadata.
2436 *
2437 * \returns the pointer to the resource whose offset is \p offset.
2438 */
2439 const char*
mono_image_get_resource(MonoImage * image,guint32 offset,guint32 * size)2440 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2441 {
2442 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2443 MonoCLIHeader *ch = &iinfo->cli_cli_header;
2444 const char* data;
2445
2446 if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2447 return NULL;
2448
2449 data = mono_image_rva_map (image, ch->ch_resources.rva);
2450 if (!data)
2451 return NULL;
2452 data += offset;
2453 if (size)
2454 *size = read32 (data);
2455 data += 4;
2456 return data;
2457 }
2458
2459 // Returning NULL with no error set will be interpeted as "not found"
2460 MonoImage*
mono_image_load_file_for_image_checked(MonoImage * image,int fileidx,MonoError * error)2461 mono_image_load_file_for_image_checked (MonoImage *image, int fileidx, MonoError *error)
2462 {
2463 char *base_dir, *name;
2464 MonoImage *res;
2465 MonoTableInfo *t = &image->tables [MONO_TABLE_FILE];
2466 const char *fname;
2467 guint32 fname_id;
2468
2469 error_init (error);
2470
2471 if (fileidx < 1 || fileidx > t->rows)
2472 return NULL;
2473
2474 mono_image_lock (image);
2475 if (image->files && image->files [fileidx - 1]) {
2476 mono_image_unlock (image);
2477 return image->files [fileidx - 1];
2478 }
2479 mono_image_unlock (image);
2480
2481 fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2482 fname = mono_metadata_string_heap (image, fname_id);
2483 base_dir = g_path_get_dirname (image->name);
2484 name = g_build_filename (base_dir, fname, NULL);
2485 res = mono_image_open (name, NULL);
2486 if (!res)
2487 goto done;
2488
2489 mono_image_lock (image);
2490 if (image->files && image->files [fileidx - 1]) {
2491 MonoImage *old = res;
2492 res = image->files [fileidx - 1];
2493 mono_image_unlock (image);
2494 mono_image_close (old);
2495 } else {
2496 int i;
2497 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2498 if (!assign_assembly_parent_for_netmodule (res, image, error)) {
2499 mono_image_unlock (image);
2500 mono_image_close (res);
2501 return NULL;
2502 }
2503
2504 for (i = 0; i < res->module_count; ++i) {
2505 if (res->modules [i] && !res->modules [i]->assembly)
2506 res->modules [i]->assembly = image->assembly;
2507 }
2508
2509 if (!image->files) {
2510 image->files = g_new0 (MonoImage*, t->rows);
2511 image->file_count = t->rows;
2512 }
2513 image->files [fileidx - 1] = res;
2514 mono_image_unlock (image);
2515 /* vtable fixup can't happen with the image lock held */
2516 #ifdef HOST_WIN32
2517 if (res->is_module_handle)
2518 mono_image_fixup_vtable (res);
2519 #endif
2520 }
2521
2522 done:
2523 g_free (name);
2524 g_free (base_dir);
2525 return res;
2526 }
2527
2528 /**
2529 * mono_image_load_file_for_image:
2530 */
2531 MonoImage*
mono_image_load_file_for_image(MonoImage * image,int fileidx)2532 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2533 {
2534 MonoError error;
2535 MonoImage *result = mono_image_load_file_for_image_checked (image, fileidx, &error);
2536 mono_error_assert_ok (&error);
2537 return result;
2538 }
2539
2540 /**
2541 * mono_image_get_strong_name:
2542 * \param image a MonoImage
2543 * \param size a \c guint32 pointer, or NULL.
2544 *
2545 * If the image has a strong name, and \p size is not NULL, the value
2546 * pointed to by size will have the size of the strong name.
2547 *
2548 * \returns NULL if the image does not have a strong name, or a
2549 * pointer to the public key.
2550 */
2551 const char*
mono_image_get_strong_name(MonoImage * image,guint32 * size)2552 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2553 {
2554 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2555 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2556 const char* data;
2557
2558 if (!de->size || !de->rva)
2559 return NULL;
2560 data = mono_image_rva_map (image, de->rva);
2561 if (!data)
2562 return NULL;
2563 if (size)
2564 *size = de->size;
2565 return data;
2566 }
2567
2568 /**
2569 * mono_image_strong_name_position:
2570 * \param image a \c MonoImage
2571 * \param size a \c guint32 pointer, or NULL.
2572 *
2573 * If the image has a strong name, and \p size is not NULL, the value
2574 * pointed to by size will have the size of the strong name.
2575 *
2576 * \returns the position within the image file where the strong name
2577 * is stored.
2578 */
2579 guint32
mono_image_strong_name_position(MonoImage * image,guint32 * size)2580 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2581 {
2582 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2583 MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2584 guint32 pos;
2585
2586 if (size)
2587 *size = de->size;
2588 if (!de->size || !de->rva)
2589 return 0;
2590 pos = mono_cli_rva_image_map (image, de->rva);
2591 return pos == INVALID_ADDRESS ? 0 : pos;
2592 }
2593
2594 /**
2595 * mono_image_get_public_key:
2596 * \param image a \c MonoImage
2597 * \param size a \c guint32 pointer, or NULL.
2598 *
2599 * This is used to obtain the public key in the \p image.
2600 *
2601 * If the image has a public key, and \p size is not NULL, the value
2602 * pointed to by size will have the size of the public key.
2603 *
2604 * \returns NULL if the image does not have a public key, or a pointer
2605 * to the public key.
2606 */
2607 const char*
mono_image_get_public_key(MonoImage * image,guint32 * size)2608 mono_image_get_public_key (MonoImage *image, guint32 *size)
2609 {
2610 const char *pubkey;
2611 guint32 len, tok;
2612
2613 if (image_is_dynamic (image)) {
2614 if (size)
2615 *size = ((MonoDynamicImage*)image)->public_key_len;
2616 return (char*)((MonoDynamicImage*)image)->public_key;
2617 }
2618 if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2619 return NULL;
2620 tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2621 if (!tok)
2622 return NULL;
2623 pubkey = mono_metadata_blob_heap (image, tok);
2624 len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2625 if (size)
2626 *size = len;
2627 return pubkey;
2628 }
2629
2630 /**
2631 * mono_image_get_name:
2632 * \param name a \c MonoImage
2633 * \returns the name of the assembly.
2634 */
2635 const char*
mono_image_get_name(MonoImage * image)2636 mono_image_get_name (MonoImage *image)
2637 {
2638 return image->assembly_name;
2639 }
2640
2641 /**
2642 * mono_image_get_filename:
2643 * \param image a \c MonoImage
2644 * Used to get the filename that hold the actual \c MonoImage
2645 * \returns the filename.
2646 */
2647 const char*
mono_image_get_filename(MonoImage * image)2648 mono_image_get_filename (MonoImage *image)
2649 {
2650 return image->name;
2651 }
2652
2653 /**
2654 * mono_image_get_guid:
2655 */
2656 const char*
mono_image_get_guid(MonoImage * image)2657 mono_image_get_guid (MonoImage *image)
2658 {
2659 return image->guid;
2660 }
2661
2662 /**
2663 * mono_image_get_table_info:
2664 */
2665 const MonoTableInfo*
mono_image_get_table_info(MonoImage * image,int table_id)2666 mono_image_get_table_info (MonoImage *image, int table_id)
2667 {
2668 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2669 return NULL;
2670 return &image->tables [table_id];
2671 }
2672
2673 /**
2674 * mono_image_get_table_rows:
2675 */
2676 int
mono_image_get_table_rows(MonoImage * image,int table_id)2677 mono_image_get_table_rows (MonoImage *image, int table_id)
2678 {
2679 if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2680 return 0;
2681 return image->tables [table_id].rows;
2682 }
2683
2684 /**
2685 * mono_table_info_get_rows:
2686 */
2687 int
mono_table_info_get_rows(const MonoTableInfo * table)2688 mono_table_info_get_rows (const MonoTableInfo *table)
2689 {
2690 return table->rows;
2691 }
2692
2693 /**
2694 * mono_image_get_assembly:
2695 * \param image the \c MonoImage .
2696 * Use this routine to get the assembly that owns this image.
2697 * \returns the assembly that holds this image.
2698 */
2699 MonoAssembly*
mono_image_get_assembly(MonoImage * image)2700 mono_image_get_assembly (MonoImage *image)
2701 {
2702 return image->assembly;
2703 }
2704
2705 /**
2706 * mono_image_is_dynamic:
2707 * \param image the \c MonoImage
2708 *
2709 * Determines if the given image was created dynamically through the
2710 * \c System.Reflection.Emit API
2711 * \returns TRUE if the image was created dynamically, FALSE if not.
2712 */
2713 gboolean
mono_image_is_dynamic(MonoImage * image)2714 mono_image_is_dynamic (MonoImage *image)
2715 {
2716 return image_is_dynamic (image);
2717 }
2718
2719 /**
2720 * mono_image_has_authenticode_entry:
2721 * \param image the \c MonoImage
2722 * Use this routine to determine if the image has a Authenticode
2723 * Certificate Table.
2724 * \returns TRUE if the image contains an authenticode entry in the PE
2725 * directory.
2726 */
2727 gboolean
mono_image_has_authenticode_entry(MonoImage * image)2728 mono_image_has_authenticode_entry (MonoImage *image)
2729 {
2730 MonoCLIImageInfo *iinfo = (MonoCLIImageInfo *)image->image_info;
2731 MonoDotNetHeader *header = &iinfo->cli_header;
2732 if (!header)
2733 return FALSE;
2734 MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2735 // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2736 return ((de->rva != 0) && (de->size > 8));
2737 }
2738
2739 gpointer
mono_image_alloc(MonoImage * image,guint size)2740 mono_image_alloc (MonoImage *image, guint size)
2741 {
2742 gpointer res;
2743
2744 #ifndef DISABLE_PERFCOUNTERS
2745 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
2746 #endif
2747 mono_image_lock (image);
2748 res = mono_mempool_alloc (image->mempool, size);
2749 mono_image_unlock (image);
2750
2751 return res;
2752 }
2753
2754 gpointer
mono_image_alloc0(MonoImage * image,guint size)2755 mono_image_alloc0 (MonoImage *image, guint size)
2756 {
2757 gpointer res;
2758
2759 #ifndef DISABLE_PERFCOUNTERS
2760 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, size);
2761 #endif
2762 mono_image_lock (image);
2763 res = mono_mempool_alloc0 (image->mempool, size);
2764 mono_image_unlock (image);
2765
2766 return res;
2767 }
2768
2769 char*
mono_image_strdup(MonoImage * image,const char * s)2770 mono_image_strdup (MonoImage *image, const char *s)
2771 {
2772 char *res;
2773
2774 #ifndef DISABLE_PERFCOUNTERS
2775 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (s));
2776 #endif
2777 mono_image_lock (image);
2778 res = mono_mempool_strdup (image->mempool, s);
2779 mono_image_unlock (image);
2780
2781 return res;
2782 }
2783
2784 char*
mono_image_strdup_vprintf(MonoImage * image,const char * format,va_list args)2785 mono_image_strdup_vprintf (MonoImage *image, const char *format, va_list args)
2786 {
2787 char *buf;
2788 mono_image_lock (image);
2789 buf = mono_mempool_strdup_vprintf (image->mempool, format, args);
2790 mono_image_unlock (image);
2791 #ifndef DISABLE_PERFCOUNTERS
2792 mono_atomic_fetch_add_i32 (&mono_perfcounters->loader_bytes, (gint32)strlen (buf));
2793 #endif
2794 return buf;
2795 }
2796
2797 char*
mono_image_strdup_printf(MonoImage * image,const char * format,...)2798 mono_image_strdup_printf (MonoImage *image, const char *format, ...)
2799 {
2800 char *buf;
2801 va_list args;
2802
2803 va_start (args, format);
2804 buf = mono_image_strdup_vprintf (image, format, args);
2805 va_end (args);
2806 return buf;
2807 }
2808
2809 GList*
g_list_prepend_image(MonoImage * image,GList * list,gpointer data)2810 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2811 {
2812 GList *new_list;
2813
2814 new_list = (GList *)mono_image_alloc (image, sizeof (GList));
2815 new_list->data = data;
2816 new_list->prev = list ? list->prev : NULL;
2817 new_list->next = list;
2818
2819 if (new_list->prev)
2820 new_list->prev->next = new_list;
2821 if (list)
2822 list->prev = new_list;
2823
2824 return new_list;
2825 }
2826
2827 GSList*
g_slist_append_image(MonoImage * image,GSList * list,gpointer data)2828 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2829 {
2830 GSList *new_list;
2831
2832 new_list = (GSList *)mono_image_alloc (image, sizeof (GSList));
2833 new_list->data = data;
2834 new_list->next = NULL;
2835
2836 return g_slist_concat (list, new_list);
2837 }
2838
2839 void
mono_image_lock(MonoImage * image)2840 mono_image_lock (MonoImage *image)
2841 {
2842 mono_locks_os_acquire (&image->lock, ImageDataLock);
2843 }
2844
2845 void
mono_image_unlock(MonoImage * image)2846 mono_image_unlock (MonoImage *image)
2847 {
2848 mono_locks_os_release (&image->lock, ImageDataLock);
2849 }
2850
2851
2852 /**
2853 * mono_image_property_lookup:
2854 * Lookup a property on \p image . Used to store very rare fields of \c MonoClass and \c MonoMethod .
2855 *
2856 * LOCKING: Takes the image lock
2857 */
2858 gpointer
mono_image_property_lookup(MonoImage * image,gpointer subject,guint32 property)2859 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2860 {
2861 gpointer res;
2862
2863 mono_image_lock (image);
2864 res = mono_property_hash_lookup (image->property_hash, subject, property);
2865 mono_image_unlock (image);
2866
2867 return res;
2868 }
2869
2870 /**
2871 * mono_image_property_insert:
2872 * Insert a new property \p property with value \p value on \p subject in \p
2873 * image. Used to store very rare fields of \c MonoClass and \c MonoMethod.
2874 *
2875 * LOCKING: Takes the image lock
2876 */
2877 void
mono_image_property_insert(MonoImage * image,gpointer subject,guint32 property,gpointer value)2878 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2879 {
2880 CHECKED_METADATA_STORE_LOCAL (image->mempool, value);
2881 mono_image_lock (image);
2882 mono_property_hash_insert (image->property_hash, subject, property, value);
2883 mono_image_unlock (image);
2884 }
2885
2886 /**
2887 * mono_image_property_remove:
2888 * Remove all properties associated with \p subject in \p image. Used to store very rare fields of \c MonoClass and \c MonoMethod .
2889 *
2890 * LOCKING: Takes the image lock
2891 */
2892 void
mono_image_property_remove(MonoImage * image,gpointer subject)2893 mono_image_property_remove (MonoImage *image, gpointer subject)
2894 {
2895 mono_image_lock (image);
2896 mono_property_hash_remove_object (image->property_hash, subject);
2897 mono_image_unlock (image);
2898 }
2899
2900 void
mono_image_append_class_to_reflection_info_set(MonoClass * klass)2901 mono_image_append_class_to_reflection_info_set (MonoClass *klass)
2902 {
2903 MonoImage *image = klass->image;
2904 g_assert (image_is_dynamic (image));
2905 mono_image_lock (image);
2906 image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, klass);
2907 mono_image_unlock (image);
2908 }
2909
2910 // 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.
2911
2912 /**
2913 * mono_find_image_owner:
2914 *
2915 * Find the image, if any, which a given pointer is located in the memory of.
2916 */
2917 MonoImage *
mono_find_image_owner(void * ptr)2918 mono_find_image_owner (void *ptr)
2919 {
2920 mono_images_lock ();
2921
2922 MonoImage *owner = NULL;
2923
2924 // Iterate over both by-path image hashes
2925 const int hash_candidates[] = {IMAGES_HASH_PATH, IMAGES_HASH_PATH_REFONLY};
2926 int hash_idx;
2927 for (hash_idx = 0; !owner && hash_idx < G_N_ELEMENTS (hash_candidates); hash_idx++)
2928 {
2929 GHashTable *target = loaded_images_hashes [hash_candidates [hash_idx]];
2930 GHashTableIter iter;
2931 MonoImage *image;
2932
2933 // Iterate over images within a hash
2934 g_hash_table_iter_init (&iter, target);
2935 while (!owner && g_hash_table_iter_next(&iter, NULL, (gpointer *)&image))
2936 {
2937 mono_image_lock (image);
2938 if (mono_mempool_contains_addr (image->mempool, ptr))
2939 owner = image;
2940 mono_image_unlock (image);
2941 }
2942 }
2943
2944 mono_images_unlock ();
2945
2946 return owner;
2947 }
2948