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