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