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