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