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