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