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