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