merge -r 60814:60815
[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  * (C) 2001-2003 Ximian, Inc.  http://www.ximian.com
10  *
11  */
12 #include <config.h>
13 #include <stdio.h>
14 #include <glib.h>
15 #include <errno.h>
16 #include <time.h>
17 #include <string.h>
18 #include "image.h"
19 #include "cil-coff.h"
20 #include "rawbuffer.h"
21 #include "mono-endian.h"
22 #include "tabledefs.h"
23 #include "tokentype.h"
24 #include "metadata-internals.h"
25 #include "loader.h"
26 #include <mono/io-layer/io-layer.h>
27 #include <mono/utils/mono-logger.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31
32 #define INVALID_ADDRESS 0xffffffff
33
34 /*
35  * Keeps track of the various assemblies loaded
36  */
37 static GHashTable *loaded_images_hash;
38 static GHashTable *loaded_images_guid_hash;
39 static GHashTable *loaded_images_refonly_hash;
40 static GHashTable *loaded_images_refonly_guid_hash;
41
42 static gboolean debug_assembly_unload = FALSE;
43
44 #define mono_images_lock() EnterCriticalSection (&images_mutex)
45 #define mono_images_unlock() LeaveCriticalSection (&images_mutex)
46 static CRITICAL_SECTION images_mutex;
47
48 guint32
49 mono_cli_rva_image_map (MonoCLIImageInfo *iinfo, guint32 addr)
50 {
51         const int top = iinfo->cli_section_count;
52         MonoSectionTable *tables = iinfo->cli_section_tables;
53         int i;
54         
55         for (i = 0; i < top; i++){
56                 if ((addr >= tables->st_virtual_address) &&
57                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
58                         return addr - tables->st_virtual_address + tables->st_raw_data_ptr;
59                 }
60                 tables++;
61         }
62         return INVALID_ADDRESS;
63 }
64
65 char *
66 mono_image_rva_map (MonoImage *image, guint32 addr)
67 {
68         MonoCLIImageInfo *iinfo = image->image_info;
69         const int top = iinfo->cli_section_count;
70         MonoSectionTable *tables = iinfo->cli_section_tables;
71         int i;
72         
73         for (i = 0; i < top; i++){
74                 if ((addr >= tables->st_virtual_address) &&
75                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
76                         if (!iinfo->cli_sections [i]) {
77                                 if (!mono_image_ensure_section_idx (image, i))
78                                         return NULL;
79                         }
80                         return (char*)iinfo->cli_sections [i] +
81                                 (addr - tables->st_virtual_address);
82                 }
83                 tables++;
84         }
85         return NULL;
86 }
87
88 static gchar *
89 canonicalize_path (const char *path)
90 {
91         gchar *abspath, *pos, *lastpos, *dest;
92         int backc;
93
94         if (g_path_is_absolute (path)) {
95                 abspath = g_strdup (path);
96         } else {
97                 gchar *tmpdir = g_get_current_dir ();
98                 abspath = g_build_filename (tmpdir, path, NULL);
99                 g_free (tmpdir);
100         }
101
102         abspath = g_strreverse (abspath);
103
104         backc = 0;
105         dest = lastpos = abspath;
106         pos = strchr (lastpos, G_DIR_SEPARATOR);
107
108         while (pos != NULL) {
109                 int len = pos - lastpos;
110                 if (len == 1 && lastpos [0] == '.') {
111                         // nop
112                 } else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') {
113                         backc++;
114                 } else if (len > 0) {
115                         if (backc > 0) {
116                                 backc--;
117                         } else {
118                                 if (dest != lastpos) 
119                                         /* The two strings can overlap */
120                                         memmove (dest, lastpos, len + 1);
121                                 dest += len + 1;
122                         }
123                 }
124                 lastpos = pos + 1;
125                 pos = strchr (lastpos, G_DIR_SEPARATOR);
126         }
127         
128         if (dest != lastpos) strcpy (dest, lastpos);
129         return g_strreverse (abspath);
130 }
131
132 /**
133  * mono_images_init:
134  *
135  *  Initialize the global variables used by this module.
136  */
137 void
138 mono_images_init (void)
139 {
140         InitializeCriticalSection (&images_mutex);
141
142         loaded_images_hash = g_hash_table_new (g_str_hash, g_str_equal);
143         loaded_images_guid_hash = g_hash_table_new (g_str_hash, g_str_equal);
144         loaded_images_refonly_hash = g_hash_table_new (g_str_hash, g_str_equal);
145         loaded_images_refonly_guid_hash = g_hash_table_new (g_str_hash, g_str_equal);
146
147         debug_assembly_unload = getenv ("MONO_DEBUG_ASSEMBLY_UNLOAD") != NULL;
148 }
149
150 /**
151  * mono_images_cleanup:
152  *
153  *  Free all resources used by this module.
154  */
155 void
156 mono_images_cleanup (void)
157 {
158         DeleteCriticalSection (&images_mutex);
159
160         g_hash_table_destroy (loaded_images_hash);
161         g_hash_table_destroy (loaded_images_guid_hash);
162         g_hash_table_destroy (loaded_images_refonly_hash);
163         g_hash_table_destroy (loaded_images_refonly_guid_hash);
164 }
165
166 /**
167  * mono_image_ensure_section_idx:
168  * @image: The image we are operating on
169  * @section: section number that we will load/map into memory
170  *
171  * This routine makes sure that we have an in-memory copy of
172  * an image section (.text, .rsrc, .data).
173  *
174  * Returns: TRUE on success
175  */
176 int
177 mono_image_ensure_section_idx (MonoImage *image, int section)
178 {
179         MonoCLIImageInfo *iinfo = image->image_info;
180         MonoSectionTable *sect;
181         gboolean writable;
182         
183         g_return_val_if_fail (section < iinfo->cli_section_count, FALSE);
184
185         if (iinfo->cli_sections [section] != NULL)
186                 return TRUE;
187
188         sect = &iinfo->cli_section_tables [section];
189         
190         writable = sect->st_flags & SECT_FLAGS_MEM_WRITE;
191
192         if (sect->st_raw_data_ptr + sect->st_raw_data_size > image->raw_data_len)
193                 return FALSE;
194         /* FIXME: we ignore the writable flag since we don't patch the binary */
195         iinfo->cli_sections [section] = image->raw_data + sect->st_raw_data_ptr;
196         return TRUE;
197 }
198
199 /**
200  * mono_image_ensure_section:
201  * @image: The image we are operating on
202  * @section: section name that we will load/map into memory
203  *
204  * This routine makes sure that we have an in-memory copy of
205  * an image section (.text, .rsrc, .data).
206  *
207  * Returns: TRUE on success
208  */
209 int
210 mono_image_ensure_section (MonoImage *image, const char *section)
211 {
212         MonoCLIImageInfo *ii = image->image_info;
213         int i;
214         
215         for (i = 0; i < ii->cli_section_count; i++){
216                 if (strncmp (ii->cli_section_tables [i].st_name, section, 8) != 0)
217                         continue;
218                 
219                 return mono_image_ensure_section_idx (image, i);
220         }
221         return FALSE;
222 }
223
224 static int
225 load_section_tables (MonoImage *image, MonoCLIImageInfo *iinfo, guint32 offset)
226 {
227         const int top = iinfo->cli_header.coff.coff_sections;
228         int i;
229
230         iinfo->cli_section_count = top;
231         iinfo->cli_section_tables = g_new0 (MonoSectionTable, top);
232         iinfo->cli_sections = g_new0 (void *, top);
233         
234         for (i = 0; i < top; i++){
235                 MonoSectionTable *t = &iinfo->cli_section_tables [i];
236
237                 if (offset + sizeof (MonoSectionTable) > image->raw_data_len)
238                         return FALSE;
239                 memcpy (t, image->raw_data + offset, sizeof (MonoSectionTable));
240                 offset += sizeof (MonoSectionTable);
241
242 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
243                 t->st_virtual_size = GUINT32_FROM_LE (t->st_virtual_size);
244                 t->st_virtual_address = GUINT32_FROM_LE (t->st_virtual_address);
245                 t->st_raw_data_size = GUINT32_FROM_LE (t->st_raw_data_size);
246                 t->st_raw_data_ptr = GUINT32_FROM_LE (t->st_raw_data_ptr);
247                 t->st_reloc_ptr = GUINT32_FROM_LE (t->st_reloc_ptr);
248                 t->st_lineno_ptr = GUINT32_FROM_LE (t->st_lineno_ptr);
249                 t->st_reloc_count = GUINT16_FROM_LE (t->st_reloc_count);
250                 t->st_line_count = GUINT16_FROM_LE (t->st_line_count);
251                 t->st_flags = GUINT32_FROM_LE (t->st_flags);
252 #endif
253                 /* consistency checks here */
254         }
255
256         return TRUE;
257 }
258
259 static gboolean
260 load_cli_header (MonoImage *image, MonoCLIImageInfo *iinfo)
261 {
262         guint32 offset;
263         
264         offset = mono_cli_rva_image_map (iinfo, iinfo->cli_header.datadir.pe_cli_header.rva);
265         if (offset == INVALID_ADDRESS)
266                 return FALSE;
267
268         if (offset + sizeof (MonoCLIHeader) > image->raw_data_len)
269                 return FALSE;
270         memcpy (&iinfo->cli_cli_header, image->raw_data + offset, sizeof (MonoCLIHeader));
271
272 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
273 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
274 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
275 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
276         SWAP32 (iinfo->cli_cli_header.ch_size);
277         SWAP32 (iinfo->cli_cli_header.ch_flags);
278         SWAP32 (iinfo->cli_cli_header.ch_entry_point);
279         SWAP16 (iinfo->cli_cli_header.ch_runtime_major);
280         SWAP16 (iinfo->cli_cli_header.ch_runtime_minor);
281         SWAPPDE (iinfo->cli_cli_header.ch_metadata);
282         SWAPPDE (iinfo->cli_cli_header.ch_resources);
283         SWAPPDE (iinfo->cli_cli_header.ch_strong_name);
284         SWAPPDE (iinfo->cli_cli_header.ch_code_manager_table);
285         SWAPPDE (iinfo->cli_cli_header.ch_vtable_fixups);
286         SWAPPDE (iinfo->cli_cli_header.ch_export_address_table_jumps);
287         SWAPPDE (iinfo->cli_cli_header.ch_eeinfo_table);
288         SWAPPDE (iinfo->cli_cli_header.ch_helper_table);
289         SWAPPDE (iinfo->cli_cli_header.ch_dynamic_info);
290         SWAPPDE (iinfo->cli_cli_header.ch_delay_load_info);
291         SWAPPDE (iinfo->cli_cli_header.ch_module_image);
292         SWAPPDE (iinfo->cli_cli_header.ch_external_fixups);
293         SWAPPDE (iinfo->cli_cli_header.ch_ridmap);
294         SWAPPDE (iinfo->cli_cli_header.ch_debug_map);
295         SWAPPDE (iinfo->cli_cli_header.ch_ip_map);
296 #undef SWAP32
297 #undef SWAP16
298 #undef SWAPPDE
299 #endif
300         /* Catch new uses of the fields that are supposed to be zero */
301
302         if ((iinfo->cli_cli_header.ch_eeinfo_table.rva != 0) ||
303             (iinfo->cli_cli_header.ch_helper_table.rva != 0) ||
304             (iinfo->cli_cli_header.ch_dynamic_info.rva != 0) ||
305             (iinfo->cli_cli_header.ch_delay_load_info.rva != 0) ||
306             (iinfo->cli_cli_header.ch_module_image.rva != 0) ||
307             (iinfo->cli_cli_header.ch_external_fixups.rva != 0) ||
308             (iinfo->cli_cli_header.ch_ridmap.rva != 0) ||
309             (iinfo->cli_cli_header.ch_debug_map.rva != 0) ||
310             (iinfo->cli_cli_header.ch_ip_map.rva != 0)){
311
312                 /*
313                  * No need to scare people who are testing this, I am just
314                  * labelling this as a LAMESPEC
315                  */
316                 /* g_warning ("Some fields in the CLI header which should have been zero are not zero"); */
317
318         }
319             
320         return TRUE;
321 }
322
323 static gboolean
324 load_metadata_ptrs (MonoImage *image, MonoCLIImageInfo *iinfo)
325 {
326         guint32 offset, size;
327         guint16 streams;
328         int i;
329         guint32 pad;
330         char *ptr;
331         
332         offset = mono_cli_rva_image_map (iinfo, iinfo->cli_cli_header.ch_metadata.rva);
333         if (offset == INVALID_ADDRESS)
334                 return FALSE;
335
336         size = iinfo->cli_cli_header.ch_metadata.size;
337
338         if (offset + size > image->raw_data_len)
339                 return FALSE;
340         image->raw_metadata = image->raw_data + offset;
341
342         ptr = image->raw_metadata;
343
344         if (strncmp (ptr, "BSJB", 4) == 0){
345                 guint32 version_string_len;
346
347                 ptr += 4;
348                 image->md_version_major = read16 (ptr);
349                 ptr += 4;
350                 image->md_version_minor = read16 (ptr);
351                 ptr += 4;
352
353                 version_string_len = read32 (ptr);
354                 ptr += 4;
355                 image->version = g_strndup (ptr, version_string_len);
356                 ptr += version_string_len;
357                 pad = ptr - image->raw_metadata;
358                 if (pad % 4)
359                         ptr += 4 - (pad % 4);
360         } else
361                 return FALSE;
362
363         /* skip over flags */
364         ptr += 2;
365         
366         streams = read16 (ptr);
367         ptr += 2;
368
369         for (i = 0; i < streams; i++){
370                 if (strncmp (ptr + 8, "#~", 3) == 0){
371                         image->heap_tables.data = image->raw_metadata + read32 (ptr);
372                         image->heap_tables.size = read32 (ptr + 4);
373                         ptr += 8 + 3;
374                 } else if (strncmp (ptr + 8, "#Strings", 9) == 0){
375                         image->heap_strings.data = image->raw_metadata + read32 (ptr);
376                         image->heap_strings.size = read32 (ptr + 4);
377                         ptr += 8 + 9;
378                 } else if (strncmp (ptr + 8, "#US", 4) == 0){
379                         image->heap_us.data = image->raw_metadata + read32 (ptr);
380                         image->heap_us.size = read32 (ptr + 4);
381                         ptr += 8 + 4;
382                 } else if (strncmp (ptr + 8, "#Blob", 6) == 0){
383                         image->heap_blob.data = image->raw_metadata + read32 (ptr);
384                         image->heap_blob.size = read32 (ptr + 4);
385                         ptr += 8 + 6;
386                 } else if (strncmp (ptr + 8, "#GUID", 6) == 0){
387                         image->heap_guid.data = image->raw_metadata + read32 (ptr);
388                         image->heap_guid.size = read32 (ptr + 4);
389                         ptr += 8 + 6;
390                 } else if (strncmp (ptr + 8, "#-", 3) == 0) {
391                         g_print ("Assembly '%s' has the non-standard metadata heap #-.\nRecompile it correctly (without the /incremental switch or in Release mode).", image->name);
392                         return FALSE;
393                 } else {
394                         g_message ("Unknown heap type: %s\n", ptr + 8);
395                         ptr += 8 + strlen (ptr + 8) + 1;
396                 }
397                 pad = ptr - image->raw_metadata;
398                 if (pad % 4)
399                         ptr += 4 - (pad % 4);
400         }
401
402         g_assert (image->heap_guid.data);
403         g_assert (image->heap_guid.size >= 16);
404
405         image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
406
407         return TRUE;
408 }
409
410 /*
411  * Load representation of logical metadata tables, from the "#~" stream
412  */
413 static gboolean
414 load_tables (MonoImage *image)
415 {
416         const char *heap_tables = image->heap_tables.data;
417         const guint32 *rows;
418         guint64 valid_mask, sorted_mask;
419         int valid = 0, table;
420         int heap_sizes;
421         
422         heap_sizes = heap_tables [6];
423         image->idx_string_wide = ((heap_sizes & 0x01) == 1);
424         image->idx_guid_wide   = ((heap_sizes & 0x02) == 2);
425         image->idx_blob_wide   = ((heap_sizes & 0x04) == 4);
426         
427         valid_mask = read64 (heap_tables + 8);
428         sorted_mask = read64 (heap_tables + 16);
429         rows = (const guint32 *) (heap_tables + 24);
430         
431         for (table = 0; table < 64; table++){
432                 if ((valid_mask & ((guint64) 1 << table)) == 0){
433                         if (table > MONO_TABLE_LAST)
434                                 continue;
435                         image->tables [table].rows = 0;
436                         continue;
437                 }
438                 if (table > MONO_TABLE_LAST) {
439                         g_warning("bits in valid must be zero above 0x2d (II - 23.1.6)");
440                 } else {
441                         image->tables [table].rows = read32 (rows);
442                 }
443                 /*if ((sorted_mask & ((guint64) 1 << table)) == 0){
444                         g_print ("table %s (0x%02x) is sorted\n", mono_meta_table_name (table), table);
445                 }*/
446                 rows++;
447                 valid++;
448         }
449
450         image->tables_base = (heap_tables + 24) + (4 * valid);
451
452         /* They must be the same */
453         g_assert ((const void *) image->tables_base == (const void *) rows);
454
455         mono_metadata_compute_table_bases (image);
456         return TRUE;
457 }
458
459 static gboolean
460 load_metadata (MonoImage *image, MonoCLIImageInfo *iinfo)
461 {
462         if (!load_metadata_ptrs (image, iinfo))
463                 return FALSE;
464
465         return load_tables (image);
466 }
467
468 void
469 mono_image_add_to_name_cache (MonoImage *image, const char *nspace, 
470                                                           const char *name, guint32 index)
471 {
472         GHashTable *nspace_table;
473         GHashTable *name_cache = image->name_cache;
474
475         if (!(nspace_table = g_hash_table_lookup (name_cache, nspace))) {
476                 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
477                 g_hash_table_insert (name_cache, (char *)nspace, (char *)nspace_table);
478         }
479         g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (index));
480 }
481
482 static void
483 load_modules (MonoImage *image, MonoImageOpenStatus *status)
484 {
485         MonoTableInfo *t;
486         int i;
487         char *base_dir;
488         gboolean refonly = image->ref_only;
489
490         if (image->modules)
491                 return;
492
493         t = &image->tables [MONO_TABLE_MODULEREF];
494         image->modules = g_new0 (MonoImage *, t->rows);
495         image->module_count = t->rows;
496         base_dir = g_path_get_dirname (image->name);
497         for (i = 0; i < t->rows; i++){
498                 char *module_ref;
499                 const char *name;
500                 guint32 cols [MONO_MODULEREF_SIZE];
501
502                 mono_metadata_decode_row (t, i, cols, MONO_MODULEREF_SIZE);
503                 name = mono_metadata_string_heap (image, cols [MONO_MODULEREF_NAME]);
504                 module_ref = g_build_filename (base_dir, name, NULL);
505                 image->modules [i] = mono_image_open_full (module_ref, status, refonly);
506                 if (image->modules [i]) {
507                         mono_image_addref (image->modules [i]);
508                         /* g_print ("loaded module %s from %s (%p)\n", module_ref, image->name, image->assembly); */
509                 }
510                 /* 
511                  * FIXME: what do we do here? it could be a native dll...
512                  * We should probably do lazy-loading of modules.
513                  */
514                 if (status)
515                         *status = MONO_IMAGE_OK;
516                 g_free (module_ref);
517         }
518
519         g_free (base_dir);
520 }
521
522 static void
523 load_class_names (MonoImage *image)
524 {
525         MonoTableInfo  *t = &image->tables [MONO_TABLE_TYPEDEF];
526         guint32 cols [MONO_TYPEDEF_SIZE];
527         const char *name;
528         const char *nspace;
529         guint32 i, visib, nspace_index;
530         GHashTable *name_cache2, *nspace_table;
531
532         /* Temporary hash table to avoid lookups in the nspace_table */
533         name_cache2 = g_hash_table_new (NULL, NULL);
534
535         for (i = 1; i <= t->rows; ++i) {
536                 mono_metadata_decode_row (t, i - 1, cols, MONO_TYPEDEF_SIZE);
537                 /* nested types are accessed from the nesting name */
538                 visib = cols [MONO_TYPEDEF_FLAGS] & TYPE_ATTRIBUTE_VISIBILITY_MASK;
539                 if (visib > TYPE_ATTRIBUTE_PUBLIC && visib <= TYPE_ATTRIBUTE_NESTED_ASSEMBLY)
540                         continue;
541                 name = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAME]);
542                 nspace = mono_metadata_string_heap (image, cols [MONO_TYPEDEF_NAMESPACE]);
543
544                 nspace_index = cols [MONO_TYPEDEF_NAMESPACE];
545                 nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
546                 if (!nspace_table) {
547                         nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
548                         g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
549                         g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
550                                                                  nspace_table);
551                 }
552                 g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (i));
553         }
554
555         /* Load type names from EXPORTEDTYPES table */
556         {
557                 MonoTableInfo  *t = &image->tables [MONO_TABLE_EXPORTEDTYPE];
558                 guint32 cols [MONO_EXP_TYPE_SIZE];
559                 int i;
560
561                 for (i = 0; i < t->rows; ++i) {
562                         mono_metadata_decode_row (t, i, cols, MONO_EXP_TYPE_SIZE);
563                         name = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAME]);
564                         nspace = mono_metadata_string_heap (image, cols [MONO_EXP_TYPE_NAMESPACE]);
565
566                         nspace_index = cols [MONO_EXP_TYPE_NAMESPACE];
567                         nspace_table = g_hash_table_lookup (name_cache2, GUINT_TO_POINTER (nspace_index));
568                         if (!nspace_table) {
569                                 nspace_table = g_hash_table_new (g_str_hash, g_str_equal);
570                                 g_hash_table_insert (image->name_cache, (char*)nspace, nspace_table);
571                                 g_hash_table_insert (name_cache2, GUINT_TO_POINTER (nspace_index),
572                                                                          nspace_table);
573                         }
574                         g_hash_table_insert (nspace_table, (char *) name, GUINT_TO_POINTER (mono_metadata_make_token (MONO_TABLE_EXPORTEDTYPE, i + 1)));
575                 }
576         }
577
578         g_hash_table_destroy (name_cache2);
579 }
580
581 static void
582 register_guid (gpointer key, gpointer value, gpointer user_data)
583 {
584         MonoImage *image = (MonoImage*)value;
585
586         if (!g_hash_table_lookup (loaded_images_guid_hash, image))
587                 g_hash_table_insert (loaded_images_guid_hash, image->guid, image);
588 }
589
590 static void
591 build_guid_table (gboolean refonly)
592 {
593         GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
594         g_hash_table_foreach (loaded_images, register_guid, NULL);
595 }
596
597 void
598 mono_image_init (MonoImage *image)
599 {
600         image->mempool = mono_mempool_new ();
601         image->method_cache = g_hash_table_new (NULL, NULL);
602         image->class_cache = g_hash_table_new (NULL, NULL);
603         image->field_cache = g_hash_table_new (NULL, NULL);
604         image->name_cache = g_hash_table_new (g_str_hash, g_str_equal);
605
606         image->delegate_begin_invoke_cache = 
607                 g_hash_table_new ((GHashFunc)mono_signature_hash, 
608                                   (GCompareFunc)mono_metadata_signature_equal);
609         image->delegate_end_invoke_cache = 
610                 g_hash_table_new ((GHashFunc)mono_signature_hash, 
611                                   (GCompareFunc)mono_metadata_signature_equal);
612         image->delegate_invoke_cache = 
613                 g_hash_table_new ((GHashFunc)mono_signature_hash, 
614                                   (GCompareFunc)mono_metadata_signature_equal);
615         image->runtime_invoke_cache  = 
616                 g_hash_table_new ((GHashFunc)mono_signature_hash, 
617                                   (GCompareFunc)mono_metadata_signature_equal);
618         
619         image->managed_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
620         image->native_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
621         image->remoting_invoke_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
622         image->synchronized_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
623         image->unbox_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
624
625         image->ldfld_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
626         image->ldflda_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
627         image->ldfld_remote_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
628         image->stfld_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
629         image->stfld_remote_wrapper_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
630         image->isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
631         image->castclass_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
632         image->proxy_isinst_cache = g_hash_table_new (mono_aligned_addr_hash, NULL);
633
634         image->typespec_cache = g_hash_table_new (NULL, NULL);
635         image->memberref_signatures = g_hash_table_new (NULL, NULL);
636         image->helper_signatures = g_hash_table_new (g_str_hash, g_str_equal);
637         image->method_signatures = g_hash_table_new (NULL, NULL);
638 }
639
640 static MonoImage *
641 do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status,
642                     gboolean care_about_cli)
643 {
644         MonoCLIImageInfo *iinfo;
645         MonoDotNetHeader *header;
646         MonoMSDOSHeader msdos;
647         guint32 offset = 0;
648
649         mono_image_init (image);
650
651         iinfo = image->image_info;
652         header = &iinfo->cli_header;
653                 
654         if (status)
655                 *status = MONO_IMAGE_IMAGE_INVALID;
656
657         if (offset + sizeof (msdos) > image->raw_data_len)
658                 goto invalid_image;
659         memcpy (&msdos, image->raw_data + offset, sizeof (msdos));
660         
661         if (!(msdos.msdos_sig [0] == 'M' && msdos.msdos_sig [1] == 'Z'))
662                 goto invalid_image;
663         
664         msdos.pe_offset = GUINT32_FROM_LE (msdos.pe_offset);
665
666         offset = msdos.pe_offset;
667
668         if (offset + sizeof (MonoDotNetHeader) > image->raw_data_len)
669                 goto invalid_image;
670         memcpy (header, image->raw_data + offset, sizeof (MonoDotNetHeader));
671         offset += sizeof (MonoDotNetHeader);
672
673 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
674 #define SWAP32(x) (x) = GUINT32_FROM_LE ((x))
675 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
676 #define SWAPPDE(x) do { (x).rva = GUINT32_FROM_LE ((x).rva); (x).size = GUINT32_FROM_LE ((x).size);} while (0)
677         SWAP32 (header->coff.coff_time);
678         SWAP32 (header->coff.coff_symptr);
679         SWAP32 (header->coff.coff_symcount);
680         SWAP16 (header->coff.coff_machine);
681         SWAP16 (header->coff.coff_sections);
682         SWAP16 (header->coff.coff_opt_header_size);
683         SWAP16 (header->coff.coff_attributes);
684         /* MonoPEHeader */
685         SWAP32 (header->pe.pe_code_size);
686         SWAP32 (header->pe.pe_data_size);
687         SWAP32 (header->pe.pe_uninit_data_size);
688         SWAP32 (header->pe.pe_rva_entry_point);
689         SWAP32 (header->pe.pe_rva_code_base);
690         SWAP32 (header->pe.pe_rva_data_base);
691         SWAP16 (header->pe.pe_magic);
692
693         /* MonoPEHeaderNT: not used yet */
694         SWAP32  (header->nt.pe_image_base);     /* must be 0x400000 */
695         SWAP32  (header->nt.pe_section_align);       /* must be 8192 */
696         SWAP32  (header->nt.pe_file_alignment);      /* must be 512 or 4096 */
697         SWAP16  (header->nt.pe_os_major);            /* must be 4 */
698         SWAP16  (header->nt.pe_os_minor);            /* must be 0 */
699         SWAP16  (header->nt.pe_user_major);
700         SWAP16  (header->nt.pe_user_minor);
701         SWAP16  (header->nt.pe_subsys_major);
702         SWAP16  (header->nt.pe_subsys_minor);
703         SWAP32  (header->nt.pe_reserved_1);
704         SWAP32  (header->nt.pe_image_size);
705         SWAP32  (header->nt.pe_header_size);
706         SWAP32  (header->nt.pe_checksum);
707         SWAP16  (header->nt.pe_subsys_required);
708         SWAP16  (header->nt.pe_dll_flags);
709         SWAP32  (header->nt.pe_stack_reserve);
710         SWAP32  (header->nt.pe_stack_commit);
711         SWAP32  (header->nt.pe_heap_reserve);
712         SWAP32  (header->nt.pe_heap_commit);
713         SWAP32  (header->nt.pe_loader_flags);
714         SWAP32  (header->nt.pe_data_dir_count);
715
716         /* MonoDotNetHeader: mostly unused */
717         SWAPPDE (header->datadir.pe_export_table);
718         SWAPPDE (header->datadir.pe_import_table);
719         SWAPPDE (header->datadir.pe_resource_table);
720         SWAPPDE (header->datadir.pe_exception_table);
721         SWAPPDE (header->datadir.pe_certificate_table);
722         SWAPPDE (header->datadir.pe_reloc_table);
723         SWAPPDE (header->datadir.pe_debug);
724         SWAPPDE (header->datadir.pe_copyright);
725         SWAPPDE (header->datadir.pe_global_ptr);
726         SWAPPDE (header->datadir.pe_tls_table);
727         SWAPPDE (header->datadir.pe_load_config_table);
728         SWAPPDE (header->datadir.pe_bound_import);
729         SWAPPDE (header->datadir.pe_iat);
730         SWAPPDE (header->datadir.pe_delay_import_desc);
731         SWAPPDE (header->datadir.pe_cli_header);
732         SWAPPDE (header->datadir.pe_reserved);
733
734 #undef SWAP32
735 #undef SWAP16
736 #undef SWAPPDE
737 #endif
738
739         if (header->coff.coff_machine != 0x14c)
740                 goto invalid_image;
741
742         if (header->coff.coff_opt_header_size != (sizeof (MonoDotNetHeader) - sizeof (MonoCOFFHeader) - 4))
743                 goto invalid_image;
744
745         if (header->pesig[0] != 'P' || header->pesig[1] != 'E' || header->pe.pe_magic != 0x10B)
746                 goto invalid_image;
747
748 #if 0
749         /*
750          * The spec says that this field should contain 6.0, but Visual Studio includes a new compiler,
751          * which produces binaries with 7.0.  From Sergey:
752          *
753          * The reason is that MSVC7 uses traditional compile/link
754          * sequence for CIL executables, and VS.NET (and Framework
755          * SDK) includes linker version 7, that puts 7.0 in this
756          * field.  That's why it's currently not possible to load VC
757          * binaries with Mono.  This field is pretty much meaningless
758          * anyway (what linker?).
759          */
760         if (header->pe.pe_major != 6 || header->pe.pe_minor != 0)
761                 goto invalid_image;
762 #endif
763
764         /*
765          * FIXME: byte swap all addresses here for header.
766          */
767         
768         if (!load_section_tables (image, iinfo, offset))
769                 goto invalid_image;
770         
771         if (care_about_cli == FALSE) {
772                 goto done;
773         }
774         
775         /* Load the CLI header */
776         if (!load_cli_header (image, iinfo))
777                 goto invalid_image;
778
779         if (!load_metadata (image, iinfo))
780                 goto invalid_image;
781
782         load_class_names (image);
783
784         /* modules don't have an assembly table row */
785         if (image->tables [MONO_TABLE_ASSEMBLY].rows)
786                 image->assembly_name = mono_metadata_string_heap (image, 
787                         mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY],
788                                         0, MONO_ASSEMBLY_NAME));
789
790         image->module_name = mono_metadata_string_heap (image, 
791                         mono_metadata_decode_row_col (&image->tables [MONO_TABLE_MODULE],
792                                         0, MONO_MODULE_NAME));
793
794         load_modules (image, status);
795
796 done:
797         if (status)
798                 *status = MONO_IMAGE_OK;
799
800         return image;
801
802 invalid_image:
803         mono_image_close (image);
804                 return NULL;
805 }
806
807 static MonoImage *
808 do_mono_image_open (const char *fname, MonoImageOpenStatus *status,
809                     gboolean care_about_cli, gboolean refonly)
810 {
811         MonoCLIImageInfo *iinfo;
812         MonoImage *image;
813         FILE *filed;
814         struct stat stat_buf;
815
816         if ((filed = fopen (fname, "rb")) == NULL){
817                 if (status)
818                         *status = MONO_IMAGE_ERROR_ERRNO;
819                 return NULL;
820         }
821
822         if (fstat (fileno (filed), &stat_buf)) {
823                 fclose (filed);
824                 if (status)
825                         *status = MONO_IMAGE_ERROR_ERRNO;
826                 return NULL;
827         }
828         image = g_new0 (MonoImage, 1);
829         image->file_descr = filed;
830         image->raw_data_len = stat_buf.st_size;
831         image->raw_data = mono_raw_buffer_load (fileno (filed), FALSE, 0, stat_buf.st_size);
832         iinfo = g_new0 (MonoCLIImageInfo, 1);
833         image->image_info = iinfo;
834         image->name = canonicalize_path (fname);
835         image->ref_only = refonly;
836         image->ref_count = 1;
837
838         return do_mono_image_load (image, status, care_about_cli);
839 }
840
841 MonoImage *
842 mono_image_loaded_full (const char *name, gboolean refonly)
843 {
844         MonoImage *res;
845         GHashTable *loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
846         
847         mono_images_lock ();
848         res = g_hash_table_lookup (loaded_images, name);
849         mono_images_unlock ();
850         return res;
851 }
852
853 MonoImage *
854 mono_image_loaded (const char *name)
855 {
856         return mono_image_loaded_full (name, FALSE);
857 }
858
859 MonoImage *
860 mono_image_loaded_by_guid_full (const char *guid, gboolean refonly)
861 {
862         MonoImage *res;
863         GHashTable *loaded_images = refonly ? loaded_images_refonly_guid_hash : loaded_images_guid_hash;
864
865         mono_images_lock ();
866         res = g_hash_table_lookup (loaded_images, guid);
867         mono_images_unlock ();
868         return res;
869 }
870
871 MonoImage *
872 mono_image_loaded_by_guid (const char *guid)
873 {
874         return mono_image_loaded_by_guid_full (guid, FALSE);
875 }
876
877 static MonoImage *
878 register_image (MonoImage *image)
879 {
880         MonoImage *image2;
881         GHashTable *loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash;
882
883         mono_images_lock ();
884         image2 = g_hash_table_lookup (loaded_images, image->name);
885
886         if (image2) {
887                 /* Somebody else beat us to it */
888                 mono_image_addref (image2);
889                 mono_images_unlock ();
890                 mono_image_close (image);
891                 return image2;
892         }
893         g_hash_table_insert (loaded_images, image->name, image);
894         if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == NULL))
895                 g_hash_table_insert (loaded_images, (char *) image->assembly_name, image);      
896         g_hash_table_insert (image->ref_only ? loaded_images_refonly_guid_hash : loaded_images_guid_hash, image->guid, image);
897         mono_images_unlock ();
898
899         return image;
900 }
901
902 MonoImage *
903 mono_image_open_from_data_full (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status, gboolean refonly)
904 {
905         MonoCLIImageInfo *iinfo;
906         MonoImage *image;
907         char *datac;
908
909         if (!data || !data_len) {
910                 if (status)
911                         *status = MONO_IMAGE_IMAGE_INVALID;
912                 return NULL;
913         }
914         datac = data;
915         if (need_copy) {
916                 datac = g_try_malloc (data_len);
917                 if (!datac) {
918                         if (status)
919                                 *status = MONO_IMAGE_ERROR_ERRNO;
920                         return NULL;
921                 }
922                 memcpy (datac, data, data_len);
923         }
924
925         image = g_new0 (MonoImage, 1);
926         image->raw_data = datac;
927         image->raw_data_len = data_len;
928         image->raw_data_allocated = need_copy;
929         image->name = g_strdup_printf ("data-%p", datac);
930         iinfo = g_new0 (MonoCLIImageInfo, 1);
931         image->image_info = iinfo;
932         image->ref_only = refonly;
933
934         image = do_mono_image_load (image, status, TRUE);
935         if (image == NULL)
936                 return NULL;
937
938         return register_image (image);
939 }
940
941 MonoImage *
942 mono_image_open_from_data (char *data, guint32 data_len, gboolean need_copy, MonoImageOpenStatus *status)
943 {
944         return mono_image_open_from_data_full (data, data_len, need_copy, status, FALSE);
945 }
946
947 MonoImage *
948 mono_image_open_full (const char *fname, MonoImageOpenStatus *status, gboolean refonly)
949 {
950         MonoImage *image;
951         GHashTable *loaded_images;
952         char *absfname;
953         
954         g_return_val_if_fail (fname != NULL, NULL);
955         
956         absfname = canonicalize_path (fname);
957
958         /*
959          * The easiest solution would be to do all the loading inside the mutex,
960          * but that would lead to scalability problems. So we let the loading
961          * happen outside the mutex, and if multiple threads happen to load
962          * the same image, we discard all but the first copy.
963          */
964         mono_images_lock ();
965         loaded_images = refonly ? loaded_images_refonly_hash : loaded_images_hash;
966         image = g_hash_table_lookup (loaded_images, absfname);
967         g_free (absfname);
968         
969         if (image){
970                 mono_image_addref (image);
971                 mono_images_unlock ();
972                 return image;
973         }
974         mono_images_unlock ();
975
976         image = do_mono_image_open (fname, status, TRUE, refonly);
977         if (image == NULL)
978                 return NULL;
979
980         return register_image (image);
981 }
982
983 /**
984  * mono_image_open:
985  * @fname: filename that points to the module we want to open
986  * @status: An error condition is returned in this field
987  *
988  * Returns: An open image of type %MonoImage or NULL on error. 
989  * The caller holds a temporary reference to the returned image which should be cleared 
990  * when no longer needed by calling mono_image_close ().
991  * if NULL, then check the value of @status for details on the error
992  */
993 MonoImage *
994 mono_image_open (const char *fname, MonoImageOpenStatus *status)
995 {
996         return mono_image_open_full (fname, status, FALSE);
997 }
998
999 /**
1000  * mono_pe_file_open:
1001  * @fname: filename that points to the module we want to open
1002  * @status: An error condition is returned in this field
1003  *
1004  * Returns: An open image of type %MonoImage or NULL on error.  if
1005  * NULL, then check the value of @status for details on the error.
1006  * This variant for mono_image_open DOES NOT SET UP CLI METADATA.
1007  * It's just a PE file loader, used for FileVersionInfo.  It also does
1008  * not use the image cache.
1009  */
1010 MonoImage *
1011 mono_pe_file_open (const char *fname, MonoImageOpenStatus *status)
1012 {
1013         g_return_val_if_fail (fname != NULL, NULL);
1014         
1015         return(do_mono_image_open (fname, status, FALSE, FALSE));
1016 }
1017
1018 static void
1019 free_hash_table (gpointer key, gpointer val, gpointer user_data)
1020 {
1021         g_hash_table_destroy ((GHashTable*)val);
1022 }
1023
1024 /*
1025 static void
1026 free_mr_signatures (gpointer key, gpointer val, gpointer user_data)
1027 {
1028         mono_metadata_free_method_signature ((MonoMethodSignature*)val);
1029 }
1030 */
1031
1032 static void
1033 free_blob_cache_entry (gpointer key, gpointer val, gpointer user_data)
1034 {
1035         g_free (key);
1036 }
1037
1038 static void
1039 free_remoting_wrappers (gpointer key, gpointer val, gpointer user_data)
1040 {
1041         g_free (val);
1042 }
1043
1044 static void
1045 free_array_cache_entry (gpointer key, gpointer val, gpointer user_data)
1046 {
1047         g_slist_free ((GSList*)val);
1048 }
1049
1050 /**
1051  * mono_image_addref:
1052  * @image: The image file we wish to add a reference to
1053  *
1054  *  Increases the reference count of an image.
1055  */
1056 void
1057 mono_image_addref (MonoImage *image)
1058 {
1059         InterlockedIncrement (&image->ref_count);
1060 }       
1061
1062 void
1063 mono_dynamic_stream_reset (MonoDynamicStream* stream)
1064 {
1065         stream->alloc_size = stream->index = stream->offset = 0;
1066         g_free (stream->data);
1067         stream->data = NULL;
1068         if (stream->hash) {
1069                 g_hash_table_destroy (stream->hash);
1070                 stream->hash = NULL;
1071         }
1072 }
1073
1074 /**
1075  * mono_image_close:
1076  * @image: The image file we wish to close
1077  *
1078  * Closes an image file, deallocates all memory consumed and
1079  * unmaps all possible sections of the file
1080  */
1081 void
1082 mono_image_close (MonoImage *image)
1083 {
1084         MonoImage *image2;
1085         GHashTable *loaded_images, *loaded_images_guid;
1086         int i;
1087
1088         g_return_if_fail (image != NULL);
1089
1090         if (InterlockedDecrement (&image->ref_count) > 0)
1091                 return;
1092
1093         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image);
1094         
1095         mono_images_lock ();
1096         loaded_images = image->ref_only ? loaded_images_refonly_hash : loaded_images_hash;
1097         loaded_images_guid = image->ref_only ? loaded_images_refonly_guid_hash : loaded_images_guid_hash;
1098         image2 = g_hash_table_lookup (loaded_images, image->name);
1099         if (image == image2) {
1100                 /* This is not true if we are called from mono_image_open () */
1101                 g_hash_table_remove (loaded_images, image->name);
1102                 g_hash_table_remove (loaded_images_guid, image->guid);
1103         }
1104         if (image->assembly_name && (g_hash_table_lookup (loaded_images, image->assembly_name) == image))
1105                 g_hash_table_remove (loaded_images, (char *) image->assembly_name);     
1106
1107         /* Multiple images might have the same guid */
1108         build_guid_table (image->ref_only);
1109
1110         mono_images_unlock ();
1111
1112         if (image->file_descr) {
1113                 fclose (image->file_descr);
1114                 image->file_descr = NULL;
1115                 if (image->raw_data != NULL)
1116                         mono_raw_buffer_free (image->raw_data);
1117         }
1118         
1119         if (image->raw_data_allocated) {
1120                 /* image->raw_metadata and cli_sections might lie inside image->raw_data */
1121                 MonoCLIImageInfo *ii = image->image_info;
1122
1123                 if ((image->raw_metadata > image->raw_data) &&
1124                         (image->raw_metadata <= (image->raw_data + image->raw_data_len)))
1125                         image->raw_metadata = NULL;
1126
1127                 for (i = 0; i < ii->cli_section_count; i++)
1128                         if (((char*)(ii->cli_sections [i]) > image->raw_data) &&
1129                                 ((char*)(ii->cli_sections [i]) <= ((char*)image->raw_data + image->raw_data_len)))
1130                                 ii->cli_sections [i] = NULL;
1131
1132                 g_free (image->raw_data);
1133         }
1134
1135         if (debug_assembly_unload) {
1136                 image->name = g_strdup_printf ("%s - UNLOADED", image->name);
1137         } else {
1138                 g_free (image->name);
1139                 g_free (image->guid);
1140                 g_free (image->version);
1141                 g_free (image->files);
1142         }
1143
1144         g_hash_table_destroy (image->method_cache);
1145         g_hash_table_destroy (image->class_cache);
1146         g_hash_table_destroy (image->field_cache);
1147         if (image->array_cache) {
1148                 g_hash_table_foreach (image->array_cache, free_array_cache_entry, NULL);
1149                 g_hash_table_destroy (image->array_cache);
1150         }
1151         if (image->ptr_cache)
1152                 g_hash_table_destroy (image->ptr_cache);
1153         g_hash_table_foreach (image->name_cache, free_hash_table, NULL);
1154         g_hash_table_destroy (image->name_cache);
1155         g_hash_table_destroy (image->native_wrapper_cache);
1156         g_hash_table_destroy (image->managed_wrapper_cache);
1157         g_hash_table_destroy (image->delegate_begin_invoke_cache);
1158         g_hash_table_destroy (image->delegate_end_invoke_cache);
1159         g_hash_table_destroy (image->delegate_invoke_cache);
1160         g_hash_table_foreach (image->remoting_invoke_cache, free_remoting_wrappers, NULL);
1161         g_hash_table_destroy (image->remoting_invoke_cache);
1162         g_hash_table_destroy (image->runtime_invoke_cache);
1163         g_hash_table_destroy (image->synchronized_cache);
1164         g_hash_table_destroy (image->unbox_wrapper_cache);
1165         g_hash_table_destroy (image->typespec_cache);
1166         g_hash_table_destroy (image->ldfld_wrapper_cache);
1167         g_hash_table_destroy (image->ldflda_wrapper_cache);
1168         g_hash_table_destroy (image->ldfld_remote_wrapper_cache);
1169         g_hash_table_destroy (image->stfld_wrapper_cache);
1170         g_hash_table_destroy (image->stfld_remote_wrapper_cache);
1171         g_hash_table_destroy (image->isinst_cache);
1172         g_hash_table_destroy (image->castclass_cache);
1173         g_hash_table_destroy (image->proxy_isinst_cache);
1174
1175         /* The ownership of signatures is not well defined */
1176         //g_hash_table_foreach (image->memberref_signatures, free_mr_signatures, NULL);
1177         g_hash_table_destroy (image->memberref_signatures);
1178         //g_hash_table_foreach (image->helper_signatures, free_mr_signatures, NULL);
1179         g_hash_table_destroy (image->helper_signatures);
1180         g_hash_table_destroy (image->method_signatures);
1181
1182         if (image->interface_bitset) {
1183                 mono_unload_interface_ids (image->interface_bitset);
1184                 mono_bitset_free (image->interface_bitset);
1185         }
1186         if (image->image_info){
1187                 MonoCLIImageInfo *ii = image->image_info;
1188
1189                 if (ii->cli_section_tables)
1190                         g_free (ii->cli_section_tables);
1191                 if (ii->cli_sections)
1192                         g_free (ii->cli_sections);
1193                 g_free (image->image_info);
1194         }
1195
1196         for (i = 0; i < image->module_count; ++i) {
1197                 if (image->modules [i])
1198                         mono_image_close (image->modules [i]);
1199         }
1200         if (image->modules)
1201                 g_free (image->modules);
1202         if (image->references)
1203                 g_free (image->references);
1204         /*g_print ("destroy image %p (dynamic: %d)\n", image, image->dynamic);*/
1205         if (!image->dynamic) {
1206                 if (debug_assembly_unload)
1207                         mono_mempool_invalidate (image->mempool);
1208                 else {
1209                         mono_mempool_destroy (image->mempool);
1210                         g_free (image);
1211                 }
1212         } else {
1213                 /* Dynamic images are GC_MALLOCed */
1214                 struct _MonoDynamicImage *di = (struct _MonoDynamicImage*)image;
1215                 int i;
1216                 g_free ((char*)image->module_name);
1217                 if (di->typespec)
1218                         g_hash_table_destroy (di->typespec);
1219                 if (di->typeref)
1220                         g_hash_table_destroy (di->typeref);
1221                 if (di->handleref)
1222                         g_hash_table_destroy (di->handleref);
1223                 if (di->tokens)
1224                         mono_g_hash_table_destroy (di->tokens);
1225                 if (di->blob_cache) {
1226                         g_hash_table_foreach (di->blob_cache, free_blob_cache_entry, NULL);
1227                         g_hash_table_destroy (di->blob_cache);
1228                 }
1229                 g_list_free (di->array_methods);
1230                 if (di->gen_params)
1231                         g_ptr_array_free (di->gen_params, TRUE);
1232                 if (di->token_fixups)
1233                         mono_g_hash_table_destroy (di->token_fixups);
1234                 if (di->method_to_table_idx)
1235                         g_hash_table_destroy (di->method_to_table_idx);
1236                 if (di->field_to_table_idx)
1237                         g_hash_table_destroy (di->field_to_table_idx);
1238                 if (di->method_aux_hash)
1239                         g_hash_table_destroy (di->method_aux_hash);
1240                 g_free (di->strong_name);
1241                 g_free (di->win32_res);
1242                 /*g_print ("string heap destroy for image %p\n", di);*/
1243                 mono_dynamic_stream_reset (&di->sheap);
1244                 mono_dynamic_stream_reset (&di->code);
1245                 mono_dynamic_stream_reset (&di->resources);
1246                 mono_dynamic_stream_reset (&di->us);
1247                 mono_dynamic_stream_reset (&di->blob);
1248                 mono_dynamic_stream_reset (&di->tstream);
1249                 mono_dynamic_stream_reset (&di->guid);
1250                 for (i = 0; i < MONO_TABLE_NUM; ++i) {
1251                         g_free (di->tables [i].values);
1252                 }
1253                 mono_mempool_destroy (image->mempool);
1254         }
1255 }
1256
1257 /** 
1258  * mono_image_strerror:
1259  * @status: an code indicating the result from a recent operation
1260  *
1261  * Returns: a string describing the error
1262  */
1263 const char *
1264 mono_image_strerror (MonoImageOpenStatus status)
1265 {
1266         switch (status){
1267         case MONO_IMAGE_OK:
1268                 return "success";
1269         case MONO_IMAGE_ERROR_ERRNO:
1270                 return strerror (errno);
1271         case MONO_IMAGE_IMAGE_INVALID:
1272                 return "File does not contain a valid CIL image";
1273         case MONO_IMAGE_MISSING_ASSEMBLYREF:
1274                 return "An assembly was referenced, but could not be found";
1275         }
1276         return "Internal error";
1277 }
1278
1279 static gpointer
1280 mono_image_walk_resource_tree (MonoCLIImageInfo *info, guint32 res_id,
1281                                guint32 lang_id, gunichar2 *name,
1282                                MonoPEResourceDirEntry *entry,
1283                                MonoPEResourceDir *root, guint32 level)
1284 {
1285         gboolean is_string=entry->name_is_string;
1286
1287         /* Level 0 holds a directory entry for each type of resource
1288          * (identified by ID or name).
1289          *
1290          * Level 1 holds a directory entry for each named resource
1291          * item, and each "anonymous" item of a particular type of
1292          * resource.
1293          *
1294          * Level 2 holds a directory entry for each language pointing to
1295          * the actual data.
1296          */
1297
1298         if(level==0) {
1299                 if((is_string==FALSE && entry->name_offset!=res_id) ||
1300                    (is_string==TRUE)) {
1301                         return(NULL);
1302                 }
1303         } else if (level==1) {
1304 #if 0
1305                 if(name!=NULL &&
1306                    is_string==TRUE && name!=lookup (entry->name_offset)) {
1307                         return(NULL);
1308                 }
1309 #endif
1310         } else if (level==2) {
1311                 if ((is_string == FALSE &&
1312                     entry->name_offset != lang_id &&
1313                     lang_id != 0) ||
1314                    (is_string == TRUE)) {
1315                         return(NULL);
1316                 }
1317         } else {
1318                 g_assert_not_reached ();
1319         }
1320
1321         if(entry->is_dir==TRUE) {
1322                 MonoPEResourceDir *res_dir=(MonoPEResourceDir *)(((char *)root)+entry->dir_offset);
1323                 MonoPEResourceDirEntry *sub_entries=(MonoPEResourceDirEntry *)(res_dir+1);
1324                 guint32 entries, i;
1325                 
1326                 entries=res_dir->res_named_entries + res_dir->res_id_entries;
1327
1328                 for(i=0; i<entries; i++) {
1329                         MonoPEResourceDirEntry *sub_entry=&sub_entries[i];
1330                         gpointer ret;
1331                         
1332                         ret=mono_image_walk_resource_tree (info, res_id,
1333                                                            lang_id, name,
1334                                                            sub_entry, root,
1335                                                            level+1);
1336                         if(ret!=NULL) {
1337                                 return(ret);
1338                         }
1339                 }
1340
1341                 return(NULL);
1342         } else {
1343                 MonoPEResourceDataEntry *data_entry=(MonoPEResourceDataEntry *)((char *)(root)+entry->dir_offset);
1344                 
1345                 return(data_entry);
1346         }
1347 }
1348
1349 /**
1350  * mono_image_lookup_resource:
1351  * @image: the image to look up the resource in
1352  * @res_id: A MONO_PE_RESOURCE_ID_ that represents the resource ID to lookup.
1353  * @lang_id: The language id.
1354  * @name: the resource name to lookup.
1355  *
1356  * Returns: NULL if not found, otherwise a pointer to the in-memory representation
1357  * of the given resource.
1358  */
1359 gpointer
1360 mono_image_lookup_resource (MonoImage *image, guint32 res_id, guint32 lang_id, gunichar2 *name)
1361 {
1362         MonoCLIImageInfo *info;
1363         MonoDotNetHeader *header;
1364         MonoPEDatadir *datadir;
1365         MonoPEDirEntry *rsrc;
1366         MonoPEResourceDir *resource_dir;
1367         MonoPEResourceDirEntry *res_entries;
1368         guint32 entries, i;
1369
1370         if(image==NULL) {
1371                 return(NULL);
1372         }
1373
1374         info=image->image_info;
1375         if(info==NULL) {
1376                 return(NULL);
1377         }
1378
1379         header=&info->cli_header;
1380         if(header==NULL) {
1381                 return(NULL);
1382         }
1383
1384         datadir=&header->datadir;
1385         if(datadir==NULL) {
1386                 return(NULL);
1387         }
1388
1389         rsrc=&datadir->pe_resource_table;
1390         if(rsrc==NULL) {
1391                 return(NULL);
1392         }
1393
1394         resource_dir=(MonoPEResourceDir *)mono_image_rva_map (image, rsrc->rva);
1395         if(resource_dir==NULL) {
1396                 return(NULL);
1397         }
1398         
1399         entries=resource_dir->res_named_entries + resource_dir->res_id_entries;
1400         res_entries=(MonoPEResourceDirEntry *)(resource_dir+1);
1401         
1402         for(i=0; i<entries; i++) {
1403                 MonoPEResourceDirEntry *entry=&res_entries[i];
1404                 gpointer ret;
1405                 
1406                 ret=mono_image_walk_resource_tree (info, res_id, lang_id,
1407                                                    name, entry, resource_dir,
1408                                                    0);
1409                 if(ret!=NULL) {
1410                         return(ret);
1411                 }
1412         }
1413
1414         return(NULL);
1415 }
1416
1417 /** 
1418  * mono_image_get_entry_point:
1419  * @image: the image where the entry point will be looked up.
1420  *
1421  * Use this routine to determine the metadata token for method that
1422  * has been flagged as the entry point.
1423  *
1424  * Returns: the token for the entry point method in the image
1425  */
1426 guint32
1427 mono_image_get_entry_point (MonoImage *image)
1428 {
1429         return ((MonoCLIImageInfo*)image->image_info)->cli_cli_header.ch_entry_point;
1430 }
1431
1432 /**
1433  * mono_image_get_resource:
1434  * @image: the image where the resource will be looked up.
1435  * @offset: The offset to add to the resource
1436  * @size: a pointer to an int where the size of the resource will be stored
1437  *
1438  * This is a low-level routine that fetches a resource from the
1439  * metadata that starts at a given @offset.  The @size parameter is
1440  * filled with the data field as encoded in the metadata.
1441  *
1442  * Returns: the pointer to the resource whose offset is @offset.
1443  */
1444 const char*
1445 mono_image_get_resource (MonoImage *image, guint32 offset, guint32 *size)
1446 {
1447         MonoCLIImageInfo *iinfo = image->image_info;
1448         MonoCLIHeader *ch = &iinfo->cli_cli_header;
1449         const char* data;
1450
1451         if (!ch->ch_resources.rva || offset + 4 > ch->ch_resources.size)
1452                 return NULL;
1453         
1454         data = mono_image_rva_map (image, ch->ch_resources.rva);
1455         if (!data)
1456                 return NULL;
1457         data += offset;
1458         if (size)
1459                 *size = read32 (data);
1460         data += 4;
1461         return data;
1462 }
1463
1464 MonoImage*
1465 mono_image_load_file_for_image (MonoImage *image, int fileidx)
1466 {
1467         char *base_dir, *name;
1468         MonoImage *res;
1469         MonoTableInfo  *t = &image->tables [MONO_TABLE_FILE];
1470         const char *fname;
1471         guint32 fname_id;
1472
1473         if (fileidx < 1 || fileidx > t->rows)
1474                 return NULL;
1475
1476         if (image->files && image->files [fileidx - 1])
1477                 return image->files [fileidx - 1];
1478
1479         if (!image->files)
1480                 image->files = g_new0 (MonoImage*, t->rows);
1481
1482         fname_id = mono_metadata_decode_row_col (t, fileidx - 1, MONO_FILE_NAME);
1483         fname = mono_metadata_string_heap (image, fname_id);
1484         base_dir = g_path_get_dirname (image->name);
1485         name = g_build_filename (base_dir, fname, NULL);
1486         res = mono_image_open (name, NULL);
1487         if (res) {
1488                 int i;
1489                 /* g_print ("loaded file %s from %s (%p)\n", name, image->name, image->assembly); */
1490                 res->assembly = image->assembly;
1491                 for (i = 0; i < res->module_count; ++i) {
1492                         if (res->modules [i] && !res->modules [i]->assembly)
1493                                 res->modules [i]->assembly = image->assembly;
1494                 }
1495
1496                 image->files [fileidx - 1] = res;
1497         }
1498         g_free (name);
1499         g_free (base_dir);
1500         return res;
1501 }
1502
1503 const char*
1504 mono_image_get_strong_name (MonoImage *image, guint32 *size)
1505 {
1506         MonoCLIImageInfo *iinfo = image->image_info;
1507         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
1508         const char* data;
1509
1510         if (!de->size || !de->rva)
1511                 return NULL;
1512         data = mono_image_rva_map (image, de->rva);
1513         if (!data)
1514                 return NULL;
1515         if (size)
1516                 *size = de->size;
1517         return data;
1518 }
1519
1520 guint32
1521 mono_image_strong_name_position (MonoImage *image, guint32 *size)
1522 {
1523         MonoCLIImageInfo *iinfo = image->image_info;
1524         MonoPEDirEntry *de = &iinfo->cli_cli_header.ch_strong_name;
1525         const int top = iinfo->cli_section_count;
1526         MonoSectionTable *tables = iinfo->cli_section_tables;
1527         int i;
1528         guint32 addr = de->rva;
1529         
1530         if (size)
1531                 *size = de->size;
1532         if (!de->size || !de->rva)
1533                 return 0;
1534         for (i = 0; i < top; i++){
1535                 if ((addr >= tables->st_virtual_address) &&
1536                     (addr < tables->st_virtual_address + tables->st_raw_data_size)){
1537                         return tables->st_raw_data_ptr +
1538                                 (addr - tables->st_virtual_address);
1539                 }
1540                 tables++;
1541         }
1542
1543         return 0;
1544 }
1545
1546 const char*
1547 mono_image_get_public_key (MonoImage *image, guint32 *size)
1548 {
1549         const char *pubkey;
1550         guint32 len, tok;
1551         if (image->tables [MONO_TABLE_ASSEMBLY].rows != 1)
1552                 return NULL;
1553         tok = mono_metadata_decode_row_col (&image->tables [MONO_TABLE_ASSEMBLY], 0, MONO_ASSEMBLY_PUBLIC_KEY);
1554         if (!tok)
1555                 return NULL;
1556         pubkey = mono_metadata_blob_heap (image, tok);
1557         len = mono_metadata_decode_blob_size (pubkey, &pubkey);
1558         if (size)
1559                 *size = len;
1560         return pubkey;
1561 }
1562
1563 const char*
1564 mono_image_get_name (MonoImage *image)
1565 {
1566         return image->assembly_name;
1567 }
1568
1569 const char*
1570 mono_image_get_filename (MonoImage *image)
1571 {
1572         return image->name;
1573 }
1574
1575 const char*
1576 mono_image_get_guid (MonoImage *image)
1577 {
1578         return image->guid;
1579 }
1580
1581 const MonoTableInfo*
1582 mono_image_get_table_info (MonoImage *image, int table_id)
1583 {
1584         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
1585                 return NULL;
1586         return &image->tables [table_id];
1587 }
1588
1589 int
1590 mono_image_get_table_rows (MonoImage *image, int table_id)
1591 {
1592         if (table_id < 0 || table_id >= MONO_TABLE_NUM)
1593                 return 0;
1594         return image->tables [table_id].rows;
1595 }
1596
1597 int
1598 mono_table_info_get_rows (const MonoTableInfo *table)
1599 {
1600         return table->rows;
1601 }
1602
1603 MonoAssembly* 
1604 mono_image_get_assembly (MonoImage *image)
1605 {
1606         return image->assembly;
1607 }
1608
1609 gboolean
1610 mono_image_is_dynamic (MonoImage *image)
1611 {
1612         return image->dynamic;
1613 }
1614
1615 gboolean
1616 mono_image_has_authenticode_entry (MonoImage *image)
1617 {
1618         MonoCLIImageInfo *iinfo = image->image_info;
1619         MonoDotNetHeader *header = &iinfo->cli_header;
1620         MonoPEDirEntry *de = &header->datadir.pe_certificate_table;
1621         // the Authenticode "pre" (non ASN.1) header is 8 bytes long
1622         return ((de->rva != 0) && (de->size > 8));
1623 }