Merge pull request #2155 from akoeplinger/bug-34334-pr
[mono.git] / mono / metadata / image.c
1 /*
2  * image.c: Routines for manipulating an image stored in an
3  * extended PE/COFF file.
4  * 
5  * Authors:
6  *   Miguel de Icaza (miguel@ximian.com)
7  *   Paolo Molaro (lupus@ximian.com)
8  *
9  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
10  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
11  *
12  */
13 #include <config.h>
14 #include <stdio.h>
15 #include <glib.h>
16 #include <errno.h>
17 #include <time.h>
18 #include <string.h>
19 #include "image.h"
20 #include "cil-coff.h"
21 #include "mono-endian.h"
22 #include "tabledefs.h"
23 #include "tokentype.h"
24 #include "metadata-internals.h"
25 #include "profiler-private.h"
26 #include "loader.h"
27 #include "marshal.h"
28 #include "coree.h"
29 #include <mono/io-layer/io-layer.h>
30 #include <mono/utils/mono-logger-internal.h>
31 #include <mono/utils/mono-path.h>
32 #include <mono/utils/mono-mmap.h>
33 #include <mono/utils/mono-io-portability.h>
34 #include <mono/utils/atomic.h>
35 #include <mono/metadata/class-internals.h>
36 #include <mono/metadata/assembly.h>
37 #include <mono/metadata/object-internals.h>
38 #include <mono/metadata/security-core-clr.h>
39 #include <mono/metadata/verify-internals.h>
40 #include <mono/metadata/verify.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46
47 #define INVALID_ADDRESS 0xffffffff
48
49 /*
50  * Keeps track of the various assemblies loaded
51  */
52 static GHashTable *loaded_images_hash;
53 static GHashTable *loaded_images_refonly_hash;
54
55 static gboolean debug_assembly_unload = FALSE;
56
57 #define mono_images_lock() if (mutex_inited) mono_mutex_lock (&images_mutex)
58 #define mono_images_unlock() if (mutex_inited) mono_mutex_unlock (&images_mutex)
59 static gboolean mutex_inited;
60 static mono_mutex_t images_mutex;
61
62 static void install_pe_loader (void);
63
64 typedef struct ImageUnloadHook ImageUnloadHook;
65 struct ImageUnloadHook {
66         MonoImageUnloadFunc func;
67         gpointer user_data;
68 };
69
70 static GSList *image_unload_hooks;
71
72 void
73 mono_install_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
74 {
75         ImageUnloadHook *hook;
76         
77         g_return_if_fail (func != NULL);
78
79         hook = g_new0 (ImageUnloadHook, 1);
80         hook->func = func;
81         hook->user_data = user_data;
82         image_unload_hooks = g_slist_prepend (image_unload_hooks, hook);
83 }
84
85 void
86 mono_remove_image_unload_hook (MonoImageUnloadFunc func, gpointer user_data)
87 {
88         GSList *l;
89         ImageUnloadHook *hook;
90
91         for (l = image_unload_hooks; l; l = l->next) {
92                 hook = l->data;
93
94                 if (hook->func == func && hook->user_data == user_data) {
95                         g_free (hook);
96                         image_unload_hooks = g_slist_delete_link (image_unload_hooks, l);
97                         break;
98                 }
99         }
100 }
101
102 static void
103 mono_image_invoke_unload_hook (MonoImage *image)
104 {
105         GSList *l;
106         ImageUnloadHook *hook;
107
108         for (l = image_unload_hooks; l; l = l->next) {
109                 hook = l->data;
110
111                 hook->func (image, hook->user_data);
112         }
113 }
114
115 static GSList *image_loaders;
116
117 void
118 mono_install_image_loader (const MonoImageLoader *loader)
119 {
120         image_loaders = g_slist_prepend (image_loaders, (MonoImageLoader*)loader);
121 }
122
123 /* returns offset relative to image->raw_data */
124 guint32
125 mono_cli_rva_image_map (MonoImage *image, guint32 addr)
126 {
127         MonoCLIImageInfo *iinfo = image->image_info;
128         const int top = iinfo->cli_section_count;
129         MonoSectionTable *tables = iinfo->cli_section_tables;
130         int i;
131
132         if (image->metadata_only)
133                 return addr;
134
135         for (i = 0; i < top; i++){
136                 if ((addr >= tables->st_virtual_address) &&
137                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
138 #ifdef HOST_WIN32
139                         if (image->is_module_handle)
140                                 return addr;
141 #endif
142                         return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
143                 }
144                 tables++;
145         }
146         return INVALID_ADDRESS;
147 }
148
149 /**
150  * mono_images_rva_map:
151  * @image: a MonoImage
152  * @addr: relative virtual address (RVA)
153  *
154  * This is a low-level routine used by the runtime to map relative
155  * virtual address (RVA) into their location in memory. 
156  *
157  * Returns: the address in memory for the given RVA, or NULL if the
158  * RVA is not valid for this image. 
159  */
160 char *
161 mono_image_rva_map (MonoImage *image, guint32 addr)
162 {
163         MonoCLIImageInfo *iinfo = image->image_info;
164         const int top = iinfo->cli_section_count;
165         MonoSectionTable *tables = iinfo->cli_section_tables;
166         int i;
167
168 #ifdef HOST_WIN32
169         if (image->is_module_handle) {
170                 if (addr && addr < image->raw_data_len)
171                         return image->raw_data + addr;
172                 else
173                         return NULL;
174         }
175 #endif
176
177         for (i = 0; i < top; i++){
178                 if ((addr >= tables->st_virtual_address) &&
179                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
180                         if (!iinfo->cli_sections [i]) {
181                                 if (!mono_image_ensure_section_idx (image, i))
182                                         return NULL;
183                         }
184                         return (char*)iinfo->cli_sections [i] +
185                                 (addr - tables->st_virtual_address);
186                 }
187                 tables++;
188         }
189         return NULL;
190 }
191
192 /**
193  * mono_images_init:
194  *
195  *  Initialize the global variables used by this module.
196  */
197 void
198 mono_images_init (void)
199 {
200         mono_mutex_init_recursive (&images_mutex);
201
202         loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal);
203         loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal);
204
205         debug_assembly_unload = g_getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
206
207         install_pe_loader ();
208
209         mutex_inited = TRUE;
210 }
211
212 /**
213  * mono_images_cleanup:
214  *
215  *  Free all resources used by this module.
216  */
217 void
218 mono_images_cleanup (void)
219 {
220         GHashTableIter iter;
221         MonoImage *image;
222
223         mono_mutex_destroy (&images_mutex);
224
225         g_hash_table_iter_init (&iter, loaded_images_hash);
226         while (g_hash_table_iter_next (&iter, NULL, (void**)&image))
227                 mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Assembly image '%s' still loaded at shutdown.", image->name);
228
229         g_hash_table_destroy (loaded_images_hash);
230         g_hash_table_destroy (loaded_images_refonly_hash);
231
232         mutex_inited = FALSE;
233 }
234
235 /**
236  * mono_image_ensure_section_idx:
237  * @image: The image we are operating on
238  * @section: section number that we will load/map into memory
239  *
240  * This routine makes sure that we have an in-memory copy of
241  * an image section (.text, .rsrc, .data).
242  *
243  * Returns: TRUE on success
244  */
245 int
246 mono_image_ensure_section_idx (MonoImage *image, int section)
247 {
248         MonoCLIImageInfo *iinfo = image->image_info;
249         MonoSectionTable *sect;
250         
251         g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
252
253         if (iinfo->cli_sections [section] != NULL)
254                 return TRUE;
255
256         sect = &iinfo->cli_section_tables [section];
257         
258         if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
259                 return FALSE;
260 #ifdef HOST_WIN32
261         if (image->is_module_handle)
262                 iinfo->cli_sections [section] = image->raw_data + sect->st_virtual_address;
263         else
264 #endif
265         /* FIXME: we ignore the writable flag since we don't patch the binary */
266         iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
267         return TRUE;
268 }
269
270 /**
271  * mono_image_ensure_section:
272  * @image: The image we are operating on
273  * @section: section name that we will load/map into memory
274  *
275  * This routine makes sure that we have an in-memory copy of
276  * an image section (.text, .rsrc, .data).
277  *
278  * Returns: TRUE on success
279  */
280 int
281 mono_image_ensure_section (MonoImage *image, const char *section)
282 {
283         MonoCLIImageInfo *ii = image->image_info;
284         int i;
285         
286         for (i = 0; i < ii->cli_section_count; i++){
287                 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
288                         continue;
289                 
290                 return mono_image_ensure_section_idx (image, i);
291         }
292         return FALSE;
293 }
294
295 static int
296 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
297 {
298         const int top = iinfo->cli_header.coff.coff_sections;
299         int i;
300
301         iinfo->cli_section_count = top;
302         iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
303         iinfo->cli_sections = g_new0 (void *, top);
304         
305         for (i = 0; i < top; i++){
306                 MonoSectionTable *t = &iinfo->cli_section_tables [i];
307
308                 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
309                         return FALSE;
310                 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
311                 offset += sizeof (MonoSectionTable);
312
313 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
314                 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
315                 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
316                 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
317                 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
318                 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
319                 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
320                 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
321                 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
322                 t->st_flags = GUINT32_FROM_LE (t->st_flags);
323 #endif
324                 /* consistency checks here */
325         }
326
327         return TRUE;
328 }
329
330 static gboolean
331 load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
332 {
333         guint32 offset;
334         
335         offset = mono_cli_rva_image_map (image, iinfo->cli_header.datadir.pe_cli_header.rva);
336         if (offset == INVALID_ADDRESS)
337                 return FALSE;
338
339         if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
340                 return FALSE;
341         memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
342
343 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
344 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
345 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
346 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
347         SWAP32 (iinfo->cli_cli_header.ch_size);
348         SWAP32 (iinfo->cli_cli_header.ch_flags);
349         SWAP32 (iinfo->cli_cli_header.ch_entry_point);
350         SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
351         SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
352         SWAPPDE (iinfo->cli_cli_header.ch_metadata);
353         SWAPPDE (iinfo->cli_cli_header.ch_resources);
354         SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
355         SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
356         SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
357         SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
358         SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
359         SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
360         SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
361         SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
362         SWAPPDE (iinfo->cli_cli_header.ch_module_image);
363         SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
364         SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
365         SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
366         SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
367 #undef SWAP32
368 #undef SWAP16
369 #undef SWAPPDE
370 #endif
371         /* Catch new uses of the fields that are supposed to be zero */
372
373         if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
374             (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
375             (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
376             (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
377             (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
378             (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
379             (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
380             (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
381             (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
382
383                 /*
384                  * No need to scare people who are testing this, I am just
385                  * labelling this as a LAMESPEC
386                  */
387                 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
388
389         }
390             
391         return TRUE;
392 }
393
394 static gboolean
395 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
396 {
397         guint32 offset, size;
398         guint16 streams;
399         int i;
400         guint32 pad;
401         char *ptr;
402         
403         offset = mono_cli_rva_image_map (image, iinfo->cli_cli_header.ch_metadata.rva);
404         if (offset == INVALID_ADDRESS)
405                 return FALSE;
406
407         size = iinfo->cli_cli_header.ch_metadata.size;
408
409         if (offset + size > image->raw_data_len)
410                 return FALSE;
411         image->raw_metadata = image->raw_data + offset;
412
413         /* 24.2.1: Metadata root starts here */
414         ptr = image->raw_metadata;
415
416         if (strncmp (ptr, "BSJB", 4) == 0){
417                 guint32 version_string_len;
418
419                 ptr += 4;
420                 image->md_version_major = read16 (ptr);
421                 ptr += 2;
422                 image->md_version_minor = read16 (ptr);
423                 ptr += 6;
424
425                 version_string_len = read32 (ptr);
426                 ptr += 4;
427                 image->version = g_strndup (ptr, version_string_len);
428                 ptr += version_string_len;
429                 pad = ptr - image->raw_metadata;
430                 if (pad % 4)
431                         ptr += 4 - (pad % 4);
432         } else
433                 return FALSE;
434
435         /* skip over flags */
436         ptr += 2;
437         
438         streams = read16 (ptr);
439         ptr += 2;
440
441         for (i = 0; i < streams; i++){
442                 if (strncmp (ptr + 8, "#~", 3) == 0){
443                         image->heap_tables.data = image->raw_metadata + read32 (ptr);
444                         image->heap_tables.size = read32 (ptr + 4);
445                         ptr += 8 + 3;
446                 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
447                         image->heap_strings.data = image->raw_metadata + read32 (ptr);
448                         image->heap_strings.size = read32 (ptr + 4);
449                         ptr += 8 + 9;
450                 } else if (strncmp (ptr + 8, "#US", 4) == 0){
451                         image->heap_us.data = image->raw_metadata + read32 (ptr);
452                         image->heap_us.size = read32 (ptr + 4);
453                         ptr += 8 + 4;
454                 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
455                         image->heap_blob.data = image->raw_metadata + read32 (ptr);
456                         image->heap_blob.size = read32 (ptr + 4);
457                         ptr += 8 + 6;
458                 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
459                         image->heap_guid.data = image->raw_metadata + read32 (ptr);
460                         image->heap_guid.size = read32 (ptr + 4);
461                         ptr += 8 + 6;
462                 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
463                         image->heap_tables.data = image->raw_metadata + read32 (ptr);
464                         image->heap_tables.size = read32 (ptr + 4);
465                         ptr += 8 + 3;
466                         image->uncompressed_metadata = TRUE;
467                         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).\n", image->name);
468                 } else if (strncmp (ptr + 8, "#Pdb", 5) == 0) {
469                         image->heap_pdb.data = image->raw_metadata + read32 (ptr);
470                         image->heap_pdb.size = read32 (ptr + 4);
471                         ptr += 8 + 5;
472                 } else {
473                         g_message ("Unknown heap type: %s\n", ptr + 8);
474                         ptr += 8 + strlen (ptr + 8) + 1;
475                 }
476                 pad = ptr - image->raw_metadata;
477                 if (pad % 4)
478                         ptr += 4 - (pad % 4);
479         }
480
481         i = ((MonoImageLoader*)image->loader)->load_tables (image);
482         g_assert (image->heap_guid.data);
483         g_assert (image->heap_guid.size >= 16);
484
485         image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
486
487         return i;
488 }
489
490 /*
491  * Load representation of logical metadata tables, from the "#~" stream
492  */
493 static gboolean
494 load_tables (MonoImage *image)
495 {
496         const char *heap_tables = image->heap_tables.data;
497         const guint32 *rows;
498         guint64 valid_mask;
499         int valid = 0, table;
500         int heap_sizes;
501         
502         heap_sizes = heap_tables [6];
503         image->idx_string_wide = ((heap_sizes & 0x01) == 1);
504         image->idx_guid_wide   = ((heap_sizes & 0x02) == 2);
505         image->idx_blob_wide   = ((heap_sizes & 0x04) == 4);
506         
507         valid_mask = read64 (heap_tables + 8);
508         rows = (const guint32 *) (heap_tables + 24);
509         
510         for (table = 0; table < 64; table++){
511                 if ((valid_mask & ((guint64) 1 << table)) == 0){
512                         if (table > MONO_TABLE_LAST)
513                                 continue;
514                         image->tables [table].rows = 0;
515                         continue;
516                 }
517                 if (table > MONO_TABLE_LAST) {
518                         g_warning("bits in valid must be zero above 0x37 (II - 23.1.6)");
519                 } else {
520                         image->tables [table].rows = read32 (rows);
521                 }
522                 rows++;
523                 valid++;
524         }
525
526         image->tables_base = (heap_tables + 24) + (4 * valid);
527
528         /* They must be the same */
529         g_assert ((const void *) image->tables_base == (const void *) rows);
530
531         mono_metadata_compute_table_bases (image);
532         return TRUE;
533 }
534
535 static gboolean
536 load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
537 {
538         if (!load_metadata_ptrs (image, iinfo))
539                 return FALSE;
540
541         return load_tables (image);
542 }
543
544 void
545 mono_image_check_for_module_cctor (MonoImage *image)
546 {
547         MonoTableInfo *t, *mt;
548         t = &image->tables [MONO_TABLE_TYPEDEF];
549         mt = &image->tables [MONO_TABLE_METHOD];
550         if (image_is_dynamic (image)) {
551                 /* FIXME: */
552                 image->checked_module_cctor = TRUE;
553                 return;
554         }
555         if (t->rows >= 1) {
556                 guint32 nameidx = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_NAME);
557                 const char *name = mono_metadata_string_heap (image, nameidx);
558                 if (strcmp (name, "<Module>") == 0) {
559                         guint32 first_method = mono_metadata_decode_row_col (t, 0, MONO_TYPEDEF_METHOD_LIST) - 1;
560                         guint32 last_method;
561                         if (t->rows > 1)
562                                 last_method = mono_metadata_decode_row_col (t, 1, MONO_TYPEDEF_METHOD_LIST) - 1;
563                         else 
564                                 last_method = mt->rows;
565                         for (; first_method < last_method; first_method++) {
566                                 nameidx = mono_metadata_decode_row_col (mt, first_method, MONO_METHOD_NAME);
567                                 name = mono_metadata_string_heap (image, nameidx);
568                                 if (strcmp (name, ".cctor") == 0) {
569                                         image->has_module_cctor = TRUE;
570                                         image->checked_module_cctor = TRUE;
571                                         return;
572                                 }
573                         }
574                 }
575         }
576         image->has_module_cctor = FALSE;
577         image->checked_module_cctor = TRUE;
578 }
579
580 static void
581 load_modules (MonoImage *image)
582 {
583         MonoTableInfo *t;
584
585         if (image->modules)
586                 return;
587
588         t = &image->tables [MONO_TABLE_MODULEREF];
589         image->modules = g_new0 (MonoImage *, t->rows);
590         image->modules_loaded = g_new0 (gboolean, t->rows);
591         image->module_count = t->rows;
592 }
593
594 /**
595  * mono_image_load_module:
596  *
597  *   Load the module with the one-based index IDX from IMAGE and return it. Return NULL if
598  * it cannot be loaded.
599  */
600 MonoImage*
601 mono_image_load_module (MonoImage *image, int idx)
602 {
603         MonoTableInfo *t;
604         MonoTableInfo *file_table;
605         int i;
606         char *base_dir;
607         gboolean refonly = image->ref_only;
608         GList *list_iter, *valid_modules = NULL;
609         MonoImageOpenStatus status;
610
611         if ((image->module_count == 0) || (idx > image->module_count || idx <= 0))
612                 return NULL;
613         if (image->modules_loaded [idx - 1])
614                 return image->modules [idx - 1];
615
616         file_table = &image->tables [MONO_TABLE_FILE];
617         for (i = 0; i < file_table->rows; i++) {
618                 guint32 cols [MONO_FILE_SIZE];
619                 mono_metadata_decode_row (file_table, i, cols, MONO_FILE_SIZE);
620                 if (cols [MONO_FILE_FLAGS] == FILE_CONTAINS_NO_METADATA)
621                         continue;
622                 valid_modules = g_list_prepend (valid_modules, (char*)mono_metadata_string_heap (image, cols [MONO_FILE_NAME]));
623         }
624
625         t = &image->tables [MONO_TABLE_MODULEREF];
626         base_dir = g_path_get_dirname (image->name);
627
628         {
629                 char *module_ref;
630                 const char *name;
631                 guint32 cols [MONO_MODULEREF_SIZE];
632                 /* if there is no file table, we try to load the module... */
633                 int valid = file_table->rows == 0;
634
635                 mono_metadata_decode_row (t, idx - 1, cols, MONO_MODULEREF_SIZE);
636                 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
637                 for (list_iter = valid_modules; list_iter; list_iter = list_iter->next) {
638                         /* be safe with string dups, but we could just compare string indexes  */
639                         if (strcmp (list_iter->data, name) == 0) {
640                                 valid = TRUE;
641                                 break;
642                         }
643                 }
644                 if (valid) {
645                         module_ref = g_build_filename (base_dir, name, NULL);
646                         image->modules [idx - 1] = mono_image_open_full (module_ref, &status, refonly);
647                         if (image->modules [idx - 1]) {
648                                 mono_image_addref (image->modules [idx - 1]);
649                                 image->modules [idx - 1]->assembly = image->assembly;
650 #ifdef HOST_WIN32
651                                 if (image->modules [idx - 1]->is_module_handle)
652                                         mono_image_fixup_vtable (image->modules [idx - 1]);
653 #endif
654                                 /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
655                         }
656                         g_free (module_ref);
657                 }
658         }
659
660         image->modules_loaded [idx - 1] = TRUE;
661
662         g_free (base_dir);
663         g_list_free (valid_modules);
664
665         return image->modules [idx - 1];
666 }
667
668 static gpointer
669 class_key_extract (gpointer value)
670 {
671         MonoClass *class = value;
672
673         return GUINT_TO_POINTER (class->type_token);
674 }
675
676 static gpointer*
677 class_next_value (gpointer value)
678 {
679         MonoClass *class = value;
680
681         return (gpointer*)&class->next_class_cache;
682 }
683
684 void
685 mono_image_init (MonoImage *image)
686 {
687         mono_mutex_init_recursive (&image->lock);
688         mono_mutex_init_recursive (&image->szarray_cache_lock);
689
690         image->mempool = mono_mempool_new_size (512);
691         mono_internal_hash_table_init (&image->class_cache,
692                                        g_direct_hash,
693                                        class_key_extract,
694                                        class_next_value);
695         image->field_cache = mono_conc_hashtable_new (NULL, NULL);
696
697         image->typespec_cache = g_hash_table_new (NULL, NULL);
698         image->memberref_signatures = g_hash_table_new (NULL, NULL);
699         image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
700         image->method_signatures = g_hash_table_new (NULL, NULL);
701
702         image->property_hash = mono_property_hash_new ();
703 }
704
705 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
706 #define SWAP64(x) (x) = GUINT64_FROM_LE ((x))
707 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
708 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
709 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
710 #else
711 #define SWAP64(x)
712 #define SWAP32(x)
713 #define SWAP16(x)
714 #define SWAPPDE(x)
715 #endif
716
717 /*
718  * Returns < 0 to indicate an error.
719  */
720 static int
721 do_load_header (MonoImage *image, MonoDotNetHeader *header, int offset)
722 {
723         MonoDotNetHeader64 header64;
724
725 #ifdef HOST_WIN32
726         if (!image->is_module_handle)
727 #endif
728         if (offset + sizeof (MonoDotNetHeader32) > image->raw_data_len)
729                 return -1;
730
731         memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
732
733         if (header->pesig [0] != 'P' || header->pesig [1] != 'E')
734                 return -1;
735
736         /* endian swap the fields common between PE and PE+ */
737         SWAP32 (header->coff.coff_time);
738         SWAP32 (header->coff.coff_symptr);
739         SWAP32 (header->coff.coff_symcount);
740         SWAP16 (header->coff.coff_machine);
741         SWAP16 (header->coff.coff_sections);
742         SWAP16 (header->coff.coff_opt_header_size);
743         SWAP16 (header->coff.coff_attributes);
744         /* MonoPEHeader */
745         SWAP32 (header->pe.pe_code_size);
746         SWAP32 (header->pe.pe_uninit_data_size);
747         SWAP32 (header->pe.pe_rva_entry_point);
748         SWAP32 (header->pe.pe_rva_code_base);
749         SWAP32 (header->pe.pe_rva_data_base);
750         SWAP16 (header->pe.pe_magic);
751
752         /* now we are ready for the basic tests */
753
754         if (header->pe.pe_magic == 0x10B) {
755                 offset += sizeof (MonoDotNetHeader);
756                 SWAP32 (header->pe.pe_data_size);
757                 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
758                         return -1;
759
760                 SWAP32  (header->nt.pe_image_base);     /* must be 0x400000 */
761                 SWAP32  (header->nt.pe_stack_reserve);
762                 SWAP32  (header->nt.pe_stack_commit);
763                 SWAP32  (header->nt.pe_heap_reserve);
764                 SWAP32  (header->nt.pe_heap_commit);
765         } else if (header->pe.pe_magic == 0x20B) {
766                 /* PE32+ file format */
767                 if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader64) - sizeof (MonoCOFFHeader) - 4))
768                         return -1;
769                 memcpy (&header64, image->raw_data + offset, sizeof (MonoDotNetHeader64));
770                 offset += sizeof (MonoDotNetHeader64);
771                 /* copy the fields already swapped. the last field, pe_data_size, is missing */
772                 memcpy (&header64, header, sizeof (MonoDotNetHeader) - 4);
773                 /* FIXME: we lose bits here, but we don't use this stuff internally, so we don't care much.
774                  * will be fixed when we change MonoDotNetHeader to not match the 32 bit variant
775                  */
776                 SWAP64  (header64.nt.pe_image_base);
777                 header->nt.pe_image_base = header64.nt.pe_image_base;
778                 SWAP64  (header64.nt.pe_stack_reserve);
779                 header->nt.pe_stack_reserve = header64.nt.pe_stack_reserve;
780                 SWAP64  (header64.nt.pe_stack_commit);
781                 header->nt.pe_stack_commit = header64.nt.pe_stack_commit;
782                 SWAP64  (header64.nt.pe_heap_reserve);
783                 header->nt.pe_heap_reserve = header64.nt.pe_heap_reserve;
784                 SWAP64  (header64.nt.pe_heap_commit);
785                 header->nt.pe_heap_commit = header64.nt.pe_heap_commit;
786
787                 header->nt.pe_section_align = header64.nt.pe_section_align;
788                 header->nt.pe_file_alignment = header64.nt.pe_file_alignment;
789                 header->nt.pe_os_major = header64.nt.pe_os_major;
790                 header->nt.pe_os_minor = header64.nt.pe_os_minor;
791                 header->nt.pe_user_major = header64.nt.pe_user_major;
792                 header->nt.pe_user_minor = header64.nt.pe_user_minor;
793                 header->nt.pe_subsys_major = header64.nt.pe_subsys_major;
794                 header->nt.pe_subsys_minor = header64.nt.pe_subsys_minor;
795                 header->nt.pe_reserved_1 = header64.nt.pe_reserved_1;
796                 header->nt.pe_image_size = header64.nt.pe_image_size;
797                 header->nt.pe_header_size = header64.nt.pe_header_size;
798                 header->nt.pe_checksum = header64.nt.pe_checksum;
799                 header->nt.pe_subsys_required = header64.nt.pe_subsys_required;
800                 header->nt.pe_dll_flags = header64.nt.pe_dll_flags;
801                 header->nt.pe_loader_flags = header64.nt.pe_loader_flags;
802                 header->nt.pe_data_dir_count = header64.nt.pe_data_dir_count;
803
804                 /* copy the datadir */
805                 memcpy (&header->datadir, &header64.datadir, sizeof (MonoPEDatadir));
806         } else {
807                 return -1;
808         }
809
810         /* MonoPEHeaderNT: not used yet */
811         SWAP32  (header->nt.pe_section_align);       /* must be 8192 */
812         SWAP32  (header->nt.pe_file_alignment);      /* must be 512 or 4096 */
813         SWAP16  (header->nt.pe_os_major);            /* must be 4 */
814         SWAP16  (header->nt.pe_os_minor);            /* must be 0 */
815         SWAP16  (header->nt.pe_user_major);
816         SWAP16  (header->nt.pe_user_minor);
817         SWAP16  (header->nt.pe_subsys_major);
818         SWAP16  (header->nt.pe_subsys_minor);
819         SWAP32  (header->nt.pe_reserved_1);
820         SWAP32  (header->nt.pe_image_size);
821         SWAP32  (header->nt.pe_header_size);
822         SWAP32  (header->nt.pe_checksum);
823         SWAP16  (header->nt.pe_subsys_required);
824         SWAP16  (header->nt.pe_dll_flags);
825         SWAP32  (header->nt.pe_loader_flags);
826         SWAP32  (header->nt.pe_data_dir_count);
827
828         /* MonoDotNetHeader: mostly unused */
829         SWAPPDE (header->datadir.pe_export_table);
830         SWAPPDE (header->datadir.pe_import_table);
831         SWAPPDE (header->datadir.pe_resource_table);
832         SWAPPDE (header->datadir.pe_exception_table);
833         SWAPPDE (header->datadir.pe_certificate_table);
834         SWAPPDE (header->datadir.pe_reloc_table);
835         SWAPPDE (header->datadir.pe_debug);
836         SWAPPDE (header->datadir.pe_copyright);
837         SWAPPDE (header->datadir.pe_global_ptr);
838         SWAPPDE (header->datadir.pe_tls_table);
839         SWAPPDE (header->datadir.pe_load_config_table);
840         SWAPPDE (header->datadir.pe_bound_import);
841         SWAPPDE (header->datadir.pe_iat);
842         SWAPPDE (header->datadir.pe_delay_import_desc);
843         SWAPPDE (header->datadir.pe_cli_header);
844         SWAPPDE (header->datadir.pe_reserved);
845
846 #ifdef HOST_WIN32
847         if (image->is_module_handle)
848                 image->raw_data_len = header->nt.pe_image_size;
849 #endif
850
851         return offset;
852 }
853
854 gboolean
855 mono_image_load_pe_data (MonoImage *image)
856 {
857         return ((MonoImageLoader*)image->loader)->load_pe_data (image);
858 }
859
860 static gboolean
861 pe_image_load_pe_data (MonoImage *image)
862 {
863         MonoCLIImageInfo *iinfo;
864         MonoDotNetHeader *header;
865         MonoMSDOSHeader msdos;
866         gint32 offset = 0;
867
868         iinfo = image->image_info;
869         header = &iinfo->cli_header;
870
871 #ifdef HOST_WIN32
872         if (!image->is_module_handle)
873 #endif
874         if (offset + sizeof (msdos) > image->raw_data_len)
875                 goto invalid_image;
876         memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
877         
878         if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
879                 goto invalid_image;
880         
881         msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
882
883         offset = msdos.pe_offset;
884
885         offset = do_load_header (image, header, offset);
886         if (offset < 0)
887                 goto invalid_image;
888
889         /*
890          * this tests for a x86 machine type, but itanium, amd64 and others could be used, too.
891          * we skip this test.
892         if (header->coff.coff_machine != 0x14c)
893                 goto invalid_image;
894         */
895
896 #if 0
897         /*
898          * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
899          * which produces binaries with 7.0.  From Sergey:
900          *
901          * The reason is that MSVC7 uses traditional compile/link
902          * sequence for CIL executables, and VS.NET (and Framework
903          * SDK) includes linker version 7, that puts 7.0 in this
904          * field.  That's why it's currently not possible to load VC
905          * binaries with Mono.  This field is pretty much meaningless
906          * anyway (what linker?).
907          */
908         if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
909                 goto invalid_image;
910 #endif
911
912         /*
913          * FIXME: byte swap all addresses here for header.
914          */
915         
916         if (!load_section_tables (image, iinfo, offset))
917                 goto invalid_image;
918
919         return TRUE;
920
921 invalid_image:
922         return FALSE;
923 }
924
925 gboolean
926 mono_image_load_cli_data (MonoImage *image)
927 {
928         return ((MonoImageLoader*)image->loader)->load_cli_data (image);
929 }
930
931 static gboolean
932 pe_image_load_cli_data (MonoImage *image)
933 {
934         MonoCLIImageInfo *iinfo;
935         MonoDotNetHeader *header;
936
937         iinfo = image->image_info;
938         header = &iinfo->cli_header;
939
940         /* Load the CLI header */
941         if (!load_cli_header (image, iinfo))
942                 return FALSE;
943
944         if (!load_metadata (image, iinfo))
945                 return FALSE;
946
947         return TRUE;
948 }
949
950 void
951 mono_image_load_names (MonoImage *image)
952 {
953         /* modules don't have an assembly table row */
954         if (image->tables [MONO_TABLE_ASSEMBLY].rows) {
955                 image->assembly_name = mono_metadata_string_heap (image, 
956                         mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
957                                         0, MONO_ASSEMBLY_NAME));
958         }
959
960         /* Portable pdb images don't have a MODULE row */
961         if (image->tables [MONO_TABLE_MODULE].rows) {
962                 image->module_name = mono_metadata_string_heap (image,
963                         mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
964                                         0, MONO_MODULE_NAME));
965         }
966 }
967
968 static gboolean
969 pe_image_load_tables (MonoImage *image)
970 {
971         return TRUE;
972 }
973
974 static gboolean
975 pe_image_match (MonoImage *image)
976 {
977         if (image->raw_data [0] == 'M' && image->raw_data [1] == 'Z')
978                 return TRUE;
979         return FALSE;
980 }
981
982 static const MonoImageLoader pe_loader = {
983         pe_image_match,
984         pe_image_load_pe_data,
985         pe_image_load_cli_data,
986         pe_image_load_tables,
987 };
988
989 static void
990 install_pe_loader (void)
991 {
992         mono_install_image_loader (&pe_loader);
993 }
994
995 static MonoImage *
996 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
997                     gboolean care_about_cli, gboolean care_about_pecoff)
998 {
999         MonoCLIImageInfo *iinfo;
1000         MonoDotNetHeader *header;
1001         GSList *errors = NULL;
1002         GSList *l;
1003
1004         mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
1005
1006         mono_image_init (image);
1007
1008         iinfo = image->image_info;
1009         header = &iinfo->cli_header;
1010
1011         for (l = image_loaders; l; l = l->next) {
1012                 MonoImageLoader *loader = l->data;
1013                 if (loader->match (image)) {
1014                         image->loader = loader;
1015                         break;
1016                 }
1017         }
1018         if (!image->loader) {
1019                 *status = MONO_IMAGE_IMAGE_INVALID;
1020                 goto invalid_image;
1021         }
1022
1023         if (status)
1024                 *status = MONO_IMAGE_IMAGE_INVALID;
1025
1026         if (care_about_pecoff == FALSE)
1027                 goto done;
1028
1029         if (!image->metadata_only) {
1030                 if (image->loader == &pe_loader && !mono_verifier_verify_pe_data (image, &errors))
1031                         goto invalid_image;
1032
1033                 if (!mono_image_load_pe_data (image))
1034                         goto invalid_image;
1035         }
1036
1037         if (care_about_cli == FALSE) {
1038                 goto done;
1039         }
1040
1041         if (image->loader == &pe_loader && !mono_verifier_verify_cli_data (image, &errors))
1042                 goto invalid_image;
1043
1044         if (!mono_image_load_cli_data (image))
1045                 goto invalid_image;
1046
1047         if (image->loader == &pe_loader && !mono_verifier_verify_table_data (image, &errors))
1048                 goto invalid_image;
1049
1050         mono_image_load_names (image);
1051
1052         load_modules (image);
1053
1054 done:
1055         mono_profiler_module_loaded (image, MONO_PROFILE_OK);
1056         if (status)
1057                 *status = MONO_IMAGE_OK;
1058
1059         return image;
1060
1061 invalid_image:
1062         if (errors) {
1063                 MonoVerifyInfo *info = errors->data;
1064                 g_warning ("Could not load image %s due to %s", image->name, info->message);
1065                 mono_free_verify_list (errors);
1066         }
1067         mono_profiler_module_loaded (image, MONO_PROFILE_FAILED);
1068         mono_image_close (image);
1069         return NULL;
1070 }
1071
1072 static MonoImage *
1073 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
1074                                         gboolean care_about_cli, gboolean care_about_pecoff, gboolean refonly, gboolean metadata_only)
1075 {
1076         MonoCLIImageInfo *iinfo;
1077         MonoImage *image;
1078         MonoFileMap *filed;
1079
1080         if ((filed = mono_file_map_open (fname)) == NULL){
1081                 if (IS_PORTABILITY_SET) {
1082                         gchar *ffname = mono_portability_find_file (fname, TRUE);
1083                         if (ffname) {
1084                                 filed = mono_file_map_open (ffname);
1085                                 g_free (ffname);
1086                         }
1087                 }
1088
1089                 if (filed == NULL) {
1090                         if (status)
1091                                 *status = MONO_IMAGE_ERROR_ERRNO;
1092                         return NULL;
1093                 }
1094         }
1095
1096         image = g_new0 (MonoImage, 1);
1097         image->raw_buffer_used = TRUE;
1098         image->raw_data_len = mono_file_map_size (filed);
1099         image->raw_data = mono_file_map (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1100 #if defined(HAVE_MMAP) && !defined (HOST_WIN32)
1101         if (!image->raw_data) {
1102                 image->fileio_used = TRUE;
1103                 image->raw_data = mono_file_map_fileio (image->raw_data_len, MONO_MMAP_READ|MONO_MMAP_PRIVATE, mono_file_map_fd (filed), 0, &image->raw_data_handle);
1104         }
1105 #endif
1106         if (!image->raw_data) {
1107                 mono_file_map_close (filed);
1108                 g_free (image);
1109                 if (status)
1110                         *status = MONO_IMAGE_IMAGE_INVALID;
1111                 return NULL;
1112         }
1113         iinfo = g_new0 (MonoCLIImageInfo, 1);
1114         image->image_info = iinfo;
1115         image->name = mono_path_resolve_symlinks (fname);
1116         image->ref_only = refonly;
1117         image->metadata_only = metadata_only;
1118         image->ref_count = 1;
1119         /* if MONO_SECURITY_MODE_CORE_CLR is set then determine if this image is platform code */
1120         image->core_clr_platform_code = mono_security_core_clr_determine_platform_image (image);
1121
1122         mono_file_map_close (filed);
1123         return do_mono_image_load (image, status, care_about_cli, care_about_pecoff);
1124 }
1125
1126 MonoImage *
1127 mono_image_loaded_full (const char *name, gboolean refonly)
1128 {
1129         MonoImage *res;
1130         GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
1131         
1132         mono_images_lock ();
1133         res = g_hash_table_lookup (loaded_images, name);
1134         mono_images_unlock ();
1135         return res;
1136 }
1137
1138 /**
1139  * mono_image_loaded:
1140  * @name: name of the image to load
1141  *
1142  * This routine ensures that the given image is loaded.
1143  *
1144  * Returns: the loaded MonoImage, or NULL on failure.
1145  */
1146 MonoImage *
1147 mono_image_loaded (const char *name)
1148 {
1149         return mono_image_loaded_full (name, FALSE);
1150 }
1151
1152 typedef struct {
1153         MonoImage *res;
1154         const char* guid;
1155 } GuidData;
1156
1157 static void
1158 find_by_guid (gpointer key, gpointer val, gpointer user_data)
1159 {
1160         GuidData *data = user_data;
1161         MonoImage *image;
1162
1163         if (data->res)
1164                 return;
1165         image = val;
1166         if (strcmp (data->guid, mono_image_get_guid (image)) == 0)
1167                 data->res = image;
1168 }
1169
1170 MonoImage *
1171 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
1172 {
1173         GuidData data;
1174         GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
1175         data.res = NULL;
1176         data.guid = guid;
1177
1178         mono_images_lock ();
1179         g_hash_table_foreach (loaded_images, find_by_guid, &data);
1180         mono_images_unlock ();
1181         return data.res;
1182 }
1183
1184 MonoImage *
1185 mono_image_loaded_by_guid (const char *guid)
1186 {
1187         return mono_image_loaded_by_guid_full (guid, FALSE);
1188 }
1189
1190 static MonoImage *
1191 register_image (MonoImage *image)
1192 {
1193         MonoImage *image2;
1194         GHashTable *loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash;
1195
1196         mono_images_lock ();
1197         image2 = g_hash_table_lookup (loaded_images, image->name);
1198
1199         if (image2) {
1200                 /* Somebody else beat us to it */
1201                 mono_image_addref (image2);
1202                 mono_images_unlock ();
1203                 mono_image_close (image);
1204                 return image2;
1205         }
1206         g_hash_table_insert (loaded_images, image->name, image);
1207         if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == NULL))
1208                 g_hash_table_insert (loaded_images, (char *) image->assembly_name, image);      
1209         mono_images_unlock ();
1210
1211         return image;
1212 }
1213
1214 MonoImage *
1215 mono_image_open_from_data_internal (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, gboolean metadata_only, const char *name)
1216 {
1217         MonoCLIImageInfo *iinfo;
1218         MonoImage *image;
1219         char *datac;
1220
1221         if (!data || !data_len) {
1222                 if (status)
1223                         *status = MONO_IMAGE_IMAGE_INVALID;
1224                 return NULL;
1225         }
1226         datac = data;
1227         if (need_copy) {
1228                 datac = g_try_malloc (data_len);
1229                 if (!datac) {
1230                         if (status)
1231                                 *status = MONO_IMAGE_ERROR_ERRNO;
1232                         return NULL;
1233                 }
1234                 memcpy (datac, data, data_len);
1235         }
1236
1237         image = g_new0 (MonoImage, 1);
1238         image->raw_data = datac;
1239         image->raw_data_len = data_len;
1240         image->raw_data_allocated = need_copy;
1241         image->name = (name == NULL) ? g_strdup_printf ("data-%p", datac) : g_strdup(name);
1242         iinfo = g_new0 (MonoCLIImageInfo, 1);
1243         image->image_info = iinfo;
1244         image->ref_only = refonly;
1245         image->metadata_only = metadata_only;
1246
1247         image = do_mono_image_load (image, status, TRUE, TRUE);
1248         if (image == NULL)
1249                 return NULL;
1250
1251         return register_image (image);
1252 }
1253
1254 MonoImage *
1255 mono_image_open_from_data_with_name (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly, const char *name)
1256 {
1257         return mono_image_open_from_data_internal (data, data_len, need_copy, status, refonly, FALSE, name);
1258 }
1259
1260 MonoImage *
1261 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
1262 {
1263   return mono_image_open_from_data_with_name (data, data_len, need_copy, status, refonly, NULL);
1264 }
1265
1266 MonoImage *
1267 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
1268 {
1269         return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
1270 }
1271
1272 #ifdef HOST_WIN32
1273 /* fname is not duplicated. */
1274 MonoImage*
1275 mono_image_open_from_module_handle (HMODULE module_handle, char* fname, gboolean has_entry_point, MonoImageOpenStatus* status)
1276 {
1277         MonoImage* image;
1278         MonoCLIImageInfo* iinfo;
1279
1280         image = g_new0 (MonoImage, 1);
1281         image->raw_data = (char*) module_handle;
1282         image->is_module_handle = TRUE;
1283         iinfo = g_new0 (MonoCLIImageInfo, 1);
1284         image->image_info = iinfo;
1285         image->name = fname;
1286         image->ref_count = has_entry_point ? 0 : 1;
1287         image->has_entry_point = has_entry_point;
1288
1289         image = do_mono_image_load (image, status, TRUE, TRUE);
1290         if (image == NULL)
1291                 return NULL;
1292
1293         return register_image (image);
1294 }
1295 #endif
1296
1297 MonoImage *
1298 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
1299 {
1300         MonoImage *image;
1301         GHashTable *loaded_images;
1302         char *absfname;
1303         
1304         g_return_val_if_fail (fname != NULL, NULL);
1305         
1306 #ifdef HOST_WIN32
1307         /* Load modules using LoadLibrary. */
1308         if (!refonly && coree_module_handle) {
1309                 HMODULE module_handle;
1310                 guint16 *fname_utf16;
1311                 DWORD last_error;
1312
1313                 absfname = mono_path_resolve_symlinks (fname);
1314                 fname_utf16 = NULL;
1315
1316                 /* There is little overhead because the OS loader lock is held by LoadLibrary. */
1317                 mono_images_lock ();
1318                 image = g_hash_table_lookup (loaded_images_hash, absfname);
1319                 if (image) {
1320                         g_assert (image->is_module_handle);
1321                         if (image->has_entry_point && image->ref_count == 0) {
1322                                 /* Increment reference count on images loaded outside of the runtime. */
1323                                 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1324                                 /* The image is already loaded because _CorDllMain removes images from the hash. */
1325                                 module_handle = LoadLibrary (fname_utf16);
1326                                 g_assert (module_handle == (HMODULE) image->raw_data);
1327                         }
1328                         mono_image_addref (image);
1329                         mono_images_unlock ();
1330                         if (fname_utf16)
1331                                 g_free (fname_utf16);
1332                         g_free (absfname);
1333                         return image;
1334                 }
1335
1336                 fname_utf16 = g_utf8_to_utf16 (absfname, -1, NULL, NULL, NULL);
1337                 module_handle = MonoLoadImage (fname_utf16);
1338                 if (status && module_handle == NULL)
1339                         last_error = GetLastError ();
1340
1341                 /* mono_image_open_from_module_handle is called by _CorDllMain. */
1342                 image = g_hash_table_lookup (loaded_images_hash, absfname);
1343                 if (image)
1344                         mono_image_addref (image);
1345                 mono_images_unlock ();
1346
1347                 g_free (fname_utf16);
1348
1349                 if (module_handle == NULL) {
1350                         g_assert (!image);
1351                         g_free (absfname);
1352                         if (status) {
1353                                 if (last_error == ERROR_BAD_EXE_FORMAT || last_error == STATUS_INVALID_IMAGE_FORMAT)
1354                                         *status = MONO_IMAGE_IMAGE_INVALID;
1355                                 else {
1356                                         if (last_error == ERROR_FILE_NOT_FOUND || last_error == ERROR_PATH_NOT_FOUND)
1357                                                 errno = ENOENT;
1358                                         else
1359                                                 errno = 0;
1360                                 }
1361                         }
1362                         return NULL;
1363                 }
1364
1365                 if (image) {
1366                         g_assert (image->is_module_handle);
1367                         g_assert (image->has_entry_point);
1368                         g_free (absfname);
1369                         return image;
1370                 }
1371
1372                 return mono_image_open_from_module_handle (module_handle, absfname, FALSE, status);
1373         }
1374 #endif
1375
1376         absfname = mono_path_canonicalize (fname);
1377
1378         /*
1379          * The easiest solution would be to do all the loading inside the mutex,
1380          * but that would lead to scalability problems. So we let the loading
1381          * happen outside the mutex, and if multiple threads happen to load
1382          * the same image, we discard all but the first copy.
1383          */
1384         mono_images_lock ();
1385         loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
1386         image = g_hash_table_lookup (loaded_images, absfname);
1387         g_free (absfname);
1388         
1389         if (image){
1390                 mono_image_addref (image);
1391                 mono_images_unlock ();
1392                 return image;
1393         }
1394         mono_images_unlock ();
1395
1396         image = do_mono_image_open (fname, status, TRUE, TRUE, refonly, FALSE);
1397         if (image == NULL)
1398                 return NULL;
1399
1400         return register_image (image);
1401 }
1402
1403 /**
1404  * mono_image_open:
1405  * @fname: filename that points to the module we want to open
1406  * @status: An error condition is returned in this field
1407  *
1408  * Returns: An open image of type %MonoImage or NULL on error. 
1409  * The caller holds a temporary reference to the returned image which should be cleared 
1410  * when no longer needed by calling mono_image_close ().
1411  * if NULL, then check the value of @status for details on the error
1412  */
1413 MonoImage *
1414 mono_image_open (const char *fname, MonoImageOpenStatus *status)
1415 {
1416         return mono_image_open_full (fname, status, FALSE);
1417 }
1418
1419 /**
1420  * mono_pe_file_open:
1421  * @fname: filename that points to the module we want to open
1422  * @status: An error condition is returned in this field
1423  *
1424  * Returns: An open image of type %MonoImage or NULL on error.  if
1425  * NULL, then check the value of @status for details on the error.
1426  * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1427  * It's just a PE file loader, used for FileVersionInfo.  It also does
1428  * not use the image cache.
1429  */
1430 MonoImage *
1431 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1432 {
1433         g_return_val_if_fail (fname != NULL, NULL);
1434         
1435         return do_mono_image_open (fname, status, FALSE, TRUE, FALSE, FALSE);
1436 }
1437
1438 /**
1439  * mono_image_open_raw
1440  * @fname: filename that points to the module we want to open
1441  * @status: An error condition is returned in this field
1442  * 
1443  * Returns an image without loading neither pe or cli data.
1444  * 
1445  * Use mono_image_load_pe_data and mono_image_load_cli_data to load them.  
1446  */
1447 MonoImage *
1448 mono_image_open_raw (const char *fname, MonoImageOpenStatus *status)
1449 {
1450         g_return_val_if_fail (fname != NULL, NULL);
1451         
1452         return do_mono_image_open (fname, status, FALSE, FALSE, FALSE, FALSE);
1453 }
1454
1455 /*
1456  * mono_image_open_metadata_only:
1457  *
1458  *   Open an image which contains metadata only without a PE header.
1459  */
1460 MonoImage *
1461 mono_image_open_metadata_only (const char *fname, MonoImageOpenStatus *status)
1462 {
1463         return do_mono_image_open (fname, status, TRUE, TRUE, FALSE, TRUE);
1464 }
1465
1466 void
1467 mono_image_fixup_vtable (MonoImage *image)
1468 {
1469 #ifdef HOST_WIN32
1470         MonoCLIImageInfo *iinfo;
1471         MonoPEDirEntry *de;
1472         MonoVTableFixup *vtfixup;
1473         int count;
1474         gpointer slot;
1475         guint16 slot_type;
1476         int slot_count;
1477
1478         g_assert (image->is_module_handle);
1479
1480         iinfo = image->image_info;
1481         de = &iinfo->cli_cli_header.ch_vtable_fixups;
1482         if (!de->rva || !de->size)
1483                 return;
1484         vtfixup = (MonoVTableFixup*) mono_image_rva_map (image, de->rva);
1485         if (!vtfixup)
1486                 return;
1487         
1488         count = de->size / sizeof (MonoVTableFixup);
1489         while (count--) {
1490                 if (!vtfixup->rva || !vtfixup->count)
1491                         continue;
1492
1493                 slot = mono_image_rva_map (image, vtfixup->rva);
1494                 g_assert (slot);
1495                 slot_type = vtfixup->type;
1496                 slot_count = vtfixup->count;
1497                 if (slot_type & VTFIXUP_TYPE_32BIT)
1498                         while (slot_count--) {
1499                                 *((guint32*) slot) = (guint32) mono_marshal_get_vtfixup_ftnptr (image, *((guint32*) slot), slot_type);
1500                                 slot = ((guint32*) slot) + 1;
1501                         }
1502                 else if (slot_type & VTFIXUP_TYPE_64BIT)
1503                         while (slot_count--) {
1504                                 *((guint64*) slot) = (guint64) mono_marshal_get_vtfixup_ftnptr (image, *((guint64*) slot), slot_type);
1505                                 slot = ((guint32*) slot) + 1;
1506                         }
1507                 else
1508                         g_assert_not_reached();
1509
1510                 vtfixup++;
1511         }
1512 #else
1513         g_assert_not_reached();
1514 #endif
1515 }
1516
1517 static void
1518 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1519 {
1520         g_hash_table_destroy ((GHashTable*)val);
1521 }
1522
1523 /*
1524 static void
1525 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1526 {
1527         mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1528 }
1529 */
1530
1531 static void
1532 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1533 {
1534         g_slist_free ((GSList*)val);
1535 }
1536
1537 /**
1538  * mono_image_addref:
1539  * @image: The image file we wish to add a reference to
1540  *
1541  *  Increases the reference count of an image.
1542  */
1543 void
1544 mono_image_addref (MonoImage *image)
1545 {
1546         InterlockedIncrement (&image->ref_count);
1547 }       
1548
1549 void
1550 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1551 {
1552         stream->alloc_size = stream->index = stream->offset = 0;
1553         g_free (stream->data);
1554         stream->data = NULL;
1555         if (stream->hash) {
1556                 g_hash_table_destroy (stream->hash);
1557                 stream->hash = NULL;
1558         }
1559 }
1560
1561 static inline void
1562 free_hash (GHashTable *hash)
1563 {
1564         if (hash)
1565                 g_hash_table_destroy (hash);
1566 }
1567
1568 void
1569 mono_wrapper_caches_free (MonoWrapperCaches *cache)
1570 {
1571         free_hash (cache->delegate_invoke_cache);
1572         free_hash (cache->delegate_begin_invoke_cache);
1573         free_hash (cache->delegate_end_invoke_cache);
1574         free_hash (cache->runtime_invoke_cache);
1575         free_hash (cache->runtime_invoke_vtype_cache);
1576         
1577         free_hash (cache->delegate_abstract_invoke_cache);
1578
1579         free_hash (cache->runtime_invoke_direct_cache);
1580         free_hash (cache->managed_wrapper_cache);
1581
1582         free_hash (cache->native_wrapper_cache);
1583         free_hash (cache->native_wrapper_aot_cache);
1584         free_hash (cache->native_wrapper_check_cache);
1585         free_hash (cache->native_wrapper_aot_check_cache);
1586
1587         free_hash (cache->native_func_wrapper_aot_cache);
1588         free_hash (cache->remoting_invoke_cache);
1589         free_hash (cache->synchronized_cache);
1590         free_hash (cache->unbox_wrapper_cache);
1591         free_hash (cache->cominterop_invoke_cache);
1592         free_hash (cache->cominterop_wrapper_cache);
1593         free_hash (cache->thunk_invoke_cache);
1594 }
1595
1596 /*
1597  * Returns whether mono_image_close_finish() must be called as well.
1598  * We must unload images in two steps because clearing the domain in
1599  * SGen requires the class metadata to be intact, but we need to free
1600  * the mono_g_hash_tables in case a collection occurs during domain
1601  * unloading and the roots would trip up the GC.
1602  */
1603 gboolean
1604 mono_image_close_except_pools (MonoImage *image)
1605 {
1606         MonoImage *image2;
1607         GHashTable *loaded_images;
1608         int i;
1609
1610         g_return_val_if_fail (image != NULL, FALSE);
1611
1612         /* 
1613          * Atomically decrement the refcount and remove ourselves from the hash tables, so
1614          * register_image () can't grab an image which is being closed.
1615          */
1616         mono_images_lock ();
1617
1618         if (InterlockedDecrement (&image->ref_count) > 0) {
1619                 mono_images_unlock ();
1620                 return FALSE;
1621         }
1622
1623         loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash;
1624         image2 = g_hash_table_lookup (loaded_images, image->name);
1625         if (image == image2) {
1626                 /* This is not true if we are called from mono_image_open () */
1627                 g_hash_table_remove (loaded_images, image->name);
1628         }
1629         if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image))
1630                 g_hash_table_remove (loaded_images, (char *) image->assembly_name);     
1631
1632         mono_images_unlock ();
1633
1634 #ifdef HOST_WIN32
1635         if (image->is_module_handle && image->has_entry_point) {
1636                 mono_images_lock ();
1637                 if (image->ref_count == 0) {
1638                         /* Image will be closed by _CorDllMain. */
1639                         FreeLibrary ((HMODULE) image->raw_data);
1640                         mono_images_unlock ();
1641                         return FALSE;
1642                 }
1643                 mono_images_unlock ();
1644         }
1645 #endif
1646
1647         mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD);
1648
1649         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1650
1651         mono_image_invoke_unload_hook (image);
1652
1653         mono_metadata_clean_for_image (image);
1654
1655         /*
1656          * The caches inside a MonoImage might refer to metadata which is stored in referenced 
1657          * assemblies, so we can't release these references in mono_assembly_close () since the
1658          * MonoImage might outlive its associated MonoAssembly.
1659          */
1660         if (image->references && !image_is_dynamic (image)) {
1661                 for (i = 0; i < image->nreferences; i++) {
1662                         if (image->references [i] && image->references [i] != REFERENCE_MISSING) {
1663                                 if (!mono_assembly_close_except_image_pools (image->references [i]))
1664                                         image->references [i] = NULL;
1665                         }
1666                 }
1667         } else {
1668                 if (image->references) {
1669                         g_free (image->references);
1670                         image->references = NULL;
1671                 }
1672         }
1673
1674 #ifdef HOST_WIN32
1675         mono_images_lock ();
1676         if (image->is_module_handle && !image->has_entry_point)
1677                 FreeLibrary ((HMODULE) image->raw_data);
1678         mono_images_unlock ();
1679 #endif
1680
1681         if (image->raw_buffer_used) {
1682                 if (image->raw_data != NULL) {
1683 #ifndef HOST_WIN32
1684                         if (image->fileio_used)
1685                                 mono_file_unmap_fileio (image->raw_data, image->raw_data_handle);
1686                         else
1687 #endif
1688                                 mono_file_unmap (image->raw_data, image->raw_data_handle);
1689                 }
1690         }
1691         
1692         if (image->raw_data_allocated) {
1693                 /* FIXME: do we need this? (image is disposed anyway) */
1694                 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1695                 MonoCLIImageInfo *ii = image->image_info;
1696
1697                 if ((image->raw_metadata > image->raw_data) &&
1698                         (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1699                         image->raw_metadata = NULL;
1700
1701                 for (i = 0; i < ii->cli_section_count; i++)
1702                         if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1703                                 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1704                                 ii->cli_sections [i] = NULL;
1705
1706                 g_free (image->raw_data);
1707         }
1708
1709         if (debug_assembly_unload) {
1710                 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1711         } else {
1712                 g_free (image->name);
1713                 g_free (image->guid);
1714                 g_free (image->version);
1715                 g_free (image->files);
1716         }
1717
1718         if (image->method_cache)
1719                 g_hash_table_destroy (image->method_cache);
1720         if (image->methodref_cache)
1721                 g_hash_table_destroy (image->methodref_cache);
1722         mono_internal_hash_table_destroy (&image->class_cache);
1723         mono_conc_hashtable_destroy (image->field_cache);
1724         if (image->array_cache) {
1725                 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1726                 g_hash_table_destroy (image->array_cache);
1727         }
1728         if (image->szarray_cache)
1729                 g_hash_table_destroy (image->szarray_cache);
1730         if (image->ptr_cache)
1731                 g_hash_table_destroy (image->ptr_cache);
1732         if (image->name_cache) {
1733                 g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1734                 g_hash_table_destroy (image->name_cache);
1735         }
1736
1737         free_hash (image->delegate_bound_static_invoke_cache);
1738         free_hash (image->runtime_invoke_vcall_cache);
1739         free_hash (image->ldfld_wrapper_cache);
1740         free_hash (image->ldflda_wrapper_cache);
1741         free_hash (image->stfld_wrapper_cache);
1742         free_hash (image->isinst_cache);
1743         free_hash (image->castclass_cache);
1744         free_hash (image->proxy_isinst_cache);
1745         free_hash (image->var_cache_slow);
1746         free_hash (image->mvar_cache_slow);
1747         free_hash (image->var_cache_constrained);
1748         free_hash (image->mvar_cache_constrained);
1749         free_hash (image->wrapper_param_names);
1750         free_hash (image->pinvoke_scopes);
1751         free_hash (image->pinvoke_scope_filenames);
1752         free_hash (image->native_func_wrapper_cache);
1753         free_hash (image->typespec_cache);
1754
1755         mono_wrapper_caches_free (&image->wrapper_caches);
1756
1757         for (i = 0; i < image->gshared_types_len; ++i)
1758                 free_hash (image->gshared_types [i]);
1759         g_free (image->gshared_types);
1760
1761         /* The ownership of signatures is not well defined */
1762         g_hash_table_destroy (image->memberref_signatures);
1763         g_hash_table_destroy (image->helper_signatures);
1764         g_hash_table_destroy (image->method_signatures);
1765
1766         if (image->rgctx_template_hash)
1767                 g_hash_table_destroy (image->rgctx_template_hash);
1768
1769         if (image->property_hash)
1770                 mono_property_hash_destroy (image->property_hash);
1771
1772         /*
1773         reflection_info_unregister_classes is only required by dynamic images, which will not be properly
1774         cleared during shutdown as we don't perform regular appdomain unload for the root one.
1775         */
1776         g_assert (!image->reflection_info_unregister_classes || mono_runtime_is_shutting_down ());
1777         image->reflection_info_unregister_classes = NULL;
1778
1779         if (image->interface_bitset) {
1780                 mono_unload_interface_ids (image->interface_bitset);
1781                 mono_bitset_free (image->interface_bitset);
1782         }
1783         if (image->image_info){
1784                 MonoCLIImageInfo *ii = image->image_info;
1785
1786                 if (ii->cli_section_tables)
1787                         g_free (ii->cli_section_tables);
1788                 if (ii->cli_sections)
1789                         g_free (ii->cli_sections);
1790                 g_free (image->image_info);
1791         }
1792
1793         for (i = 0; i < image->module_count; ++i) {
1794                 if (image->modules [i]) {
1795                         if (!mono_image_close_except_pools (image->modules [i]))
1796                                 image->modules [i] = NULL;
1797                 }
1798         }
1799         if (image->modules_loaded)
1800                 g_free (image->modules_loaded);
1801
1802         mono_mutex_destroy (&image->szarray_cache_lock);
1803         mono_mutex_destroy (&image->lock);
1804
1805         /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
1806         if (image_is_dynamic (image)) {
1807                 /* Dynamic images are GC_MALLOCed */
1808                 g_free ((char*)image->module_name);
1809                 mono_dynamic_image_free ((MonoDynamicImage*)image);
1810         }
1811
1812         mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
1813
1814         return TRUE;
1815 }
1816
1817 void
1818 mono_image_close_finish (MonoImage *image)
1819 {
1820         int i;
1821
1822         if (image->references && !image_is_dynamic (image)) {
1823                 for (i = 0; i < image->nreferences; i++) {
1824                         if (image->references [i] && image->references [i] != REFERENCE_MISSING)
1825                                 mono_assembly_close_finish (image->references [i]);
1826                 }
1827
1828                 g_free (image->references);
1829                 image->references = NULL;
1830         }
1831
1832         for (i = 0; i < image->module_count; ++i) {
1833                 if (image->modules [i])
1834                         mono_image_close_finish (image->modules [i]);
1835         }
1836         if (image->modules)
1837                 g_free (image->modules);
1838
1839 #ifndef DISABLE_PERFCOUNTERS
1840         mono_perfcounters->loader_bytes -= mono_mempool_get_allocated (image->mempool);
1841 #endif
1842
1843         if (!image_is_dynamic (image)) {
1844                 if (debug_assembly_unload)
1845                         mono_mempool_invalidate (image->mempool);
1846                 else {
1847                         mono_mempool_destroy (image->mempool);
1848                         g_free (image);
1849                 }
1850         } else {
1851                 if (debug_assembly_unload)
1852                         mono_mempool_invalidate (image->mempool);
1853                 else {
1854                         mono_mempool_destroy (image->mempool);
1855                         mono_dynamic_image_free_image ((MonoDynamicImage*)image);
1856                 }
1857         }
1858 }
1859
1860 /**
1861  * mono_image_close:
1862  * @image: The image file we wish to close
1863  *
1864  * Closes an image file, deallocates all memory consumed and
1865  * unmaps all possible sections of the file
1866  */
1867 void
1868 mono_image_close (MonoImage *image)
1869 {
1870         if (mono_image_close_except_pools (image))
1871                 mono_image_close_finish (image);
1872 }
1873
1874 /** 
1875  * mono_image_strerror:
1876  * @status: an code indicating the result from a recent operation
1877  *
1878  * Returns: a string describing the error
1879  */
1880 const char *
1881 mono_image_strerror (MonoImageOpenStatus status)
1882 {
1883         switch (status){
1884         case MONO_IMAGE_OK:
1885                 return "success";
1886         case MONO_IMAGE_ERROR_ERRNO:
1887                 return strerror (errno);
1888         case MONO_IMAGE_IMAGE_INVALID:
1889                 return "File does not contain a valid CIL image";
1890         case MONO_IMAGE_MISSING_ASSEMBLYREF:
1891                 return "An assembly was referenced, but could not be found";
1892         }
1893         return "Internal error";
1894 }
1895
1896 static gpointer
1897 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
1898                                guint32 lang_id, gunichar2 *name,
1899                                MonoPEResourceDirEntry *entry,
1900                                MonoPEResourceDir *root, guint32 level)
1901 {
1902         gboolean is_string, is_dir;
1903         guint32 name_offset, dir_offset;
1904
1905         /* Level 0 holds a directory entry for each type of resource
1906          * (identified by ID or name).
1907          *
1908          * Level 1 holds a directory entry for each named resource
1909          * item, and each "anonymous" item of a particular type of
1910          * resource.
1911          *
1912          * Level 2 holds a directory entry for each language pointing to
1913          * the actual data.
1914          */
1915         is_string = MONO_PE_RES_DIR_ENTRY_NAME_IS_STRING (*entry);
1916         name_offset = MONO_PE_RES_DIR_ENTRY_NAME_OFFSET (*entry);
1917
1918         is_dir = MONO_PE_RES_DIR_ENTRY_IS_DIR (*entry);
1919         dir_offset = MONO_PE_RES_DIR_ENTRY_DIR_OFFSET (*entry);
1920
1921         if(level==0) {
1922                 if (is_string)
1923                         return NULL;
1924         } else if (level==1) {
1925                 if (res_id != name_offset)
1926                         return NULL;
1927 #if 0
1928                 if(name!=NULL &&
1929                    is_string==TRUE && name!=lookup (name_offset)) {
1930                         return(NULL);
1931                 }
1932 #endif
1933         } else if (level==2) {
1934                 if (is_string == TRUE || (is_string == FALSE && lang_id != 0 && name_offset != lang_id))
1935                         return NULL;
1936         } else {
1937                 g_assert_not_reached ();
1938         }
1939
1940         if(is_dir==TRUE) {
1941                 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+dir_offset);
1942                 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
1943                 guint32 entries, i;
1944
1945                 entries = GUINT16_FROM_LE (res_dir->res_named_entries) + GUINT16_FROM_LE (res_dir->res_id_entries);
1946
1947                 for(i=0; i<entries; i++) {
1948                         MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
1949                         gpointer ret;
1950                         
1951                         ret=mono_image_walk_resource_tree (info, res_id,
1952                                                            lang_id, name,
1953                                                            sub_entry, root,
1954                                                            level+1);
1955                         if(ret!=NULL) {
1956                                 return(ret);
1957                         }
1958                 }
1959
1960                 return(NULL);
1961         } else {
1962                 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+dir_offset);
1963                 MonoPEResourceDataEntry *res;
1964
1965                 res = g_new0 (MonoPEResourceDataEntry, 1);
1966
1967                 res->rde_data_offset = GUINT32_TO_LE (data_entry->rde_data_offset);
1968                 res->rde_size = GUINT32_TO_LE (data_entry->rde_size);
1969                 res->rde_codepage = GUINT32_TO_LE (data_entry->rde_codepage);
1970                 res->rde_reserved = GUINT32_TO_LE (data_entry->rde_reserved);
1971
1972                 return (res);
1973         }
1974 }
1975
1976 /**
1977  * mono_image_lookup_resource:
1978  * @image: the image to look up the resource in
1979  * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
1980  * @lang_id: The language id.
1981  * @name: the resource name to lookup.
1982  *
1983  * Returns: NULL if not found, otherwise a pointer to the in-memory representation
1984  * of the given resource. The caller should free it using g_free () when no longer
1985  * needed.
1986  */
1987 gpointer
1988 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
1989 {
1990         MonoCLIImageInfo *info;
1991         MonoDotNetHeader *header;
1992         MonoPEDatadir *datadir;
1993         MonoPEDirEntry *rsrc;
1994         MonoPEResourceDir *resource_dir;
1995         MonoPEResourceDirEntry *res_entries;
1996         guint32 entries, i;
1997
1998         if(image==NULL) {
1999                 return(NULL);
2000         }
2001
2002         mono_image_ensure_section_idx (image, MONO_SECTION_RSRC);
2003
2004         info=image->image_info;
2005         if(info==NULL) {
2006                 return(NULL);
2007         }
2008
2009         header=&info->cli_header;
2010         if(header==NULL) {
2011                 return(NULL);
2012         }
2013
2014         datadir=&header->datadir;
2015         if(datadir==NULL) {
2016                 return(NULL);
2017         }
2018
2019         rsrc=&datadir->pe_resource_table;
2020         if(rsrc==NULL) {
2021                 return(NULL);
2022         }
2023
2024         resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
2025         if(resource_dir==NULL) {
2026                 return(NULL);
2027         }
2028
2029         entries = GUINT16_FROM_LE (resource_dir->res_named_entries) + GUINT16_FROM_LE (resource_dir->res_id_entries);
2030         res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
2031         
2032         for(i=0; i<entries; i++) {
2033                 MonoPEResourceDirEntry *entry=&res_entries[i];
2034                 gpointer ret;
2035                 
2036                 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
2037                                                    name, entry, resource_dir,
2038                                                    0);
2039                 if(ret!=NULL) {
2040                         return(ret);
2041                 }
2042         }
2043
2044         return(NULL);
2045 }
2046
2047 /** 
2048  * mono_image_get_entry_point:
2049  * @image: the image where the entry point will be looked up.
2050  *
2051  * Use this routine to determine the metadata token for method that
2052  * has been flagged as the entry point.
2053  *
2054  * Returns: the token for the entry point method in the image
2055  */
2056 guint32
2057 mono_image_get_entry_point (MonoImage *image)
2058 {
2059         return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
2060 }
2061
2062 /**
2063  * mono_image_get_resource:
2064  * @image: the image where the resource will be looked up.
2065  * @offset: The offset to add to the resource
2066  * @size: a pointer to an int where the size of the resource will be stored
2067  *
2068  * This is a low-level routine that fetches a resource from the
2069  * metadata that starts at a given @offset.  The @size parameter is
2070  * filled with the data field as encoded in the metadata.
2071  *
2072  * Returns: the pointer to the resource whose offset is @offset.
2073  */
2074 const char*
2075 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
2076 {
2077         MonoCLIImageInfo *iinfo = image->image_info;
2078         MonoCLIHeader *ch = &iinfo->cli_cli_header;
2079         const char* data;
2080
2081         if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
2082                 return NULL;
2083         
2084         data = mono_image_rva_map (image, ch->ch_resources.rva);
2085         if (!data)
2086                 return NULL;
2087         data += offset;
2088         if (size)
2089                 *size = read32 (data);
2090         data += 4;
2091         return data;
2092 }
2093
2094 MonoImage*
2095 mono_image_load_file_for_image (MonoImage *image, int fileidx)
2096 {
2097         char *base_dir, *name;
2098         MonoImage *res;
2099         MonoTableInfo  *t = &image->tables [MONO_TABLE_FILE];
2100         const char *fname;
2101         guint32 fname_id;
2102
2103         if (fileidx < 1 || fileidx > t->rows)
2104                 return NULL;
2105
2106         mono_image_lock (image);
2107         if (image->files && image->files [fileidx - 1]) {
2108                 mono_image_unlock (image);
2109                 return image->files [fileidx - 1];
2110         }
2111         mono_image_unlock (image);
2112
2113         fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
2114         fname = mono_metadata_string_heap (image, fname_id);
2115         base_dir = g_path_get_dirname (image->name);
2116         name = g_build_filename (base_dir, fname, NULL);
2117         res = mono_image_open (name, NULL);
2118         if (!res)
2119                 goto done;
2120
2121         mono_image_lock (image);
2122         if (image->files && image->files [fileidx - 1]) {
2123                 MonoImage *old = res;
2124                 res = image->files [fileidx - 1];
2125                 mono_image_unlock (image);
2126                 mono_image_close (old);
2127         } else {
2128                 int i;
2129                 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
2130                 res->assembly = image->assembly;
2131                 for (i = 0; i < res->module_count; ++i) {
2132                         if (res->modules [i] && !res->modules [i]->assembly)
2133                                 res->modules [i]->assembly = image->assembly;
2134                 }
2135
2136                 if (!image->files)
2137                         image->files = g_new0 (MonoImage*, t->rows);
2138                 image->files [fileidx - 1] = res;
2139                 mono_image_unlock (image);
2140                 /* vtable fixup can't happen with the image lock held */
2141 #ifdef HOST_WIN32
2142                 if (res->is_module_handle)
2143                         mono_image_fixup_vtable (res);
2144 #endif
2145         }
2146
2147 done:
2148         g_free (name);
2149         g_free (base_dir);
2150         return res;
2151 }
2152
2153 /**
2154  * mono_image_get_strong_name:
2155  * @image: a MonoImage
2156  * @size: a guint32 pointer, or NULL.
2157  *
2158  * If the image has a strong name, and @size is not NULL, the value
2159  * pointed to by size will have the size of the strong name.
2160  *
2161  * Returns: NULL if the image does not have a strong name, or a
2162  * pointer to the public key.
2163  */
2164 const char*
2165 mono_image_get_strong_name (MonoImage *image, guint32 *size)
2166 {
2167         MonoCLIImageInfo *iinfo = image->image_info;
2168         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2169         const char* data;
2170
2171         if (!de->size || !de->rva)
2172                 return NULL;
2173         data = mono_image_rva_map (image, de->rva);
2174         if (!data)
2175                 return NULL;
2176         if (size)
2177                 *size = de->size;
2178         return data;
2179 }
2180
2181 /**
2182  * mono_image_strong_name_position:
2183  * @image: a MonoImage
2184  * @size: a guint32 pointer, or NULL.
2185  *
2186  * If the image has a strong name, and @size is not NULL, the value
2187  * pointed to by size will have the size of the strong name.
2188  *
2189  * Returns: the position within the image file where the strong name
2190  * is stored.
2191  */
2192 guint32
2193 mono_image_strong_name_position (MonoImage *image, guint32 *size)
2194 {
2195         MonoCLIImageInfo *iinfo = image->image_info;
2196         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
2197         guint32 pos;
2198
2199         if (size)
2200                 *size = de->size;
2201         if (!de->size || !de->rva)
2202                 return 0;
2203         pos = mono_cli_rva_image_map (image, de->rva);
2204         return pos == INVALID_ADDRESS ? 0 : pos;
2205 }
2206
2207 /**
2208  * mono_image_get_public_key:
2209  * @image: a MonoImage
2210  * @size: a guint32 pointer, or NULL.
2211  *
2212  * This is used to obtain the public key in the @image.
2213  * 
2214  * If the image has a public key, and @size is not NULL, the value
2215  * pointed to by size will have the size of the public key.
2216  * 
2217  * Returns: NULL if the image does not have a public key, or a pointer
2218  * to the public key.
2219  */
2220 const char*
2221 mono_image_get_public_key (MonoImage *image, guint32 *size)
2222 {
2223         const char *pubkey;
2224         guint32 len, tok;
2225
2226         if (image_is_dynamic (image)) {
2227                 if (size)
2228                         *size = ((MonoDynamicImage*)image)->public_key_len;
2229                 return (char*)((MonoDynamicImage*)image)->public_key;
2230         }
2231         if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
2232                 return NULL;
2233         tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
2234         if (!tok)
2235                 return NULL;
2236         pubkey = mono_metadata_blob_heap (image, tok);
2237         len = mono_metadata_decode_blob_size (pubkey, &pubkey);
2238         if (size)
2239                 *size = len;
2240         return pubkey;
2241 }
2242
2243 /**
2244  * mono_image_get_name:
2245  * @name: a MonoImage
2246  *
2247  * Returns: the name of the assembly.
2248  */
2249 const char*
2250 mono_image_get_name (MonoImage *image)
2251 {
2252         return image->assembly_name;
2253 }
2254
2255 /**
2256  * mono_image_get_filename:
2257  * @image: a MonoImage
2258  *
2259  * Used to get the filename that hold the actual MonoImage
2260  *
2261  * Returns: the filename.
2262  */
2263 const char*
2264 mono_image_get_filename (MonoImage *image)
2265 {
2266         return image->name;
2267 }
2268
2269 const char*
2270 mono_image_get_guid (MonoImage *image)
2271 {
2272         return image->guid;
2273 }
2274
2275 const MonoTableInfo*
2276 mono_image_get_table_info (MonoImage *image, int table_id)
2277 {
2278         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2279                 return NULL;
2280         return &image->tables [table_id];
2281 }
2282
2283 int
2284 mono_image_get_table_rows (MonoImage *image, int table_id)
2285 {
2286         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
2287                 return 0;
2288         return image->tables [table_id].rows;
2289 }
2290
2291 int
2292 mono_table_info_get_rows (const MonoTableInfo *table)
2293 {
2294         return table->rows;
2295 }
2296
2297 /**
2298  * mono_image_get_assembly:
2299  * @image: the MonoImage.
2300  *
2301  * Use this routine to get the assembly that owns this image.
2302  *
2303  * Returns: the assembly that holds this image.
2304  */
2305 MonoAssembly* 
2306 mono_image_get_assembly (MonoImage *image)
2307 {
2308         return image->assembly;
2309 }
2310
2311 /**
2312  * mono_image_is_dynamic:
2313  * @image: the MonoImage
2314  *
2315  * Determines if the given image was created dynamically through the
2316  * System.Reflection.Emit API
2317  *
2318  * Returns: TRUE if the image was created dynamically, FALSE if not.
2319  */
2320 gboolean
2321 mono_image_is_dynamic (MonoImage *image)
2322 {
2323         return image_is_dynamic (image);
2324 }
2325
2326 /**
2327  * mono_image_has_authenticode_entry:
2328  * @image: the MonoImage
2329  *
2330  * Use this routine to determine if the image has a Authenticode
2331  * Certificate Table.
2332  *
2333  * Returns: TRUE if the image contains an authenticode entry in the PE
2334  * directory.
2335  */
2336 gboolean
2337 mono_image_has_authenticode_entry (MonoImage *image)
2338 {
2339         MonoCLIImageInfo *iinfo = image->image_info;
2340         MonoDotNetHeader *header = &iinfo->cli_header;
2341         MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
2342         // the Authenticode "pre" (non ASN.1) header is 8 bytes long
2343         return ((de->rva != 0) && (de->size > 8));
2344 }
2345
2346 gpointer
2347 mono_image_alloc (MonoImage *image, guint size)
2348 {
2349         gpointer res;
2350
2351 #ifndef DISABLE_PERFCOUNTERS
2352         mono_perfcounters->loader_bytes += size;
2353 #endif
2354         mono_image_lock (image);
2355         res = mono_mempool_alloc (image->mempool, size);
2356         mono_image_unlock (image);
2357
2358         return res;
2359 }
2360
2361 gpointer
2362 mono_image_alloc0 (MonoImage *image, guint size)
2363 {
2364         gpointer res;
2365
2366 #ifndef DISABLE_PERFCOUNTERS
2367         mono_perfcounters->loader_bytes += size;
2368 #endif
2369         mono_image_lock (image);
2370         res = mono_mempool_alloc0 (image->mempool, size);
2371         mono_image_unlock (image);
2372
2373         return res;
2374 }
2375
2376 char*
2377 mono_image_strdup (MonoImage *image, const char *s)
2378 {
2379         char *res;
2380
2381 #ifndef DISABLE_PERFCOUNTERS
2382         mono_perfcounters->loader_bytes += strlen (s);
2383 #endif
2384         mono_image_lock (image);
2385         res = mono_mempool_strdup (image->mempool, s);
2386         mono_image_unlock (image);
2387
2388         return res;
2389 }
2390
2391 GList*
2392 g_list_prepend_image (MonoImage *image, GList *list, gpointer data)
2393 {
2394         GList *new_list;
2395         
2396         new_list = mono_image_alloc (image, sizeof (GList));
2397         new_list->data = data;
2398         new_list->prev = list ? list->prev : NULL;
2399     new_list->next = list;
2400
2401     if (new_list->prev)
2402             new_list->prev->next = new_list;
2403     if (list)
2404             list->prev = new_list;
2405
2406         return new_list;
2407 }
2408
2409 GSList*
2410 g_slist_append_image (MonoImage *image, GSList *list, gpointer data)
2411 {
2412         GSList *new_list;
2413
2414         new_list = mono_image_alloc (image, sizeof (GSList));
2415         new_list->data = data;
2416         new_list->next = NULL;
2417
2418         return g_slist_concat (list, new_list);
2419 }
2420
2421 void
2422 mono_image_lock (MonoImage *image)
2423 {
2424         mono_locks_acquire (&image->lock, ImageDataLock);
2425 }
2426
2427 void
2428 mono_image_unlock (MonoImage *image)
2429 {
2430         mono_locks_release (&image->lock, ImageDataLock);
2431 }
2432
2433
2434 /**
2435  * mono_image_property_lookup:
2436  *
2437  * Lookup a property on @image. Used to store very rare fields of MonoClass and MonoMethod.
2438  *
2439  * LOCKING: Takes the image lock
2440  */
2441 gpointer 
2442 mono_image_property_lookup (MonoImage *image, gpointer subject, guint32 property)
2443 {
2444         gpointer res;
2445
2446         mono_image_lock (image);
2447         res = mono_property_hash_lookup (image->property_hash, subject, property);
2448         mono_image_unlock (image);
2449
2450         return res;
2451 }
2452
2453 /**
2454  * mono_image_property_insert:
2455  *
2456  * Insert a new property @property with value @value on @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2457  *
2458  * LOCKING: Takes the image lock
2459  */
2460 void
2461 mono_image_property_insert (MonoImage *image, gpointer subject, guint32 property, gpointer value)
2462 {
2463         mono_image_lock (image);
2464         mono_property_hash_insert (image->property_hash, subject, property, value);
2465         mono_image_unlock (image);
2466 }
2467
2468 /**
2469  * mono_image_property_remove:
2470  *
2471  * Remove all properties associated with @subject in @image. Used to store very rare fields of MonoClass and MonoMethod.
2472  *
2473  * LOCKING: Takes the image lock
2474  */
2475 void
2476 mono_image_property_remove (MonoImage *image, gpointer subject)
2477 {
2478         mono_image_lock (image);
2479         mono_property_hash_remove_object (image->property_hash, subject);
2480         mono_image_unlock (image);
2481 }
2482
2483 void
2484 mono_image_append_class_to_reflection_info_set (MonoClass *class)
2485 {
2486         MonoImage *image = class->image;
2487         g_assert (image_is_dynamic (image));
2488         mono_image_lock (image);
2489         image->reflection_info_unregister_classes = g_slist_prepend_mempool (image->mempool, image->reflection_info_unregister_classes, class);
2490         mono_image_unlock (image);
2491 }