2002-09-25 Martin Baulig <martin@gnome.org>
[mono.git] / mono / metadata / debug-mono-symfile.c
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/rawbuffer.h>
8 #include <mono/metadata/tokentype.h>
9 #include <mono/metadata/appdomain.h>
10 #include <mono/metadata/exception.h>
11 #include <mono/metadata/debug-helpers.h>
12 #include <mono/metadata/debug-mono-symfile.h>
13
14 #include <fcntl.h>
15 #include <unistd.h>
16
17 #define RANGE_TABLE_CHUNK_SIZE  256
18 #define TYPE_TABLE_CHUNK_SIZE   256
19
20 struct MonoSymbolFilePriv
21 {
22         int fd;
23         int error;
24         char *file_name;
25         char *source_file;
26         guint32 string_table_size;
27         guint32 string_offset_size;
28         MonoImage *image;
29         GHashTable *method_table;
30         GHashTable *method_hash;
31         MonoSymbolFileOffsetTable *offset_table;
32 };
33
34 typedef struct
35 {
36         MonoMethod *method;
37         MonoDebugMethodInfo *minfo;
38         MonoSymbolFileMethodEntry *entry;
39         guint32 method_name_offset;
40         guint32 index;
41         gchar *name;
42 } MonoSymbolFileMethodEntryPriv;
43
44 static GHashTable *type_table;
45
46 static int write_string_table (MonoSymbolFile *symfile);
47 static int create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings);
48 static void close_symfile (MonoSymbolFile *symfile);
49 static MonoDebugRangeInfo *allocate_range_entry (MonoSymbolFile *symfile);
50 static MonoDebugTypeInfo *allocate_type_entry (MonoSymbolFile *symfile);
51 static gpointer write_type (MonoType *type);
52
53 static void
54 free_method_info (MonoDebugMethodInfo *minfo)
55 {
56         g_free (minfo->jit);
57         g_free (minfo);
58 }
59
60 static int
61 load_symfile (MonoSymbolFile *symfile)
62 {
63         MonoSymbolFilePriv *priv = symfile->_priv;
64         MonoSymbolFileMethodEntry *me;
65         const char *ptr, *start;
66         guint64 magic;
67         long version;
68         int i;
69
70         ptr = start = symfile->raw_contents;
71
72         magic = *((guint64 *) ptr)++;
73         if (magic != MONO_SYMBOL_FILE_MAGIC) {
74                 g_warning ("Symbol file %s has is not a mono symbol file", priv->file_name);
75                 return FALSE;
76         }
77
78         version = *((guint32 *) ptr)++;
79         if (version != MONO_SYMBOL_FILE_VERSION) {
80                 g_warning ("Symbol file %s has incorrect line number table version "
81                            "(expected %d, got %ld)", priv->file_name,
82                            MONO_SYMBOL_FILE_VERSION, version);
83                 return FALSE;
84         }
85
86         priv->offset_table = (MonoSymbolFileOffsetTable *) ptr;
87
88         /*
89          * Read method table.
90          *
91          */
92
93         priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
94                                                     (GDestroyNotify) g_free);
95         priv->method_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
96                                                    (GDestroyNotify) free_method_info);
97
98         ptr = symfile->raw_contents + priv->offset_table->method_table_offset;
99         me = (MonoSymbolFileMethodEntry *) ptr;
100
101         for (i = 0; i < priv->offset_table->method_count; i++, me++) {
102                 MonoMethod *method = mono_get_method (priv->image, me->token, NULL);
103                 MonoSymbolFileMethodEntryPriv *mep;
104                 MonoDebugMethodInfo *minfo;
105
106                 if (!method)
107                         continue;
108
109                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
110                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
111                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
112                         g_assert_not_reached ();
113
114                 if (!((MonoMethodNormal *) method)->header) {
115                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
116                                    method->klass->name, method->name);
117                         continue;
118                 }
119
120                 minfo = g_new0 (MonoDebugMethodInfo, 1);
121                 minfo->file_offset = ((const char *) me) - start;
122                 minfo->method = method;
123                 minfo->symfile = symfile;
124                 minfo->num_il_offsets = me->num_line_numbers;
125                 minfo->il_offsets = (MonoSymbolFileLineNumberEntry *)
126                         (symfile->raw_contents + me->line_number_table_offset);
127
128                 mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
129                 mep->method = method;
130                 mep->minfo = minfo;
131                 mep->entry = me;
132                 mep->index = i;
133
134                 mep->method_name_offset = priv->string_table_size;
135                 mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
136                                              method->klass->name, method->name);
137                 priv->string_table_size += strlen (mep->name) + 1;
138
139                 g_hash_table_insert (priv->method_table, method, mep);
140                 g_hash_table_insert (priv->method_hash, method, minfo);
141         }
142
143         if (!write_string_table (symfile))
144                 return FALSE;
145
146         return TRUE;
147 }
148
149 MonoSymbolFile *
150 mono_debug_open_mono_symbol_file (MonoImage *image, const char *filename, gboolean emit_warnings)
151 {
152         MonoSymbolFile *symfile;
153         MonoSymbolFilePriv *priv;
154         off_t file_size;
155         void *ptr;
156         int fd;
157
158         fd = open (filename, O_RDONLY);
159         if (fd == -1) {
160                 if (emit_warnings)
161                         g_warning ("Can't open symbol file: %s", filename);
162                 return NULL;
163         }
164
165         file_size = lseek (fd, 0, SEEK_END);
166         lseek (fd, 0, SEEK_SET);
167
168         if (file_size == (off_t) -1) {
169                 if (emit_warnings)
170                         g_warning ("Can't get size of symbol file: %s", filename);
171                 return NULL;
172         }
173
174         ptr = mono_raw_buffer_load (fd, FALSE, 0, file_size);
175         if (!ptr) {
176                 if (emit_warnings)
177                         g_warning ("Can't read symbol file: %s", filename);
178                 return NULL;
179         }
180
181         symfile = g_new0 (MonoSymbolFile, 1);
182         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
183         symfile->version = MONO_SYMBOL_FILE_VERSION;
184         symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
185         symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
186         symfile->image_file = g_strdup (image->name);
187         symfile->symbol_file = g_strdup (filename);
188         symfile->raw_contents = ptr;
189         symfile->raw_contents_size = file_size;
190
191         symfile->_priv = priv = g_new0 (MonoSymbolFilePriv, 1);
192
193         priv->fd = fd;
194         priv->image = image;
195         priv->file_name = g_strdup (filename);
196
197         if (!load_symfile (symfile)) {
198                 mono_debug_close_mono_symbol_file (symfile);
199                 return NULL;
200         }
201
202         return symfile;
203 }
204
205 static void
206 close_symfile (MonoSymbolFile *symfile)
207 {
208         MonoSymbolFilePriv *priv = symfile->_priv;
209
210         if (symfile->raw_contents) {
211                 mono_raw_buffer_free (symfile->raw_contents);
212                 symfile->raw_contents = NULL;
213         }
214
215         if (priv->fd) {
216                 close (priv->fd);
217                 priv->fd = 0;
218         }
219
220         if (priv->method_table) {
221                 g_hash_table_destroy (priv->method_table);
222                 priv->method_table = NULL;
223         }
224
225         if (symfile->is_dynamic) {
226                 unlink (priv->file_name);
227                 priv->method_hash = NULL;
228         } else if (priv->method_hash) {
229                 g_hash_table_destroy (priv->method_hash);
230                 priv->method_hash = NULL;
231         }
232
233         if (symfile->image_file) {
234                 g_free (symfile->image_file);
235                 symfile->image_file = NULL;
236         }
237
238         if (priv->file_name) {
239                 g_free (priv->file_name);
240                 priv->file_name = NULL;
241         }
242
243         priv->error = FALSE;
244 }
245
246 void
247 mono_debug_close_mono_symbol_file (MonoSymbolFile *symfile)
248 {
249         if (!symfile)
250                 return;
251
252         close_symfile (symfile);
253
254         g_free (symfile->_priv->source_file);
255         g_free (symfile->_priv);
256         g_free (symfile->image_file);
257         g_free (symfile->symbol_file);
258         g_free (symfile);
259 }
260
261 static int
262 write_string (int fd, const char *string)
263 {
264         guint32 length = strlen (string);
265
266         if (write (fd, &length, sizeof (length)) < 0)
267                 return FALSE;
268
269         if (write (fd, string, strlen (string)) < 0)
270                 return FALSE;
271
272         return TRUE;
273 }
274
275 static gchar *
276 read_string (const char *ptr)
277 {
278         int len = *((guint32 *) ptr)++;
279
280         return g_filename_from_utf8 (ptr, len, NULL, NULL, NULL);
281 }
282
283 gchar *
284 mono_debug_find_source_location (MonoSymbolFile *symfile, MonoMethod *method, guint32 offset,
285                                  guint32 *line_number)
286 {
287         MonoSymbolFilePriv *priv = symfile->_priv;
288         MonoSymbolFileLineNumberEntry *lne;
289         MonoSymbolFileMethodEntryPriv *mep;
290         gchar *source_file = NULL;
291         const char *ptr;
292         int i;
293
294         if (!priv->method_table || symfile->is_dynamic)
295                 return NULL;
296
297         mep = g_hash_table_lookup (priv->method_table, method);
298         if (!mep)
299                 return NULL;
300
301         if (mep->entry->source_file_offset)
302                 source_file = read_string (symfile->raw_contents + mep->entry->source_file_offset);
303
304         ptr = symfile->raw_contents + mep->entry->line_number_table_offset;
305
306         lne = (MonoSymbolFileLineNumberEntry *) ptr;
307
308         for (i = 0; i < mep->entry->num_line_numbers; i++, lne++) {
309                 if (lne->offset < offset)
310                         continue;
311
312                 if (line_number) {
313                         *line_number = lne->row;
314                         if (source_file)
315                                 return source_file;
316                         else
317                                 return NULL;
318                 } else if (source_file) {
319                         gchar *retval = g_strdup_printf ("%s:%d", source_file, lne->row);
320                         g_free (source_file);
321                         return retval;
322                 } else
323                         return g_strdup_printf ("%d", lne->row);
324         }
325
326         return NULL;
327 }
328
329 void
330 mono_debug_symfile_add_method (MonoSymbolFile *symfile, MonoMethod *method)
331 {
332         MonoSymbolFileMethodEntryPriv *mep;
333         MonoSymbolFileMethodAddress *address;
334         MonoDebugVarInfo *var_table;
335         MonoDebugRangeInfo *range;
336         guint32 size, num_variables, variable_size, variable_offset;
337         guint32 type_size, type_offset, *type_index_table;
338         gpointer *type_table;
339         guint8 *ptr;
340         int i;
341
342         mep = g_hash_table_lookup (symfile->_priv->method_table, method);
343         if (!mep)
344                 return;
345
346         if (!mep->minfo) {
347                 mep->minfo = g_hash_table_lookup (symfile->_priv->method_hash, mep->method);
348                 if (!mep->minfo)
349                         return;
350         }
351
352         if (!mep->minfo->jit)
353                 return;
354
355         symfile->generation++;
356
357         size = sizeof (MonoSymbolFileMethodAddress);
358
359         num_variables = mep->entry->num_parameters + mep->entry->num_locals;
360         if (mep->entry->this_type_index)
361                 num_variables++;
362
363         variable_size = num_variables * sizeof (MonoDebugVarInfo);
364         variable_offset = size;
365         size += variable_size;
366
367         type_size = num_variables * sizeof (gpointer);
368         type_offset = size;
369         size += type_size;
370
371         address = g_malloc0 (size);
372         ptr = (guint8 *) address;
373
374         address->size = size;
375         address->start_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start);
376         address->end_address = GPOINTER_TO_UINT (mep->minfo->jit->code_start + mep->minfo->jit->code_size);
377         address->variable_table_offset = variable_offset;
378         address->type_table_offset = type_offset;
379
380         if (mep->minfo->jit->line_numbers) {
381                 address->num_line_numbers = mep->minfo->jit->line_numbers->len;
382                 address->line_numbers = (MonoDebugLineNumberEntry *) mep->minfo->jit->line_numbers->data;
383                 address->line_number_size = address->num_line_numbers * sizeof (MonoDebugLineNumberEntry);
384         }
385
386         range = allocate_range_entry (symfile);
387         range->file_offset = mep->minfo->file_offset;
388         range->start_address = address->start_address;
389         range->end_address = address->end_address;
390         range->dynamic_data = address;
391         range->dynamic_size = size;
392
393         var_table = (MonoDebugVarInfo *) (ptr + variable_offset);
394         type_table = (gpointer *) (ptr + type_offset);
395
396         type_index_table = (guint32 *)
397                 (symfile->raw_contents + mep->entry->type_index_table_offset);
398
399         if (mep->entry->this_type_index) {
400                 if (!mep->minfo->jit->this_var) {
401                         g_warning (G_STRLOC ": Method %s.%s doesn't have `this'.",
402                                    mep->method->klass->name, mep->method->name);
403                         var_table++;
404                 } else {
405                         *var_table++ = *mep->minfo->jit->this_var;
406                         *type_table++ = write_type (&method->klass->this_arg);
407                 }
408         }
409
410         if (mep->minfo->jit->num_params != mep->entry->num_parameters) {
411                 g_warning (G_STRLOC ": Method %s.%s has %d parameters, but symbol file claims it has %d.",
412                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_params,
413                            mep->entry->num_parameters);
414                 var_table += mep->entry->num_parameters;
415         } else {
416                 for (i = 0; i < mep->minfo->jit->num_params; i++) {
417                         *var_table++ = mep->minfo->jit->params [i];
418                         *type_table++ = write_type (method->signature->params [i]);
419                 }
420         }
421
422         if (mep->minfo->jit->num_locals != mep->entry->num_locals) {
423 #if 0
424                 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
425                            mep->method->klass->name, mep->method->name, mep->minfo->jit->num_locals,
426                            mep->entry->num_locals);
427 #endif
428                 var_table += mep->entry->num_locals;
429         } else
430                 for (i = 0; i < mep->minfo->jit->num_locals; i++)
431                         *var_table++ = mep->minfo->jit->locals [i];
432 }
433
434 void
435 mono_debug_symfile_add_type (MonoSymbolFile *symfile, MonoClass *klass)
436 {
437         MonoDebugTypeInfo *info = allocate_type_entry (symfile);
438
439         info->klass = klass;
440         if (klass->rank) {
441                 info->token = klass->element_class->type_token;
442                 info->rank = klass->rank;
443         } else
444                 info->token = klass->type_token;
445         info->type_info = write_type (&klass->this_arg);
446 }
447
448 static void
449 free_method_entry (MonoSymbolFileMethodEntryPriv *mep)
450 {
451         g_free (mep->name);
452         g_free (mep->entry);
453         g_free (mep);
454 }
455
456 static void
457 create_method (MonoSymbolFile *symfile, guint32 token, MonoMethod *method)
458 {
459         MonoSymbolFileMethodEntryPriv *mep;
460         MonoDebugMethodInfo *minfo;
461
462         g_assert (method->klass->image == symfile->_priv->image);
463
464         mep = g_new0 (MonoSymbolFileMethodEntryPriv, 1);
465         mep->entry = g_new0 (MonoSymbolFileMethodEntry, 1);
466         mep->entry->token = token;
467         mep->entry->source_file_offset = symfile->_priv->offset_table->source_table_offset;
468
469         mep->method_name_offset = symfile->_priv->string_table_size;
470         mep->name = g_strdup_printf ("%s%s.%s", method->klass->name_space,
471                                      method->klass->name, method->name);
472         symfile->_priv->string_table_size += strlen (mep->name) + 1;
473
474         minfo = g_hash_table_lookup (symfile->_priv->method_hash, method);
475         g_assert (minfo && (minfo->method == method));
476         minfo->symfile = symfile;
477
478         mep->minfo = minfo;
479         mep->method = method;
480
481         symfile->_priv->offset_table->method_count++;
482
483         g_hash_table_insert (symfile->_priv->method_table, method, mep);
484 }
485
486 static void
487 write_method (gpointer key, gpointer value, gpointer user_data)
488 {
489         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
490         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
491
492         if (symfile->_priv->error)
493                 return;
494
495         mep->minfo->file_offset = lseek (symfile->_priv->fd, 0, SEEK_CUR);
496
497         if (write (symfile->_priv->fd, mep->entry, sizeof (MonoSymbolFileMethodEntry)) < 0) {
498                 symfile->_priv->error = TRUE;
499                 return;
500         }
501 }
502
503 static void
504 create_methods (MonoSymbolFile *symfile)
505 {
506         MonoImage *image = symfile->_priv->image;
507         MonoTableInfo *table = &image->tables [MONO_TABLE_METHOD];
508         int idx;
509
510         for (idx = 1; idx <= table->rows; idx++) {
511                 guint32 token = mono_metadata_make_token (MONO_TABLE_METHOD, idx);
512                 MonoMethod *method = mono_get_method (image, token, NULL);
513
514                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
515                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
516                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
517                         continue;
518
519                 if (method->wrapper_type != MONO_WRAPPER_NONE)
520                         continue;
521
522                 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
523                     (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
524                     (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
525                         g_assert_not_reached ();
526
527                 if (!((MonoMethodNormal *) method)->header) {
528                         g_warning (G_STRLOC ": Internal error: method %s.%s doesn't have a header",
529                                    method->klass->name, method->name);
530                         continue;
531                 }
532
533                 create_method (symfile, token, method);
534         }
535 }
536
537 static int
538 create_symfile (MonoSymbolFile *symfile, gboolean emit_warnings)
539 {
540         MonoSymbolFilePriv *priv = symfile->_priv;
541         char *ptr;
542         guint64 magic;
543         long version;
544         off_t offset;
545
546         priv->fd = g_file_open_tmp (NULL, &priv->file_name, NULL);
547         if (priv->fd == -1) {
548                 if (emit_warnings)
549                         g_warning ("Can't create symbol file");
550                 return FALSE;
551         }
552
553         symfile->symbol_file = g_strdup (priv->file_name);
554
555         magic = MONO_SYMBOL_FILE_MAGIC;
556         if (write (priv->fd, &magic, sizeof (magic)) < 0)
557                 return FALSE;
558
559         version = MONO_SYMBOL_FILE_VERSION;
560         if (write (priv->fd, &version, sizeof (version)) < 0)
561                 return FALSE;
562
563         offset = lseek (priv->fd, 0, SEEK_CUR);
564
565         priv->offset_table = g_new0 (MonoSymbolFileOffsetTable, 1);
566         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
567                 return FALSE;
568
569         //
570         // Write source file table.
571         //
572         if (priv->source_file) {
573                 priv->offset_table->source_table_offset = lseek (priv->fd, 0, SEEK_CUR);
574                 if (!write_string (priv->fd, priv->source_file))
575                         return FALSE;
576                 priv->offset_table->source_table_size = lseek (priv->fd, 0, SEEK_CUR) -
577                         priv->offset_table->source_table_offset;
578         }
579
580         //
581         // Create method table.
582         //
583
584         priv->method_table = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
585                                                     (GDestroyNotify) free_method_entry);
586
587         create_methods (symfile);
588
589         //
590         // Write method table.
591         //
592
593         priv->offset_table->method_table_offset = lseek (priv->fd, 0, SEEK_CUR);
594
595         g_hash_table_foreach (priv->method_table, write_method, symfile);
596         if (priv->error)
597                 return FALSE;
598
599         priv->offset_table->method_table_size = lseek (priv->fd, 0, SEEK_CUR) -
600                 priv->offset_table->method_table_offset;
601
602         //
603         // Write offset table.
604         //
605
606         symfile->raw_contents_size = lseek (priv->fd, 0, SEEK_CUR);
607
608         lseek (priv->fd, offset, SEEK_SET);
609         if (write (priv->fd, priv->offset_table, sizeof (MonoSymbolFileOffsetTable)) < 0)
610                 return FALSE;
611
612         lseek (priv->fd, symfile->raw_contents_size, SEEK_SET);
613
614         ptr = mono_raw_buffer_load (priv->fd, TRUE, 0, symfile->raw_contents_size);
615         if (!ptr)
616                 return FALSE;
617
618         symfile->raw_contents = ptr;
619
620         if (!write_string_table (symfile))
621                 return FALSE;
622
623         return TRUE;
624 }
625
626 MonoSymbolFile *
627 mono_debug_create_mono_symbol_file (MonoImage *image, GHashTable *method_hash)
628 {
629         MonoSymbolFile *symfile;
630
631         symfile = g_new0 (MonoSymbolFile, 1);
632         symfile->magic = MONO_SYMBOL_FILE_MAGIC;
633         symfile->version = MONO_SYMBOL_FILE_VERSION;
634         symfile->dynamic_magic = MONO_SYMBOL_FILE_DYNAMIC_MAGIC;
635         symfile->dynamic_version = MONO_SYMBOL_FILE_DYNAMIC_VERSION;
636         symfile->is_dynamic = TRUE;
637         symfile->image_file = g_strdup (image->name);
638
639         symfile->_priv = g_new0 (MonoSymbolFilePriv, 1);
640         symfile->_priv->image = image;
641         symfile->_priv->method_hash = method_hash;
642
643         if (!create_symfile (symfile, TRUE)) {
644                 mono_debug_close_mono_symbol_file (symfile);
645                 return NULL;
646         }
647
648         return symfile;
649 }
650
651 MonoDebugMethodInfo *
652 mono_debug_find_method (MonoSymbolFile *symfile, MonoMethod *method)
653 {
654         return g_hash_table_lookup (symfile->_priv->method_hash, method);
655 }
656
657 static void
658 write_method_name (gpointer key, gpointer value, gpointer user_data)
659 {
660         MonoSymbolFile *symfile = (MonoSymbolFile *) user_data;
661         MonoSymbolFileMethodEntryPriv *mep = (MonoSymbolFileMethodEntryPriv *) value;
662         MonoSymbolFilePriv *priv = symfile->_priv;
663         guint8 *offset_ptr, *string_ptr;
664         guint32 offset;
665
666         offset = mep->method_name_offset + priv->string_offset_size;
667
668         offset_ptr = symfile->string_table + mep->index * 4;
669         string_ptr = symfile->string_table + offset;
670
671         *((guint32 *) offset_ptr) = offset;
672         strcpy (string_ptr, mep->name);
673 }
674
675 static int
676 write_string_table (MonoSymbolFile *symfile)
677 {
678         MonoSymbolFilePriv *priv = symfile->_priv;
679
680         priv->string_offset_size = priv->offset_table->method_count * 4;
681
682         symfile->string_table_size = priv->string_table_size + priv->string_offset_size;
683         symfile->string_table = g_malloc0 (symfile->string_table_size);
684
685         g_hash_table_foreach (symfile->_priv->method_table, write_method_name, symfile);
686         return TRUE;
687 }
688
689 MonoReflectionMethod *
690 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
691 {
692         MonoMethod *method;
693
694         method = mono_get_method (assembly->assembly->image, token, NULL);
695
696         return mono_method_get_object (mono_domain_get (), method, NULL);
697 }
698
699 MonoReflectionType *
700 ves_icall_MonoDebugger_GetType (MonoReflectionAssembly *assembly, guint32 token)
701 {
702         MonoClass *klass;
703
704         klass = g_hash_table_lookup (assembly->assembly->image->class_cache, GUINT_TO_POINTER (token));
705         if (!klass) {
706                 g_message (G_STRLOC ": %x", token);
707                 return NULL;
708         }
709
710         return mono_type_get_object (mono_domain_get (), &klass->byval_arg);
711 }
712
713 MonoReflectionType *
714 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
715 {
716         MonoDomain *domain; 
717         MonoImage *image;
718         MonoType *type;
719         const char *ptr;
720         int len = 0;
721
722         MONO_CHECK_ARG_NULL (assembly);
723         MONO_CHECK_ARG_NULL (signature);
724
725         domain = mono_domain_get();
726         image = assembly->assembly->image;
727
728         ptr = mono_array_addr (signature, char, 0);
729         g_assert (*ptr++ == 0x07);
730         len = mono_metadata_decode_value (ptr, &ptr);
731         g_assert (len == 1);
732
733         type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
734
735         return mono_type_get_object (domain, type);
736 }
737
738 static MonoDebugRangeInfo *
739 allocate_range_entry (MonoSymbolFile *symfile)
740 {
741         MonoDebugRangeInfo *retval;
742         guint32 size, chunks;
743
744         symfile->range_entry_size = sizeof (MonoDebugRangeInfo);
745
746         if (!symfile->range_table) {
747                 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE;
748                 symfile->range_table = g_malloc0 (size);
749                 symfile->num_range_entries = 1;
750                 return symfile->range_table;
751         }
752
753         if (!((symfile->num_range_entries + 1) % RANGE_TABLE_CHUNK_SIZE)) {
754                 chunks = (symfile->num_range_entries + 1) / RANGE_TABLE_CHUNK_SIZE;
755                 size = sizeof (MonoDebugRangeInfo) * RANGE_TABLE_CHUNK_SIZE * (chunks + 1);
756
757                 symfile->range_table = g_realloc (symfile->range_table, size);
758         }
759
760         retval = symfile->range_table + symfile->num_range_entries;
761         symfile->num_range_entries++;
762         return retval;
763 }
764
765 static MonoDebugTypeInfo *
766 allocate_type_entry (MonoSymbolFile *symfile)
767 {
768         MonoDebugTypeInfo *retval;
769         guint32 size, chunks;
770
771         symfile->type_entry_size = sizeof (MonoDebugTypeInfo);
772
773         if (!symfile->type_table) {
774                 size = sizeof (MonoDebugTypeInfo) * TYPE_TABLE_CHUNK_SIZE;
775                 symfile->type_table = g_malloc0 (size);
776                 symfile->num_type_entries = 1;
777                 return symfile->type_table;
778         }
779
780         if (!((symfile->num_type_entries + 1) % TYPE_TABLE_CHUNK_SIZE)) {
781                 chunks = (symfile->num_type_entries + 1) / TYPE_TABLE_CHUNK_SIZE;
782                 size = sizeof (MonoDebugTypeInfo) * TYPE_TABLE_CHUNK_SIZE * (chunks + 1);
783
784                 symfile->type_table = g_realloc (symfile->type_table, size);
785         }
786
787         retval = symfile->type_table + symfile->num_type_entries;
788         symfile->num_type_entries++;
789         return retval;
790 }
791
792 static gpointer
793 write_simple_type (MonoType *type)
794 {
795         guint8 buffer [BUFSIZ], *ptr = buffer, *retval;
796         guint32 size;
797
798         if (!type_table)
799                 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
800
801         retval = g_hash_table_lookup (type_table, type);
802         if (retval)
803                 return retval;
804
805         switch (type->type) {
806         case MONO_TYPE_BOOLEAN:
807         case MONO_TYPE_I1:
808         case MONO_TYPE_U1:
809                 *((int *) ptr)++ = 1;
810                 break;
811
812         case MONO_TYPE_CHAR:
813         case MONO_TYPE_I2:
814         case MONO_TYPE_U2:
815                 *((int *) ptr)++ = 2;
816                 break;
817
818         case MONO_TYPE_I4:
819         case MONO_TYPE_U4:
820         case MONO_TYPE_R4:
821                 *((int *) ptr)++ = 4;
822                 break;
823
824         case MONO_TYPE_I8:
825         case MONO_TYPE_U8:
826         case MONO_TYPE_R8:
827                 *((int *) ptr)++ = 8;
828                 break;
829
830         case MONO_TYPE_STRING: {
831                 MonoString string;
832
833                 *((int *) ptr)++ = -8;
834                 *((guint32 *) ptr)++ = sizeof (MonoString);
835                 *ptr++ = 1;
836                 *ptr++ = (guint8*)&string.length - (guint8*)&string;
837                 *ptr++ = sizeof (string.length);
838                 *ptr++ = (guint8*)&string.chars - (guint8*)&string;
839                 break;
840         }
841
842         default:
843                 return NULL;
844         }
845
846         size = ptr - buffer;
847
848         retval = g_malloc0 (size + 4);
849         memcpy (retval + 4, buffer, size);
850         *((int *) retval) = size;
851
852         g_hash_table_insert (type_table, type, retval);
853
854         return retval;
855 }
856
857 static gpointer
858 write_type (MonoType *type)
859 {
860         guint8 buffer [BUFSIZ], *ptr = buffer, *retval;
861         int num_fields = 0;
862         guint32 size;
863
864         if (!type_table)
865                 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
866
867         retval = g_hash_table_lookup (type_table, type);
868         if (retval)
869                 return retval;
870
871         retval = write_simple_type (type);
872         if (retval)
873                 return retval;
874
875         switch (type->type) {
876         case MONO_TYPE_SZARRAY:
877                 size = 8 + sizeof (int) + sizeof (gpointer);
878                 break;
879
880         case MONO_TYPE_ARRAY:
881                 size = 15 + sizeof (int) + sizeof (gpointer);
882                 break;
883
884         case MONO_TYPE_VALUETYPE:
885         case MONO_TYPE_CLASS: {
886                 MonoClass *klass = type->data.klass;
887                 int i;
888
889                 mono_class_init (klass);
890                 if (klass->enumtype) {
891                         size = 5 + sizeof (int) + sizeof (gpointer);
892                         break;
893                 }
894
895                 for (i = 0; i < klass->field.count; i++)
896                         if (!(klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
897                                 ++num_fields;
898
899                 size = 14 + sizeof (int) + num_fields * (4 + sizeof (gpointer));
900
901                 if (type->type == MONO_TYPE_CLASS)
902                         size += sizeof (gpointer);
903                 break;
904         }
905
906         case MONO_TYPE_OBJECT:
907                 size = 5 + sizeof (int);
908                 break;
909
910         default:
911                 size = sizeof (int);
912                 break;
913         }
914
915         retval = g_malloc0 (size + 4);
916         memcpy (retval + 4, buffer, size);
917         *((int *) retval) = size;
918
919         g_hash_table_insert (type_table, type, retval);
920
921         ptr = retval + 4;
922
923         switch (type->type) {
924         case MONO_TYPE_SZARRAY: {
925                 MonoArray array;
926
927                 *((int *) ptr)++ = -8 - sizeof (gpointer);
928                 *((guint32 *) ptr)++ = sizeof (MonoArray);
929                 *ptr++ = 2;
930                 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
931                 *ptr++ = sizeof (array.max_length);
932                 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
933                 *((gpointer *) ptr)++ = write_type (type->data.type);
934                 break;
935         }
936
937         case MONO_TYPE_ARRAY: {
938                 MonoArray array;
939                 MonoArrayBounds bounds;
940
941                 *((int *) ptr)++ = -15 - sizeof (gpointer);
942                 *((guint32 *) ptr)++ = sizeof (MonoArray);
943                 *ptr++ = 3;
944                 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
945                 *ptr++ = sizeof (array.max_length);
946                 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
947                 *ptr++ = type->data.array->rank;
948                 *ptr++ = (guint8*)&array.bounds - (guint8*)&array;
949                 *ptr++ = sizeof (MonoArrayBounds);
950                 *ptr++ = (guint8*)&bounds.lower_bound - (guint8*)&bounds;
951                 *ptr++ = sizeof (bounds.lower_bound);
952                 *ptr++ = (guint8*)&bounds.length - (guint8*)&bounds;
953                 *ptr++ = sizeof (bounds.length);
954                 *((gpointer *) ptr)++ = write_type (type->data.array->type);
955                 break;
956         }
957
958         case MONO_TYPE_VALUETYPE:
959         case MONO_TYPE_CLASS: {
960                 MonoClass *klass = type->data.klass;
961                 int base_offset = type->type == MONO_TYPE_CLASS ? 0 : - sizeof (MonoObject);
962                 int i;
963
964                 mono_class_init (klass);
965                 if (klass->enumtype) {
966                         *((int *) ptr)++ = -5 - sizeof (gpointer);
967                         *((guint32 *) ptr)++ = sizeof (MonoObject);
968                         *ptr++ = 4;
969                         *((gpointer *) ptr)++ = write_type (klass->enum_basetype);
970                         break;
971                 }
972
973                 *((int *) ptr)++ = -14 - num_fields * (4 + sizeof (gpointer));
974                 *((guint32 *) ptr)++ = klass->instance_size + base_offset;
975                 *ptr++ = type->type == MONO_TYPE_CLASS ? 6 : 5;
976                 *ptr++ = type->type == MONO_TYPE_CLASS;
977                 *((guint32 *) ptr)++ = num_fields;
978                 *((guint32 *) ptr)++ = num_fields * (4 + sizeof (gpointer));
979                 for (i = 0; i < klass->field.count; i++) {
980                         if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
981                                 continue;
982
983                         *((guint32 *) ptr)++ = klass->fields [i].offset + base_offset;
984                         *((gpointer *) ptr)++ = write_type (klass->fields [i].type);
985                 }
986
987                 if (type->type == MONO_TYPE_CLASS) {
988                         if (klass->parent)
989                                 *((gpointer *) ptr)++ = write_type (&klass->parent->this_arg);
990                         else
991                                 *((gpointer *) ptr)++ = NULL;
992                 }
993
994                 break;
995         }
996
997         case MONO_TYPE_OBJECT:
998                 *((int *) ptr)++ = -5;
999                 *((guint32 *) ptr)++ = sizeof (MonoObject);
1000                 *ptr++ = 7;
1001                 break;
1002
1003         default:
1004                 g_message (G_STRLOC ": %p - %x,%x,%x", type, type->attrs, type->type, type->byref);
1005
1006                 *((int *) ptr)++ = -1;
1007                 break;
1008         }
1009
1010         return retval;
1011 }