2004-11-07 Ben Maurer <bmaurer@ximian.com>
[mono-project.git] / mono / metadata / mono-debug-debugger.c
blobfdd66e14b008ec7a4642706f84cb813ee5543ed9
1 #include <config.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/metadata.h>
6 #include <mono/metadata/tabledefs.h>
7 #include <mono/metadata/tokentype.h>
8 #include <mono/metadata/appdomain.h>
9 #include <mono/metadata/gc-internal.h>
10 #include <mono/os/gc_wrapper.h>
11 #include <mono/metadata/object-internals.h>
12 #include <mono/metadata/class-internals.h>
13 #include <mono/metadata/exception.h>
14 #include <mono/metadata/mono-debug.h>
15 #include <mono/metadata/mono-debug-debugger.h>
16 #include <mono/metadata/mono-endian.h>
18 #define SYMFILE_TABLE_CHUNK_SIZE 16
19 #define RANGE_TABLE_CHUNK_SIZE 256
20 #define CLASS_TABLE_CHUNK_SIZE 256
21 #define TYPE_TABLE_PTR_CHUNK_SIZE 256
22 #define TYPE_TABLE_CHUNK_SIZE 65536
23 #define MISC_TABLE_PTR_CHUNK_SIZE 256
24 #define MISC_TABLE_CHUNK_SIZE 65536
26 static guint32 debugger_lock_level = 0;
27 static CRITICAL_SECTION debugger_lock_mutex;
28 static gboolean mono_debugger_initialized = FALSE;
29 static MonoObject *last_exception = NULL;
31 static gboolean must_reload_symtabs = FALSE;
32 static gboolean builtin_types_initialized = FALSE;
34 static GHashTable *images = NULL;
35 static GHashTable *type_table = NULL;
36 static GHashTable *misc_table = NULL;
37 static GHashTable *class_table = NULL;
38 static GHashTable *class_info_table = NULL;
40 static MonoDebuggerRangeInfo *allocate_range_entry (MonoDebuggerSymbolFile *symfile);
41 static MonoDebuggerClassInfo *allocate_class_entry (MonoDebuggerSymbolFile *symfile);
42 static guint32 allocate_type_entry (MonoDebuggerSymbolTable *table, guint32 size, guint8 **ptr);
43 static guint32 write_type (MonoDebuggerSymbolTable *table, MonoType *type);
44 static guint32 do_write_class (MonoDebuggerSymbolTable *table, MonoClass *klass,
45 MonoDebuggerClassInfo *cinfo);
46 static guint32 write_class (MonoDebuggerSymbolTable *table, MonoClass *klass);
48 MonoDebuggerSymbolTable *mono_debugger_symbol_table = NULL;
49 void (*mono_debugger_event_handler) (MonoDebuggerEvent event, gpointer data, guint32 arg) = NULL;
51 #define WRITE_UINT32(ptr,value) G_STMT_START { \
52 * ((guint32 *) ptr) = value; \
53 ptr += 4; \
54 } G_STMT_END
56 #define WRITE_POINTER(ptr,value) G_STMT_START { \
57 * ((gpointer *) ptr) = (gpointer) (value); \
58 ptr += sizeof (gpointer); \
59 } G_STMT_END
61 #define WRITE_STRING(ptr,value) G_STMT_START { \
62 memcpy (ptr, value, strlen (value)+1); \
63 ptr += strlen (value)+1; \
64 } G_STMT_END
66 typedef struct {
67 gpointer stack_pointer;
68 MonoObject *exception_obj;
69 guint32 stop;
70 } MonoDebuggerExceptionInfo;
72 #ifndef PLATFORM_WIN32
74 MonoDebuggerIOLayer mono_debugger_io_layer = {
75 InitializeCriticalSection, DeleteCriticalSection, TryEnterCriticalSection,
76 EnterCriticalSection, LeaveCriticalSection, WaitForSingleObjectEx, SignalObjectAndWait,
77 WaitForMultipleObjectsEx, CreateSemaphore, ReleaseSemaphore, CreateThread,
78 GetCurrentThreadId
81 #endif
83 void
84 mono_debugger_lock (void)
86 if (!mono_debugger_initialized) {
87 debugger_lock_level++;
88 return;
91 EnterCriticalSection (&debugger_lock_mutex);
92 debugger_lock_level++;
95 void
96 mono_debugger_unlock (void)
98 g_assert (debugger_lock_level > 0);
100 if (!mono_debugger_initialized) {
101 debugger_lock_level--;
102 return;
105 if (debugger_lock_level == 1) {
106 if (must_reload_symtabs) {
107 mono_debugger_event (MONO_DEBUGGER_EVENT_RELOAD_SYMTABS, NULL, 0);
108 must_reload_symtabs = FALSE;
112 debugger_lock_level--;
113 LeaveCriticalSection (&debugger_lock_mutex);
116 static MonoDebuggerSymbolFile *
117 allocate_symbol_file_entry (MonoDebuggerSymbolTable *table)
119 MonoDebuggerSymbolFile *symfile;
121 if (!table->symbol_files)
122 table->symbol_files = g_new0 (MonoDebuggerSymbolFile *, SYMFILE_TABLE_CHUNK_SIZE);
123 else if (!((table->num_symbol_files + 1) % SYMFILE_TABLE_CHUNK_SIZE)) {
124 guint32 chunks = (table->num_symbol_files + 1) / SYMFILE_TABLE_CHUNK_SIZE;
125 guint32 size = sizeof (MonoDebuggerSymbolFile *) * SYMFILE_TABLE_CHUNK_SIZE * (chunks + 1);
127 table->symbol_files = g_realloc (table->symbol_files, size);
130 symfile = g_new0 (MonoDebuggerSymbolFile, 1);
131 symfile->index = table->num_symbol_files;
132 symfile->range_entry_size = sizeof (MonoDebuggerRangeInfo);
133 symfile->class_entry_size = sizeof (MonoDebuggerClassInfo);
134 symfile->class_table_size = sizeof (MonoDebuggerClassTable);
135 table->symbol_files [table->num_symbol_files++] = symfile;
136 return symfile;
139 void
140 mono_debugger_initialize (void)
142 MonoDebuggerSymbolTable *symbol_table;
144 MONO_GC_REGISTER_ROOT (last_exception);
146 g_assert (!mono_debugger_initialized);
148 InitializeCriticalSection (&debugger_lock_mutex);
149 mono_debugger_initialized = TRUE;
151 mono_debugger_lock ();
153 symbol_table = g_new0 (MonoDebuggerSymbolTable, 1);
154 symbol_table->magic = MONO_DEBUGGER_MAGIC;
155 symbol_table->version = MONO_DEBUGGER_VERSION;
156 symbol_table->total_size = sizeof (MonoDebuggerSymbolTable);
158 images = g_hash_table_new (g_direct_hash, g_direct_equal);
159 type_table = g_hash_table_new (g_direct_hash, g_direct_equal);
160 misc_table = g_hash_table_new (g_direct_hash, g_direct_equal);
161 class_table = g_hash_table_new (g_direct_hash, g_direct_equal);
162 class_info_table = g_hash_table_new (g_direct_hash, g_direct_equal);
164 mono_debugger_symbol_table = symbol_table;
166 mono_debugger_unlock ();
169 MonoDebuggerSymbolFile *
170 mono_debugger_add_symbol_file (MonoDebugHandle *handle)
172 MonoDebuggerSymbolFile *info;
174 g_assert (mono_debugger_initialized);
175 mono_debugger_lock ();
177 info = g_hash_table_lookup (images, handle->image);
178 if (info) {
179 mono_debugger_unlock ();
180 return info;
183 info = allocate_symbol_file_entry (mono_debugger_symbol_table);
184 info->symfile = handle->symfile;
185 info->image = handle->image;
186 info->image_file = handle->image_file;
188 g_hash_table_insert (images, handle->image, info);
189 mono_debugger_unlock ();
191 return info;
194 static void
195 write_builtin_type (MonoDebuggerSymbolTable *table, MonoDebuggerSymbolFile *symfile,
196 MonoClass *klass, MonoDebuggerBuiltinTypeInfo *info)
198 guint8 buffer [BUFSIZ], *ptr = buffer;
199 guint32 size;
201 g_assert (!klass->init_pending);
202 mono_class_init (klass);
204 switch (klass->byval_arg.type) {
205 case MONO_TYPE_VOID:
206 *ptr++ = MONO_DEBUGGER_TYPE_KIND_UNKNOWN;
207 WRITE_UINT32 (ptr, 0);
208 ptr += 4;
209 break;
211 case MONO_TYPE_BOOLEAN:
212 case MONO_TYPE_I1:
213 case MONO_TYPE_U1:
214 case MONO_TYPE_CHAR:
215 case MONO_TYPE_I2:
216 case MONO_TYPE_U2:
217 case MONO_TYPE_I4:
218 case MONO_TYPE_U4:
219 case MONO_TYPE_R4:
220 case MONO_TYPE_I8:
221 case MONO_TYPE_U8:
222 case MONO_TYPE_R8:
223 *ptr++ = MONO_DEBUGGER_TYPE_KIND_FUNDAMENTAL;
224 WRITE_UINT32 (ptr, klass->instance_size - sizeof (MonoObject));
225 ptr += 4;
226 break;
228 case MONO_TYPE_STRING: {
229 MonoString string;
231 *ptr++ = MONO_DEBUGGER_TYPE_KIND_STRING;
232 WRITE_UINT32 (ptr, klass->instance_size);
233 ptr += 4;
234 *ptr++ = (guint8*)&string.length - (guint8*)&string;
235 *ptr++ = sizeof (string.length);
236 *ptr++ = (guint8*)&string.chars - (guint8*)&string;
238 break;
241 case MONO_TYPE_I:
242 case MONO_TYPE_U:
243 *ptr++ = MONO_DEBUGGER_TYPE_KIND_FUNDAMENTAL;
244 WRITE_UINT32 (ptr, sizeof (void *));
245 ptr += 4;
246 break;
248 case MONO_TYPE_VALUETYPE:
249 *ptr++ = MONO_DEBUGGER_TYPE_KIND_STRUCT;
250 WRITE_UINT32 (ptr, klass->instance_size);
251 ptr += 4;
252 break;
254 case MONO_TYPE_CLASS:
255 *ptr++ = MONO_DEBUGGER_TYPE_KIND_CLASS;
256 WRITE_UINT32 (ptr, klass->instance_size);
257 ptr += 4;
258 break;
260 case MONO_TYPE_OBJECT:
261 g_assert (klass == mono_defaults.object_class);
262 *ptr++ = MONO_DEBUGGER_TYPE_KIND_OBJECT;
263 WRITE_UINT32 (ptr, klass->instance_size);
264 ptr += 4;
265 break;
267 default:
268 g_error (G_STRLOC ": Unknown builtin type %s.%s - %d", klass->name_space, klass->name, klass->byval_arg.type);
271 size = ptr - buffer;
272 info->type_info = allocate_type_entry (table, size, &info->type_data);
273 memcpy (info->type_data, buffer, size);
275 info->centry->info = g_new0 (MonoDebuggerClassInfo, 1); //allocate_class_entry (symfile);
276 info->centry->info->klass = klass;
277 if (klass->rank) {
278 info->centry->info->token = klass->element_class->type_token;
279 info->centry->info->rank = klass->rank;
280 } else
281 info->centry->info->token = klass->type_token;
282 info->centry->info->type_info = info->type_info;
285 static MonoDebuggerBuiltinTypeInfo *
286 add_builtin_type (MonoDebuggerSymbolFile *symfile, MonoClass *klass)
288 MonoDebuggerClassEntry *centry;
289 MonoDebuggerBuiltinTypeInfo *info;
291 centry = g_new0 (MonoDebuggerClassEntry, 1);
293 info = g_new0 (MonoDebuggerBuiltinTypeInfo, 1);
294 info->klass = klass;
295 info->centry = centry;
297 g_hash_table_insert (class_info_table, klass, centry);
299 write_builtin_type (mono_debugger_symbol_table, symfile, klass, info);
300 return info;
303 static void
304 add_builtin_type_2 (MonoDebuggerBuiltinTypeInfo *info)
306 info->class_info = do_write_class (mono_debugger_symbol_table, info->klass, NULL);
307 * (guint32 *) (info->type_data + 5) = info->class_info;
310 static void
311 add_exception_class (MonoDebuggerSymbolFile *symfile, MonoException *exc)
313 mono_debugger_start_add_type (symfile, ((MonoObject *) exc)->vtable->klass);
314 mono_debugger_add_type (symfile, ((MonoObject *) exc)->vtable->klass);
317 MonoDebuggerBuiltinTypes *
318 mono_debugger_add_builtin_types (MonoDebuggerSymbolFile *symfile)
320 MonoDebuggerBuiltinTypes *types = g_new0 (MonoDebuggerBuiltinTypes, 1);
321 MonoClass *klass;
323 mono_debugger_symbol_table->corlib = symfile;
324 mono_debugger_symbol_table->builtin_types = types;
326 types->total_size = sizeof (MonoDebuggerBuiltinTypes);
327 types->type_info_size = sizeof (MonoDebuggerBuiltinTypeInfo);
329 types->object_type = add_builtin_type (symfile, mono_defaults.object_class);
330 klass = mono_class_from_name (mono_defaults.corlib, "System", "ValueType");
331 g_assert (klass);
332 types->valuetype_type = add_builtin_type (symfile, klass);
334 types->byte_type = add_builtin_type (symfile, mono_defaults.byte_class);
335 types->void_type = add_builtin_type (symfile, mono_defaults.void_class);
336 types->boolean_type = add_builtin_type (symfile, mono_defaults.boolean_class);
337 types->sbyte_type = add_builtin_type (symfile, mono_defaults.sbyte_class);
338 types->int16_type = add_builtin_type (symfile, mono_defaults.int16_class);
339 types->uint16_type = add_builtin_type (symfile, mono_defaults.uint16_class);
340 types->int32_type = add_builtin_type (symfile, mono_defaults.int32_class);
341 types->uint32_type = add_builtin_type (symfile, mono_defaults.uint32_class);
342 types->int_type = add_builtin_type (symfile, mono_defaults.int_class);
343 types->uint_type = add_builtin_type (symfile, mono_defaults.uint_class);
344 types->int64_type = add_builtin_type (symfile, mono_defaults.int64_class);
345 types->uint64_type = add_builtin_type (symfile, mono_defaults.uint64_class);
346 types->single_type = add_builtin_type (symfile, mono_defaults.single_class);
347 types->double_type = add_builtin_type (symfile, mono_defaults.double_class);
348 types->char_type = add_builtin_type (symfile, mono_defaults.char_class);
349 types->string_type = add_builtin_type (symfile, mono_defaults.string_class);
351 klass = mono_class_from_name (mono_defaults.corlib, "System", "Type");
352 g_assert (klass);
353 types->type_type = add_builtin_type (symfile, klass);
355 types->enum_type = add_builtin_type (symfile, mono_defaults.enum_class);
356 types->array_type = add_builtin_type (symfile, mono_defaults.array_class);
357 types->exception_type = add_builtin_type (symfile, mono_defaults.exception_class);
359 add_builtin_type_2 (types->object_type);
360 add_builtin_type_2 (types->valuetype_type);
362 add_builtin_type_2 (types->byte_type);
363 add_builtin_type_2 (types->void_type);
364 add_builtin_type_2 (types->boolean_type);
365 add_builtin_type_2 (types->sbyte_type);
366 add_builtin_type_2 (types->int16_type);
367 add_builtin_type_2 (types->uint16_type);
368 add_builtin_type_2 (types->int32_type);
369 add_builtin_type_2 (types->uint32_type);
370 add_builtin_type_2 (types->int_type);
371 add_builtin_type_2 (types->uint_type);
372 add_builtin_type_2 (types->int64_type);
373 add_builtin_type_2 (types->uint64_type);
374 add_builtin_type_2 (types->single_type);
375 add_builtin_type_2 (types->double_type);
376 add_builtin_type_2 (types->char_type);
377 add_builtin_type_2 (types->string_type);
378 add_builtin_type_2 (types->type_type);
380 add_builtin_type_2 (types->enum_type);
381 add_builtin_type_2 (types->array_type);
382 add_builtin_type_2 (types->exception_type);
384 add_exception_class (symfile, mono_get_exception_divide_by_zero ());
385 add_exception_class (symfile, mono_get_exception_security ());
386 add_exception_class (symfile, mono_get_exception_arithmetic ());
387 add_exception_class (symfile, mono_get_exception_overflow ());
388 add_exception_class (symfile, mono_get_exception_null_reference ());
389 add_exception_class (symfile, mono_get_exception_thread_abort ());
390 add_exception_class (symfile, mono_get_exception_invalid_cast ());
391 add_exception_class (symfile, mono_get_exception_index_out_of_range ());
392 add_exception_class (symfile, mono_get_exception_thread_abort ());
393 add_exception_class (symfile, mono_get_exception_index_out_of_range ());
394 add_exception_class (symfile, mono_get_exception_array_type_mismatch ());
395 add_exception_class (symfile, mono_get_exception_missing_method ());
396 add_exception_class (symfile, mono_get_exception_appdomain_unloaded ());
397 add_exception_class (symfile, mono_get_exception_stack_overflow ());
399 builtin_types_initialized = TRUE;
401 return types;
404 static guint32
405 write_class (MonoDebuggerSymbolTable *table, MonoClass *klass)
407 MonoDebuggerClassEntry *centry;
409 centry = g_hash_table_lookup (class_info_table, klass);
410 if (!centry) {
411 MonoDebuggerSymbolFile *symfile = _mono_debugger_get_symfile (klass->image);
413 g_assert (symfile);
414 mono_debugger_start_add_type (symfile, klass);
415 centry = g_hash_table_lookup (class_info_table, klass);
417 g_assert (centry);
419 if (centry->info) {
420 g_assert (centry->info->type_info);
421 return centry->info->type_info;
424 if (!centry->type_reference) {
425 guint8 *ptr;
427 centry->type_reference = allocate_type_entry (table, 5, &ptr);
429 *ptr++ = MONO_DEBUGGER_TYPE_KIND_REFERENCE;
430 WRITE_POINTER (ptr, klass);
433 return centry->type_reference;
436 void
437 mono_debugger_start_add_type (MonoDebuggerSymbolFile *symfile, MonoClass *klass)
439 MonoDebuggerClassEntry *centry;
441 mono_debugger_lock ();
442 centry = g_hash_table_lookup (class_info_table, klass);
443 if (centry) {
444 mono_debugger_unlock ();
445 return;
448 centry = g_new0 (MonoDebuggerClassEntry, 1);
449 g_hash_table_insert (class_info_table, klass, centry);
450 mono_debugger_unlock ();
453 void
454 mono_debugger_add_type (MonoDebuggerSymbolFile *symfile, MonoClass *klass)
456 MonoDebuggerClassEntry *centry;
458 mono_debugger_lock ();
459 centry = g_hash_table_lookup (class_info_table, klass);
460 g_assert (centry);
462 if (centry->info) {
463 mono_debugger_unlock ();
464 return;
467 centry->info = allocate_class_entry (symfile);
468 centry->info->klass = klass;
469 if (klass->rank) {
470 centry->info->token = klass->element_class->type_token;
471 centry->info->rank = klass->rank;
472 } else
473 centry->info->token = klass->type_token;
475 do_write_class (mono_debugger_symbol_table, klass, centry->info);
477 g_assert (centry->info && centry->info->type_info);
479 symfile->generation++;
480 must_reload_symtabs = TRUE;
482 mono_debugger_unlock ();
485 void
486 mono_debugger_add_method (MonoDebuggerSymbolFile *symfile, MonoDebugMethodInfo *minfo,
487 MonoDebugMethodJitInfo *jit)
489 MonoSymbolFileMethodAddress *address;
490 MonoSymbolFileLexicalBlockEntry *block;
491 MonoDebugVarInfo *var_table;
492 MonoDebuggerRangeInfo *range;
493 MonoMethodHeader *header;
494 guint32 size, num_variables, variable_size, variable_offset;
495 guint32 type_size, type_offset, *type_index_table, has_this;
496 guint32 line_size = 0, line_offset = 0, block_offset, block_size;
497 MonoDebugLexicalBlockEntry *block_table;
498 MonoDebugLineNumberEntry *line_table;
499 guint32 *type_table;
500 guint8 *ptr;
501 int i;
503 if (!symfile->symfile->method_hash)
504 return;
506 header = ((MonoMethodNormal *) minfo->method)->header;
508 symfile->generation++;
510 size = sizeof (MonoSymbolFileMethodAddress);
512 num_variables = jit->num_params + read32(&(minfo->entry->_num_locals));
513 has_this = jit->this_var != NULL;
515 variable_size = (num_variables + has_this) * sizeof (MonoDebugVarInfo);
516 variable_offset = size;
517 size += variable_size;
519 type_size = (num_variables + 1) * sizeof (gpointer);
520 type_offset = size;
521 size += type_size;
523 if (jit->line_numbers) {
524 line_offset = size;
525 line_size = jit->line_numbers->len * sizeof (MonoDebugLineNumberEntry);
526 size += line_size;
529 block_size = read32(&(minfo->entry->_num_lexical_blocks)) * sizeof (MonoSymbolFileLexicalBlockEntry);
530 block_offset = size;
531 size += block_size;
533 address = g_malloc0 (size);
534 ptr = (guint8 *) address;
536 block = (MonoSymbolFileLexicalBlockEntry *)
537 (symfile->symfile->raw_contents + read32(&(minfo->entry->_lexical_block_table_offset)));
538 block_table = (MonoDebugLexicalBlockEntry *) (ptr + block_offset);
540 for (i = 0; i < read32(&(minfo->entry->_num_lexical_blocks)); i++, block++) {
541 block_table [i].start_address = _mono_debug_address_from_il_offset (jit, read32(&(block->_start_offset)));
542 block_table [i].end_address = _mono_debug_address_from_il_offset (jit, read32(&(block->_end_offset)));
545 address->size = size;
546 address->has_this = has_this;
547 address->num_params = jit->num_params;
548 address->start_address = jit->code_start;
549 address->end_address = jit->code_start + jit->code_size;
550 address->method_start_address = address->start_address + jit->prologue_end;
551 address->method_end_address = address->start_address + jit->epilogue_begin;
552 address->wrapper_address = jit->wrapper_addr;
553 address->variable_table_offset = variable_offset;
554 address->type_table_offset = type_offset;
555 address->lexical_block_table_offset = block_offset;
557 if (jit->line_numbers) {
558 address->num_line_numbers = jit->line_numbers->len;
559 address->line_number_offset = line_offset;
561 line_table = (MonoDebugLineNumberEntry *) (ptr + line_offset);
562 memcpy (line_table, jit->line_numbers->data, line_size);
565 range = allocate_range_entry (symfile);
566 range->index = minfo->index;
567 range->start_address = address->start_address;
568 range->end_address = address->end_address;
569 range->dynamic_data = address;
570 range->dynamic_size = size;
572 if ((minfo->method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
573 (minfo->method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
574 (minfo->method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
575 return;
577 var_table = (MonoDebugVarInfo *) (ptr + variable_offset);
578 type_table = (guint32 *) (ptr + type_offset);
580 type_index_table = (guint32 *)
581 (symfile->symfile->raw_contents + read32(&(minfo->entry->_type_index_table_offset)));
583 if (jit->this_var)
584 *var_table++ = *jit->this_var;
585 *type_table++ = write_type (mono_debugger_symbol_table, &minfo->method->klass->this_arg);
587 for (i = 0; i < jit->num_params; i++) {
588 *var_table++ = jit->params [i];
589 *type_table++ = write_type (mono_debugger_symbol_table, minfo->method->signature->params [i]);
592 if (jit->num_locals < read32(&(minfo->entry->_num_locals))) {
593 g_warning (G_STRLOC ": Method %s.%s has %d locals, but symbol file claims it has %d.",
594 minfo->method->klass->name, minfo->method->name, jit->num_locals,
595 read32(&(minfo->entry->_num_locals)));
596 var_table += read32(&(minfo->entry->_num_locals));
597 } else {
598 g_assert ((header != NULL) || (minfo->entry->_num_locals == 0));
599 for (i = 0; i < read32(&(minfo->entry->_num_locals)); i++) {
600 *var_table++ = jit->locals [i];
601 *type_table++ = write_type (mono_debugger_symbol_table, header->locals [i]);
605 must_reload_symtabs = TRUE;
608 static MonoDebuggerRangeInfo *
609 allocate_range_entry (MonoDebuggerSymbolFile *symfile)
611 MonoDebuggerRangeInfo *retval;
612 guint32 size, chunks;
614 if (!symfile->range_table) {
615 size = sizeof (MonoDebuggerRangeInfo) * RANGE_TABLE_CHUNK_SIZE;
616 symfile->range_table = g_malloc0 (size);
617 symfile->num_range_entries = 1;
618 return symfile->range_table;
621 if (!((symfile->num_range_entries + 1) % RANGE_TABLE_CHUNK_SIZE)) {
622 chunks = (symfile->num_range_entries + 1) / RANGE_TABLE_CHUNK_SIZE;
623 size = sizeof (MonoDebuggerRangeInfo) * RANGE_TABLE_CHUNK_SIZE * (chunks + 1);
625 symfile->range_table = g_realloc (symfile->range_table, size);
628 retval = symfile->range_table + symfile->num_range_entries;
629 symfile->num_range_entries++;
630 return retval;
633 static MonoDebuggerClassInfo *
634 allocate_class_entry (MonoDebuggerSymbolFile *symfile)
636 MonoDebuggerClassInfo *retval;
637 MonoDebuggerClassTable *table;
638 guint32 size;
640 if (!symfile->class_table_start) {
641 table = g_new0 (MonoDebuggerClassTable, 1);
642 symfile->class_table_start = symfile->current_class_table = table;
644 size = sizeof (MonoDebuggerClassInfo) * CLASS_TABLE_CHUNK_SIZE;
645 table->data = g_malloc0 (size);
646 table->size = CLASS_TABLE_CHUNK_SIZE;
647 table->index = 1;
649 return table->data;
652 table = symfile->current_class_table;
653 if (table->index >= table->size) {
654 table = g_new0 (MonoDebuggerClassTable, 1);
656 symfile->current_class_table->next = table;
657 symfile->current_class_table = table;
659 size = sizeof (MonoDebuggerClassInfo) * CLASS_TABLE_CHUNK_SIZE;
660 table->data = g_malloc0 (size);
661 table->size = CLASS_TABLE_CHUNK_SIZE;
662 table->index = 1;
664 return table->data;
667 retval = table->data + table->index;
668 table->index++;
669 return retval;
673 * Allocate a new entry of size `size' in the type table.
674 * Returns the global offset which is to be used to reference this type and
675 * a pointer (in the `ptr' argument) which is to be used to write the type.
677 static guint32
678 allocate_type_entry (MonoDebuggerSymbolTable *table, guint32 size, guint8 **ptr)
680 guint32 retval;
681 guint8 *data;
683 g_assert (size + 4 < TYPE_TABLE_CHUNK_SIZE);
684 g_assert (ptr != NULL);
686 /* Initialize things if necessary. */
687 if (!table->current_type_table) {
688 table->current_type_table = g_malloc0 (TYPE_TABLE_CHUNK_SIZE);
689 table->type_table_size = TYPE_TABLE_CHUNK_SIZE;
690 table->type_table_chunk_size = TYPE_TABLE_CHUNK_SIZE;
691 table->type_table_offset = MONO_DEBUGGER_TYPE_MAX + 1;
694 again:
695 /* First let's check whether there's still enough room in the current_type_table. */
696 if (table->type_table_offset + size + 4 < table->type_table_size) {
697 retval = table->type_table_offset;
698 table->type_table_offset += size + 4;
699 data = ((guint8 *) table->current_type_table) + retval - table->type_table_start;
700 *(gint32 *) data = size;
701 data += sizeof(gint32);
702 *ptr = data;
703 return retval;
706 /* Add the current_type_table to the type_tables vector and ... */
707 if (!table->type_tables) {
708 guint32 tsize = sizeof (gpointer) * TYPE_TABLE_PTR_CHUNK_SIZE;
709 table->type_tables = g_malloc0 (tsize);
712 if (!((table->num_type_tables + 1) % TYPE_TABLE_PTR_CHUNK_SIZE)) {
713 guint32 chunks = (table->num_type_tables + 1) / TYPE_TABLE_PTR_CHUNK_SIZE;
714 guint32 tsize = sizeof (gpointer) * TYPE_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
716 table->type_tables = g_realloc (table->type_tables, tsize);
719 table->type_tables [table->num_type_tables++] = table->current_type_table;
721 /* .... allocate a new current_type_table. */
722 table->current_type_table = g_malloc0 (TYPE_TABLE_CHUNK_SIZE);
723 table->type_table_start = table->type_table_offset = table->type_table_size;
724 table->type_table_size += TYPE_TABLE_CHUNK_SIZE;
726 goto again;
730 * Allocate a new entry of size `size' in the misc table.
731 * Returns the global offset which is to be used to reference this entry and
732 * a pointer (in the `ptr' argument) which is to be used to write the entry.
734 static guint32
735 allocate_misc_entry (MonoDebuggerSymbolTable *table, guint32 size, guint8 **ptr)
737 guint32 retval;
738 guint8 *data;
740 g_assert (size + 4 < MISC_TABLE_CHUNK_SIZE);
741 g_assert (ptr != NULL);
743 /* Initialize things if necessary. */
744 if (!table->current_misc_table) {
745 table->current_misc_table = g_malloc0 (MISC_TABLE_CHUNK_SIZE);
746 table->misc_table_size = MISC_TABLE_CHUNK_SIZE;
747 table->misc_table_chunk_size = MISC_TABLE_CHUNK_SIZE;
748 table->misc_table_offset = 1;
751 again:
752 /* First let's check whether there's still enough room in the current_misc_table. */
753 if (table->misc_table_offset + size + 4 < table->misc_table_size) {
754 retval = table->misc_table_offset;
755 table->misc_table_offset += size + 4;
756 data = ((guint8 *) table->current_misc_table) + retval - table->misc_table_start;
757 *(gint32 *) data = size;
758 data += sizeof(gint32);
759 *ptr = data;
760 return retval;
763 /* Add the current_misc_table to the misc_tables vector and ... */
764 if (!table->misc_tables) {
765 guint32 tsize = sizeof (gpointer) * MISC_TABLE_PTR_CHUNK_SIZE;
766 table->misc_tables = g_malloc0 (tsize);
769 if (!((table->num_misc_tables + 1) % MISC_TABLE_PTR_CHUNK_SIZE)) {
770 guint32 chunks = (table->num_misc_tables + 1) / MISC_TABLE_PTR_CHUNK_SIZE;
771 guint32 tsize = sizeof (gpointer) * MISC_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
773 table->misc_tables = g_realloc (table->misc_tables, tsize);
776 table->misc_tables [table->num_misc_tables++] = table->current_misc_table;
778 /* .... allocate a new current_misc_table. */
779 table->current_misc_table = g_malloc0 (MISC_TABLE_CHUNK_SIZE);
780 table->misc_table_start = table->misc_table_offset = table->misc_table_size;
781 table->misc_table_size += MISC_TABLE_CHUNK_SIZE;
783 goto again;
786 static gboolean
787 property_is_static (MonoProperty *prop)
789 MonoMethod *method;
791 method = prop->get;
792 if (!method)
793 method = prop->set;
795 return method->flags & METHOD_ATTRIBUTE_STATIC;
798 static gboolean
799 event_is_static (MonoEvent *ev)
801 MonoMethod *method;
803 method = ev->add;
805 return method->flags & METHOD_ATTRIBUTE_STATIC;
808 static guint32
809 do_write_class (MonoDebuggerSymbolTable *table, MonoClass *klass, MonoDebuggerClassInfo *cinfo)
811 guint8 buffer [BUFSIZ], *ptr = buffer, *old_ptr;
812 GPtrArray *methods = NULL, *static_methods = NULL, *ctors = NULL, *cctors = NULL;
813 int num_fields = 0, num_static_fields = 0, num_properties = 0, num_static_properties = 0;
814 int num_events = 0, num_static_events = 0;
815 int num_methods = 0, num_static_methods = 0, num_params = 0, num_static_params = 0, base_offset = 0;
816 int num_ctors = 0, num_ctor_params = 0;
817 int num_cctors = 0;
818 int field_info_size = 0, static_field_info_size = 0, property_info_size = 0, event_info_size = 0, static_event_info_size = 0;
819 int static_property_info_size = 0, method_info_size = 0, static_method_info_size = 0;
820 int ctor_info_size = 0, cctor_info_size = 0, iface_info_size = 0;
821 guint32 size, data_size, offset, data_offset;
822 GHashTable *method_slots = NULL;
823 int i;
825 if (klass->init_pending)
826 g_warning (G_STRLOC ": %p - %s.%s", klass, klass->name_space, klass->name);
827 g_assert (!klass->init_pending);
828 mono_class_init (klass);
830 offset = GPOINTER_TO_UINT (g_hash_table_lookup (class_table, klass));
831 if (offset)
832 return offset;
834 if (klass->enumtype) {
835 offset = allocate_type_entry (table, 13, &ptr);
836 if (cinfo)
837 cinfo->type_info = offset;
838 g_hash_table_insert (class_table, klass, GUINT_TO_POINTER (offset));
840 *ptr++ = MONO_DEBUGGER_TYPE_KIND_ENUM;
841 WRITE_UINT32 (ptr, klass->instance_size);
842 WRITE_UINT32 (ptr, MONO_DEBUGGER_TYPE_ENUM);
843 WRITE_UINT32 (ptr, write_type (table, klass->enum_basetype));
844 return offset;
847 for (i = 0; i < klass->field.count; i++)
848 if (!(klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
849 ++num_fields;
850 else
851 ++num_static_fields;
853 for (i = 0; i < klass->property.count; i++)
854 if (!property_is_static (&klass->properties [i]))
855 ++num_properties;
856 else
857 ++num_static_properties;
859 for (i = 0; i < klass->event.count; i++)
860 if (!event_is_static (&klass->events [i]))
861 ++num_events;
862 else
863 ++num_static_events;
865 method_slots = g_hash_table_new (NULL, NULL);
866 methods = g_ptr_array_new ();
867 static_methods = g_ptr_array_new ();
868 ctors = g_ptr_array_new ();
869 cctors = g_ptr_array_new ();
871 for (i = 0; i < klass->method.count; i++) {
872 MonoMethod *method = klass->methods [i];
874 if (!strcmp (method->name, ".cctor")) {
875 ++num_cctors;
876 g_ptr_array_add (cctors, method);
877 continue;
880 if (!strcmp (method->name, ".ctor")) {
881 ++num_ctors;
882 num_ctor_params += method->signature->param_count;
883 g_ptr_array_add (ctors, method);
884 continue;
887 if (method->flags & METHOD_ATTRIBUTE_SPECIAL_NAME)
888 continue;
890 if (method->slot != -1) {
891 if (g_hash_table_lookup (method_slots, GUINT_TO_POINTER (method->slot)))
892 continue;
893 g_hash_table_insert (method_slots, GUINT_TO_POINTER (method->slot), method);
896 if (method->flags & METHOD_ATTRIBUTE_STATIC) {
897 ++num_static_methods;
898 num_static_params += method->signature->param_count;
899 g_ptr_array_add (static_methods, method);
900 } else {
901 ++num_methods;
902 num_params += method->signature->param_count;
903 g_ptr_array_add (methods, method);
907 g_hash_table_destroy (method_slots);
909 field_info_size = num_fields * 8;
910 static_field_info_size = num_static_fields * 8;
911 property_info_size = num_properties * (4 + 2 * sizeof (gpointer));
912 static_property_info_size = num_static_properties * (4 + 2 * sizeof (gpointer));
913 event_info_size = num_events * (4 + 2 * sizeof (gpointer));
914 static_event_info_size = num_static_events * (4 + 2 * sizeof (gpointer));
915 method_info_size = num_methods * (2 * 4 + sizeof (gpointer)) + num_params * 4;
916 static_method_info_size = num_static_methods * (2 * 4 + sizeof (gpointer)) +
917 num_static_params * 4;
918 ctor_info_size = num_ctors * (2 * 4 + sizeof (gpointer)) + num_ctor_params * 4;
919 cctor_info_size = num_cctors * (2 * 4 + sizeof (gpointer));
920 iface_info_size = klass->interface_count * 4;
922 size = 98 + sizeof (gpointer) + field_info_size + static_field_info_size +
923 property_info_size + static_property_info_size + event_info_size +
924 static_event_info_size + method_info_size + static_method_info_size +
925 ctor_info_size + cctor_info_size + iface_info_size;
927 data_size = size;
929 offset = allocate_type_entry (table, data_size, &ptr);
930 old_ptr = ptr;
932 if (cinfo)
933 cinfo->type_info = offset;
935 g_hash_table_insert (class_table, klass, GUINT_TO_POINTER (offset));
937 *ptr++ = MONO_DEBUGGER_TYPE_KIND_CLASS_INFO;
939 if (klass->valuetype)
940 base_offset = - sizeof (MonoObject);
942 WRITE_UINT32 (ptr, klass->instance_size + base_offset);
943 *ptr++ = klass->valuetype;
944 WRITE_POINTER (ptr, klass);
945 data_offset = 0;
946 WRITE_UINT32 (ptr, num_fields);
947 WRITE_UINT32 (ptr, data_offset);
948 data_offset += field_info_size;
949 WRITE_UINT32 (ptr, num_properties);
950 WRITE_UINT32 (ptr, data_offset);
951 data_offset += property_info_size;
952 WRITE_UINT32 (ptr, num_events);
953 WRITE_UINT32 (ptr, data_offset);
954 data_offset += event_info_size;
955 WRITE_UINT32 (ptr, num_methods);
956 WRITE_UINT32 (ptr, data_offset);
957 data_offset += method_info_size;
958 WRITE_UINT32 (ptr, num_static_fields);
959 WRITE_UINT32 (ptr, data_offset);
960 data_offset += static_field_info_size;
961 WRITE_UINT32 (ptr, num_static_properties);
962 WRITE_UINT32 (ptr, data_offset);
963 data_offset += static_property_info_size;
964 WRITE_UINT32 (ptr, num_static_events);
965 WRITE_UINT32 (ptr, data_offset);
966 data_offset += static_event_info_size;
967 WRITE_UINT32 (ptr, num_static_methods);
968 WRITE_UINT32 (ptr, data_offset);
969 data_offset += static_method_info_size;
970 WRITE_UINT32 (ptr, num_ctors);
971 WRITE_UINT32 (ptr, data_offset);
972 data_offset += ctor_info_size;
973 WRITE_UINT32 (ptr, num_cctors);
974 WRITE_UINT32 (ptr, data_offset);
975 data_offset += cctor_info_size;
976 WRITE_UINT32 (ptr, klass->interface_count);
977 WRITE_UINT32 (ptr, data_offset);
978 data_offset += iface_info_size;
980 if (klass->parent && (klass->parent != mono_defaults.object_class))
981 WRITE_UINT32 (ptr, write_class (table, klass->parent));
982 else
983 WRITE_UINT32 (ptr, 0);
985 for (i = 0; i < klass->field.count; i++) {
986 if (klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC)
987 continue;
989 WRITE_UINT32 (ptr, klass->fields [i].offset + base_offset);
990 WRITE_UINT32 (ptr, write_type (table, klass->fields [i].type));
993 for (i = 0; i < klass->property.count; i++) {
994 if (property_is_static (&klass->properties [i]))
995 continue;
997 if (klass->properties [i].get)
998 WRITE_UINT32 (ptr, write_type (table, klass->properties [i].get->signature->ret));
999 else
1000 WRITE_UINT32 (ptr, 0);
1001 WRITE_POINTER (ptr, klass->properties [i].get);
1002 WRITE_POINTER (ptr, klass->properties [i].set);
1005 for (i = 0; i < klass->event.count; i++) {
1006 if (event_is_static (&klass->events[i]))
1007 continue;
1009 if (klass->events [i].add) {
1010 WRITE_UINT32 (ptr, write_type (table, klass->events [i].add->signature->params[0]));
1012 else {
1013 g_warning ("event add method not defined");
1014 WRITE_UINT32 (ptr, 0);
1016 WRITE_POINTER (ptr, klass->events [i].add);
1017 WRITE_POINTER (ptr, klass->events [i].remove);
1018 /* raise? other? */
1021 for (i = 0; i < methods->len; i++) {
1022 MonoMethod *method = g_ptr_array_index (methods, i);
1023 int j;
1025 WRITE_POINTER (ptr, method);
1026 if ((method->signature->ret) && (method->signature->ret->type != MONO_TYPE_VOID))
1027 WRITE_UINT32 (ptr, write_type (table, method->signature->ret));
1028 else
1029 WRITE_UINT32 (ptr, 0);
1030 WRITE_UINT32 (ptr, method->signature->param_count);
1031 for (j = 0; j < method->signature->param_count; j++)
1032 WRITE_UINT32 (ptr, write_type (table, method->signature->params [j]));
1035 g_ptr_array_free (methods, FALSE);
1037 for (i = 0; i < klass->field.count; i++) {
1038 if (!(klass->fields [i].type->attrs & FIELD_ATTRIBUTE_STATIC))
1039 continue;
1041 WRITE_UINT32 (ptr, klass->fields [i].offset);
1042 WRITE_UINT32 (ptr, write_type (table, klass->fields [i].type));
1045 for (i = 0; i < klass->property.count; i++) {
1046 if (!property_is_static (&klass->properties [i]))
1047 continue;
1049 if (klass->properties [i].get)
1050 WRITE_UINT32 (ptr, write_type (table, klass->properties [i].get->signature->ret));
1051 else
1052 WRITE_UINT32 (ptr, 0);
1053 WRITE_POINTER (ptr, klass->properties [i].get);
1054 WRITE_POINTER (ptr, klass->properties [i].set);
1057 for (i = 0; i < klass->event.count; i++) {
1058 if (!event_is_static (&klass->events[i]))
1059 continue;
1061 if (klass->events [i].add) {
1062 WRITE_UINT32 (ptr, write_type (table, klass->events [i].add->signature->params[0]));
1064 else {
1065 g_warning ("event add method not defined");
1066 WRITE_UINT32 (ptr, 0);
1068 WRITE_POINTER (ptr, klass->events [i].add);
1069 WRITE_POINTER (ptr, klass->events [i].remove);
1070 /* raise? other? */
1073 for (i = 0; i < static_methods->len; i++) {
1074 MonoMethod *method = g_ptr_array_index (static_methods, i);
1075 int j;
1077 WRITE_POINTER (ptr, method);
1078 if ((method->signature->ret) && (method->signature->ret->type != MONO_TYPE_VOID))
1079 WRITE_UINT32 (ptr, write_type (table, method->signature->ret));
1080 else
1081 WRITE_UINT32 (ptr, 0);
1082 WRITE_UINT32 (ptr, method->signature->param_count);
1083 for (j = 0; j < method->signature->param_count; j++)
1084 WRITE_UINT32 (ptr, write_type (table, method->signature->params [j]));
1087 g_ptr_array_free (static_methods, FALSE);
1089 for (i = 0; i < ctors->len; i++) {
1090 MonoMethod *ctor = g_ptr_array_index (ctors, i);
1091 int j;
1093 WRITE_POINTER (ptr, ctor);
1094 WRITE_UINT32 (ptr, 0);
1095 WRITE_UINT32 (ptr, ctor->signature->param_count);
1096 for (j = 0; j < ctor->signature->param_count; j++)
1097 WRITE_UINT32 (ptr, write_type (table, ctor->signature->params [j]));
1100 g_ptr_array_free (ctors, FALSE);
1102 for (i = 0; i < cctors->len; i++) {
1103 MonoMethod *cctor = g_ptr_array_index (cctors, i);
1105 WRITE_POINTER (ptr, cctor);
1106 WRITE_UINT32 (ptr, 0);
1107 WRITE_UINT32 (ptr, 0);
1110 g_ptr_array_free (cctors, FALSE);
1112 for (i = 0; i < klass->interface_count; i++)
1113 WRITE_UINT32 (ptr, write_class (table, klass->interfaces [i]));
1115 if (ptr - old_ptr != data_size) {
1116 g_warning (G_STRLOC ": %d,%d,%d", ptr - old_ptr, data_size, sizeof (gpointer));
1117 if (klass)
1118 g_warning (G_STRLOC ": %s.%s", klass->name_space, klass->name);
1119 g_assert_not_reached ();
1122 return offset;
1126 * Adds type `type' to the type table and returns its offset.
1128 static guint32
1129 write_type (MonoDebuggerSymbolTable *table, MonoType *type)
1131 guint8 buffer [BUFSIZ], *ptr = buffer;
1132 guint32 size, offset;
1133 MonoClass *klass;
1135 offset = GPOINTER_TO_UINT (g_hash_table_lookup (type_table, type));
1136 if (offset)
1137 return offset;
1139 klass = mono_class_from_mono_type (type);
1140 if (type->type == MONO_TYPE_CLASS)
1141 return write_class (table, klass);
1143 // mono_class_init (klass);
1145 switch (type->type) {
1146 case MONO_TYPE_VOID:
1147 return MONO_DEBUGGER_TYPE_VOID;
1149 case MONO_TYPE_BOOLEAN:
1150 return MONO_DEBUGGER_TYPE_BOOLEAN;
1152 case MONO_TYPE_I1:
1153 return MONO_DEBUGGER_TYPE_I1;
1155 case MONO_TYPE_U1:
1156 return MONO_DEBUGGER_TYPE_U1;
1158 case MONO_TYPE_CHAR:
1159 return MONO_DEBUGGER_TYPE_CHAR;
1161 case MONO_TYPE_I2:
1162 return MONO_DEBUGGER_TYPE_I2;
1164 case MONO_TYPE_U2:
1165 return MONO_DEBUGGER_TYPE_U2;
1167 case MONO_TYPE_I4:
1168 return MONO_DEBUGGER_TYPE_I4;
1170 case MONO_TYPE_U4:
1171 return MONO_DEBUGGER_TYPE_U4;
1173 case MONO_TYPE_I8:
1174 return MONO_DEBUGGER_TYPE_I8;
1176 case MONO_TYPE_U8:
1177 return MONO_DEBUGGER_TYPE_U8;
1179 case MONO_TYPE_R4:
1180 return MONO_DEBUGGER_TYPE_R4;
1182 case MONO_TYPE_R8:
1183 return MONO_DEBUGGER_TYPE_R8;
1185 case MONO_TYPE_STRING:
1186 return MONO_DEBUGGER_TYPE_STRING;
1188 case MONO_TYPE_I:
1189 return MONO_DEBUGGER_TYPE_I;
1191 case MONO_TYPE_U:
1192 return MONO_DEBUGGER_TYPE_U;
1194 case MONO_TYPE_SZARRAY: {
1195 MonoArray array;
1197 *ptr++ = MONO_DEBUGGER_TYPE_KIND_SZARRAY;
1198 WRITE_UINT32 (ptr, sizeof (MonoArray));
1199 WRITE_UINT32 (ptr, MONO_DEBUGGER_TYPE_ARRAY);
1200 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
1201 *ptr++ = sizeof (array.max_length);
1202 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
1203 WRITE_UINT32 (ptr, write_type (table, &type->data.klass->byval_arg));
1204 break;
1207 case MONO_TYPE_ARRAY: {
1208 MonoArray array;
1209 MonoArrayBounds bounds;
1211 *ptr++ = MONO_DEBUGGER_TYPE_KIND_ARRAY;
1212 WRITE_UINT32 (ptr, sizeof (MonoArray));
1213 WRITE_UINT32 (ptr, MONO_DEBUGGER_TYPE_ARRAY);
1214 *ptr++ = (guint8*)&array.max_length - (guint8*)&array;
1215 *ptr++ = sizeof (array.max_length);
1216 *ptr++ = (guint8*)&array.vector - (guint8*)&array;
1217 *ptr++ = klass->rank;
1218 *ptr++ = (guint8*)&array.bounds - (guint8*)&array;
1219 *ptr++ = sizeof (MonoArrayBounds);
1220 *ptr++ = (guint8*)&bounds.lower_bound - (guint8*)&bounds;
1221 *ptr++ = sizeof (bounds.lower_bound);
1222 *ptr++ = (guint8*)&bounds.length - (guint8*)&bounds;
1223 *ptr++ = sizeof (bounds.length);
1224 WRITE_UINT32 (ptr, write_type (table, &type->data.array->eklass->byval_arg));
1225 break;
1228 case MONO_TYPE_VALUETYPE:
1229 case MONO_TYPE_CLASS:
1230 case MONO_TYPE_GENERICINST:
1231 case MONO_TYPE_OBJECT:
1232 return write_class (table, klass);
1234 case MONO_TYPE_PTR:
1235 *ptr++ = MONO_DEBUGGER_TYPE_KIND_POINTER;
1236 WRITE_UINT32 (ptr, sizeof (gpointer));
1237 WRITE_UINT32 (ptr, write_type (table, type->data.type));
1238 break;
1240 default:
1241 /* g_message (G_STRLOC ": %s.%s - %p - %d", klass->name_space, klass->name, klass, type->type); */
1242 *ptr++ = MONO_DEBUGGER_TYPE_KIND_UNKNOWN;
1243 WRITE_UINT32 (ptr, klass->instance_size);
1244 WRITE_UINT32 (ptr, write_class (table, klass));
1245 break;
1248 size = ptr - buffer;
1249 offset = allocate_type_entry (mono_debugger_symbol_table, size, &ptr);
1250 memcpy (ptr, buffer, size);
1252 return offset;
1255 MonoReflectionMethod *
1256 ves_icall_MonoDebugger_GetMethod (MonoReflectionAssembly *assembly, guint32 token)
1258 MonoMethod *method;
1260 method = mono_get_method (mono_assembly_get_image (assembly->assembly), token, NULL);
1262 return mono_method_get_object (mono_domain_get (), method, NULL);
1266 ves_icall_MonoDebugger_GetMethodToken (MonoReflectionAssembly *assembly, MonoReflectionMethod *method)
1268 return method->method->token;
1271 MonoReflectionType *
1272 ves_icall_MonoDebugger_GetType (MonoReflectionAssembly *assembly, guint32 token)
1274 MonoClass *klass;
1276 klass = mono_class_get (mono_assembly_get_image (assembly->assembly), token);
1277 if (!klass) {
1278 g_warning (G_STRLOC ": %x", token);
1279 return NULL;
1282 return mono_type_get_object (mono_domain_get (), &klass->byval_arg);
1285 MonoReflectionType *
1286 ves_icall_MonoDebugger_GetLocalTypeFromSignature (MonoReflectionAssembly *assembly, MonoArray *signature)
1288 MonoDomain *domain;
1289 MonoImage *image;
1290 MonoType *type;
1291 const char *ptr;
1292 int len = 0;
1294 MONO_CHECK_ARG_NULL (assembly);
1295 MONO_CHECK_ARG_NULL (signature);
1297 domain = mono_domain_get();
1298 image = mono_assembly_get_image (assembly->assembly);
1300 ptr = mono_array_addr (signature, char, 0);
1301 g_assert (*ptr++ == 0x07);
1302 len = mono_metadata_decode_value (ptr, &ptr);
1303 g_assert (len == 1);
1305 type = mono_metadata_parse_type (image, MONO_PARSE_LOCAL, 0, ptr, &ptr);
1307 return mono_type_get_object (domain, type);
1310 void
1311 mono_debugger_event (MonoDebuggerEvent event, gpointer data, guint32 arg)
1313 if (mono_debugger_event_handler)
1314 (* mono_debugger_event_handler) (event, data, arg);
1317 void
1318 mono_debugger_cleanup (void)
1320 /* Do nothing yet. */
1324 * Debugger breakpoint interface.
1326 * This interface is used to insert breakpoints on methods which are not yet JITed.
1327 * The debugging code keeps a list of all such breakpoints and automatically inserts the
1328 * breakpoint when the method is JITed.
1331 static GPtrArray *breakpoints = NULL;
1334 mono_debugger_insert_breakpoint_full (MonoMethodDesc *desc)
1336 static int last_breakpoint_id = 0;
1337 MonoDebuggerBreakpointInfo *info;
1339 info = g_new0 (MonoDebuggerBreakpointInfo, 1);
1340 info->desc = desc;
1341 info->index = ++last_breakpoint_id;
1343 if (!breakpoints)
1344 breakpoints = g_ptr_array_new ();
1346 g_ptr_array_add (breakpoints, info);
1348 return info->index;
1352 mono_debugger_remove_breakpoint (int breakpoint_id)
1354 int i;
1356 if (!breakpoints)
1357 return 0;
1359 for (i = 0; i < breakpoints->len; i++) {
1360 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
1362 if (info->index != breakpoint_id)
1363 continue;
1365 mono_method_desc_free (info->desc);
1366 g_ptr_array_remove (breakpoints, info);
1367 g_free (info);
1368 return 1;
1371 return 0;
1375 mono_debugger_insert_breakpoint (const gchar *method_name, gboolean include_namespace)
1377 MonoMethodDesc *desc;
1379 desc = mono_method_desc_new (method_name, include_namespace);
1380 if (!desc)
1381 return 0;
1383 return mono_debugger_insert_breakpoint_full (desc);
1387 mono_debugger_method_has_breakpoint (MonoMethod *method)
1389 int i;
1391 if (!breakpoints || (method->wrapper_type != MONO_WRAPPER_NONE))
1392 return 0;
1394 for (i = 0; i < breakpoints->len; i++) {
1395 MonoDebuggerBreakpointInfo *info = g_ptr_array_index (breakpoints, i);
1397 if (!mono_method_desc_full_match (info->desc, method))
1398 continue;
1400 return info->index;
1403 return 0;
1406 void
1407 mono_debugger_breakpoint_callback (MonoMethod *method, guint32 index)
1409 mono_debugger_event (MONO_DEBUGGER_EVENT_BREAKPOINT, method, index);
1412 gboolean
1413 mono_debugger_unhandled_exception (gpointer addr, gpointer stack, MonoObject *exc)
1415 if (!mono_debugger_initialized)
1416 return FALSE;
1418 // Prevent the object from being finalized.
1419 last_exception = exc;
1420 mono_debugger_event (MONO_DEBUGGER_EVENT_UNHANDLED_EXCEPTION, exc, addr);
1421 return TRUE;
1424 void
1425 mono_debugger_handle_exception (gpointer addr, gpointer stack, MonoObject *exc)
1427 MonoDebuggerExceptionInfo info;
1429 if (!mono_debugger_initialized)
1430 return;
1432 // Prevent the object from being finalized.
1433 last_exception = exc;
1435 info.stack_pointer = stack;
1436 info.exception_obj = exc;
1437 info.stop = 0;
1439 mono_debugger_event (MONO_DEBUGGER_EVENT_EXCEPTION, &info, addr);
1442 gboolean
1443 mono_debugger_throw_exception (gpointer addr, gpointer stack, MonoObject *exc)
1445 MonoDebuggerExceptionInfo info;
1447 if (!mono_debugger_initialized)
1448 return FALSE;
1450 // Prevent the object from being finalized.
1451 last_exception = exc;
1453 info.stack_pointer = stack;
1454 info.exception_obj = exc;
1455 info.stop = 0;
1457 mono_debugger_event (MONO_DEBUGGER_EVENT_THROW_EXCEPTION, &info, addr);
1458 return info.stop != 0;
1461 static gchar *
1462 get_exception_message (MonoObject *exc)
1464 char *message = NULL;
1465 MonoString *str;
1466 MonoMethod *method;
1467 MonoClass *klass;
1468 gint i;
1470 if (mono_object_isinst (exc, mono_defaults.exception_class)) {
1471 klass = exc->vtable->klass;
1472 method = NULL;
1473 while (klass && method == NULL) {
1474 for (i = 0; i < klass->method.count; ++i) {
1475 method = klass->methods [i];
1476 if (!strcmp ("ToString", method->name) &&
1477 method->signature->param_count == 0 &&
1478 method->flags & METHOD_ATTRIBUTE_VIRTUAL &&
1479 method->flags & METHOD_ATTRIBUTE_PUBLIC) {
1480 break;
1482 method = NULL;
1485 if (method == NULL)
1486 klass = klass->parent;
1489 g_assert (method);
1491 str = (MonoString *) mono_runtime_invoke (method, exc, NULL, NULL);
1492 if (str)
1493 message = mono_string_to_utf8 (str);
1496 return message;
1499 MonoObject *
1500 mono_debugger_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **exc)
1502 MonoObject *retval;
1503 gchar *message;
1505 if (!strcmp (method->name, ".ctor")) {
1506 retval = obj = mono_object_new (mono_domain_get (), method->klass);
1508 mono_runtime_invoke (method, obj, params, exc);
1509 } else
1510 retval = mono_runtime_invoke (method, obj, params, exc);
1512 if (!exc || (*exc == NULL))
1513 return retval;
1515 message = get_exception_message (*exc);
1516 if (message) {
1517 *exc = (MonoObject *) mono_string_new_wrapper (message);
1518 g_free (message);
1521 return retval;
1524 guint32
1525 mono_debugger_lookup_type (const gchar *type_name)
1527 int i;
1529 mono_debugger_lock ();
1531 for (i = 0; i < mono_debugger_symbol_table->num_symbol_files; i++) {
1532 MonoDebuggerSymbolFile *symfile = mono_debugger_symbol_table->symbol_files [i];
1533 MonoType *type;
1534 guint32 offset;
1535 gchar *name;
1537 name = g_strdup (type_name);
1538 type = mono_reflection_type_from_name (name, symfile->image);
1539 g_free (name);
1540 if (!type)
1541 continue;
1543 offset = write_type (mono_debugger_symbol_table, type);
1545 mono_debugger_unlock ();
1546 return offset;
1549 mono_debugger_unlock ();
1550 return 0;
1553 gint32
1554 mono_debugger_lookup_assembly (const gchar *name)
1556 MonoAssembly *assembly;
1557 MonoImageOpenStatus status;
1558 int i;
1560 mono_debugger_lock ();
1562 again:
1563 for (i = 0; i < mono_debugger_symbol_table->num_symbol_files; i++) {
1564 MonoDebuggerSymbolFile *symfile = mono_debugger_symbol_table->symbol_files [i];
1566 if (!strcmp (symfile->image_file, name)) {
1567 mono_debugger_unlock ();
1568 return i;
1572 assembly = mono_assembly_open (name, &status);
1574 if (status != MONO_IMAGE_OK) {
1575 g_warning (G_STRLOC ": Cannot open image `%s'", name);
1576 mono_debugger_unlock ();
1577 return -1;
1580 must_reload_symtabs = TRUE;
1581 goto again;
1584 void
1585 mono_debugger_add_wrapper (MonoMethod *wrapper, MonoDebugMethodJitInfo *jit, gpointer addr)
1587 guint32 size, offset;
1588 guint8 *ptr;
1590 if (!mono_debugger_symbol_table)
1591 return;
1593 size = strlen (wrapper->name) + 5 + 5 * sizeof (gpointer);
1595 offset = allocate_misc_entry (mono_debugger_symbol_table, size, &ptr);
1597 WRITE_UINT32 (ptr, MONO_DEBUGGER_MISC_ENTRY_TYPE_WRAPPER);
1598 WRITE_STRING (ptr, wrapper->name);
1599 WRITE_POINTER (ptr, jit->code_start);
1600 WRITE_POINTER (ptr, jit->code_start + jit->code_size);
1601 WRITE_POINTER (ptr, addr);
1602 WRITE_POINTER (ptr, jit->code_start + jit->prologue_end);
1603 WRITE_POINTER (ptr, jit->code_start + jit->epilogue_begin);