2 #include <mono/metadata/assembly.h>
3 #include <mono/metadata/tabledefs.h>
4 #include <mono/metadata/tokentype.h>
5 #include <mono/metadata/appdomain.h>
6 #include <mono/metadata/class-internals.h>
7 #include <mono/metadata/mono-debug.h>
8 #include <mono/metadata/mono-debug-debugger.h>
9 #include <mono/metadata/mono-endian.h>
12 #define SYMFILE_TABLE_CHUNK_SIZE 16
13 #define DATA_TABLE_PTR_CHUNK_SIZE 256
14 #define DATA_TABLE_CHUNK_SIZE 131072
16 MonoSymbolTable *mono_symbol_table = NULL;
17 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
19 static gboolean in_the_mono_debugger = FALSE;
20 static gboolean mono_debug_initialized = FALSE;
21 GHashTable *mono_debug_handles = NULL;
23 static GHashTable *method_hash = NULL;
25 static MonoDebugHandle *mono_debug_open_image (MonoImage *image);
26 static void mono_debug_close_image (MonoDebugHandle *debug);
28 static MonoDebugHandle *_mono_debug_get_image (MonoImage *image);
29 static void mono_debug_add_assembly (MonoAssembly *assembly,
31 static void mono_debug_start_add_type (MonoClass *klass);
32 static void mono_debug_add_type (MonoClass *klass);
34 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
35 extern void (*mono_debugger_start_class_init_func) (MonoClass *klass);
44 method_hash_hash (gconstpointer data)
46 const MethodHashEntry *entry = (const MethodHashEntry *) data;
47 return entry->symfile_id | (entry->domain_id << 16);
51 method_hash_equal (gconstpointer ka, gconstpointer kb)
53 const MethodHashEntry *a = (const MethodHashEntry *) ka;
54 const MethodHashEntry *b = (const MethodHashEntry *) kb;
56 if ((a->symfile_id != b->symfile_id) || (a->method_id != b->method_id) || (a->domain_id != b->domain_id))
62 * Initialize debugging support.
64 * This method must be called after loading corlib,
65 * but before opening the application's main assembly because we need to set some
69 mono_debug_init (MonoDebugFormat format)
71 g_assert (!mono_debug_initialized);
73 mono_debug_initialized = TRUE;
74 mono_debug_format = format;
75 in_the_mono_debugger = format == MONO_DEBUG_FORMAT_DEBUGGER;
77 if (in_the_mono_debugger)
78 mono_debugger_initialize ();
80 mono_debugger_lock ();
82 mono_symbol_table = g_new0 (MonoSymbolTable, 1);
83 mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
84 mono_symbol_table->version = MONO_DEBUGGER_VERSION;
85 mono_symbol_table->total_size = sizeof (MonoSymbolTable);
87 mono_debug_handles = g_hash_table_new_full
88 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
89 method_hash = g_hash_table_new (method_hash_hash, method_hash_equal);
91 mono_debugger_start_class_init_func = mono_debug_start_add_type;
92 mono_debugger_class_init_func = mono_debug_add_type;
93 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
97 mono_debug_init_1 (MonoDomain *domain)
99 MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
101 if (in_the_mono_debugger)
102 mono_debugger_add_builtin_types (handle);
106 * Initialize debugging support - part 2.
108 * This method must be called after loading the application's main assembly.
111 mono_debug_init_2 (MonoAssembly *assembly)
113 mono_debug_open_image (mono_assembly_get_image (assembly));
117 mono_debug_cleanup (void)
119 mono_debugger_cleanup ();
121 if (mono_debug_handles)
122 g_hash_table_destroy (mono_debug_handles);
123 mono_debug_handles = NULL;
126 static MonoDebugHandle *
127 _mono_debug_get_image (MonoImage *image)
129 return g_hash_table_lookup (mono_debug_handles, image);
132 static MonoDebugHandle *
133 allocate_debug_handle (MonoSymbolTable *table)
135 MonoDebugHandle *handle;
137 if (!table->symbol_files)
138 table->symbol_files = g_new0 (MonoDebugHandle *, SYMFILE_TABLE_CHUNK_SIZE);
139 else if (!((table->num_symbol_files + 1) % SYMFILE_TABLE_CHUNK_SIZE)) {
140 guint32 chunks = (table->num_symbol_files + 1) / SYMFILE_TABLE_CHUNK_SIZE;
141 guint32 size = sizeof (MonoDebugHandle *) * SYMFILE_TABLE_CHUNK_SIZE * (chunks + 1);
143 table->symbol_files = g_realloc (table->symbol_files, size);
146 handle = g_new0 (MonoDebugHandle, 1);
147 handle->index = table->num_symbol_files;
148 table->symbol_files [table->num_symbol_files++] = handle;
152 static MonoDebugHandle *
153 mono_debug_open_image (MonoImage *image)
155 MonoDebugHandle *handle;
157 handle = _mono_debug_get_image (image);
161 handle = allocate_debug_handle (mono_symbol_table);
163 handle->image = image;
164 mono_image_addref (image);
165 handle->image_file = g_strdup (mono_image_get_filename (image));
167 g_hash_table_insert (mono_debug_handles, image, handle);
169 if (mono_image_is_dynamic (image))
172 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
173 if (in_the_mono_debugger)
174 mono_debugger_add_symbol_file (handle);
180 mono_debug_close_image (MonoDebugHandle *handle)
183 mono_debug_close_mono_symbol_file (handle->symfile);
184 /* decrease the refcount added with mono_image_addref () */
185 mono_image_close (handle->image);
186 /* FIXME: should also free handle->image_file? */
187 g_free (handle->_priv);
192 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
194 mono_debugger_lock ();
195 mono_debug_open_image (mono_assembly_get_image (assembly));
196 mono_debugger_unlock ();
200 * Allocate a new data item of size `size'.
201 * Returns the global offset which is to be used to reference this data item and
202 * a pointer (in the `ptr' argument) which is to be used to write it.
205 allocate_data_item (MonoSymbolTable *table, MonoDebugDataItemType type, guint32 size, guint8 **ptr)
210 g_assert (size + 8 < DATA_TABLE_CHUNK_SIZE);
211 g_assert (ptr != NULL);
213 /* Initialize things if necessary. */
214 if (!table->current_data_table) {
215 table->current_data_table = g_malloc0 (DATA_TABLE_CHUNK_SIZE);
216 table->data_table_size = DATA_TABLE_CHUNK_SIZE;
217 table->data_table_chunk_size = DATA_TABLE_CHUNK_SIZE;
218 table->data_table_offset = 0;
222 /* First let's check whether there's still enough room in the current_data_table. */
223 if (table->data_table_offset + size + 8 < table->data_table_size) {
224 retval = table->data_table_offset;
225 table->data_table_offset += size + 8;
226 data = ((guint8 *) table->current_data_table) + retval - table->data_table_start;
227 * ((guint32 *) data) = size;
229 * ((guint32 *) data) = type;
235 /* Add the current_data_table to the data_tables vector and ... */
236 if (!table->data_tables) {
237 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE;
238 table->data_tables = g_malloc0 (tsize);
241 if (!((table->num_data_tables + 1) % DATA_TABLE_PTR_CHUNK_SIZE)) {
242 guint32 chunks = (table->num_data_tables + 1) / DATA_TABLE_PTR_CHUNK_SIZE;
243 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
245 table->data_tables = g_realloc (table->data_tables, tsize);
248 table->data_tables [table->num_data_tables++] = table->current_data_table;
250 /* .... allocate a new current_data_table. */
251 table->current_data_table = g_malloc0 (DATA_TABLE_CHUNK_SIZE);
252 table->data_table_start = table->data_table_offset = table->data_table_size;
253 table->data_table_size += DATA_TABLE_CHUNK_SIZE;
258 struct LookupMethodData
260 MonoDebugMethodInfo *minfo;
265 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
267 MonoDebugHandle *handle = (MonoDebugHandle *) value;
268 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
274 data->minfo = mono_debug_find_method (handle, data->method);
277 static MonoDebugMethodInfo *
278 _mono_debug_lookup_method (MonoMethod *method)
280 struct LookupMethodData data;
283 data.method = method;
285 if (!mono_debug_handles)
288 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
293 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
296 guint8 byte = value & 0x7f;
307 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
312 guint8 byte = value & 0x7f;
315 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
326 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
328 write_leb128 (var->index, ptr, &ptr);
329 write_sleb128 (var->offset, ptr, &ptr);
330 write_leb128 (var->size, ptr, &ptr);
331 write_leb128 (var->begin_scope, ptr, &ptr);
332 write_leb128 (var->end_scope, ptr, &ptr);
337 * This is called by the JIT to tell the debugging code about a newly
340 MonoDebugMethodAddress *
341 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
343 MonoDebugMethodAddress *address;
344 char buffer [BUFSIZ];
345 guint8 *ptr, *oldptr;
346 guint32 i, size, total_size, max_size;
347 gint32 last_il_offset = 0, last_native_offset = 0;
348 MonoDebugHandle *handle;
349 MonoDebugMethodInfo *minfo;
350 MethodHashEntry *hash;
352 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
353 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
354 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
355 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
358 if (method->wrapper_type != MONO_WRAPPER_NONE)
361 mono_debugger_lock ();
363 handle = _mono_debug_get_image (method->klass->image);
364 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
365 mono_debugger_unlock ();
369 minfo = _mono_debug_lookup_method (method);
371 mono_debugger_unlock ();
375 max_size = 24 + 8 * jit->num_line_numbers + 20 * (1 + jit->num_params + jit->num_locals);
376 if (max_size > BUFSIZ)
377 ptr = oldptr = g_malloc (max_size);
379 ptr = oldptr = buffer;
381 write_leb128 (jit->prologue_end, ptr, &ptr);
382 write_leb128 (jit->epilogue_begin, ptr, &ptr);
384 write_leb128 (jit->num_line_numbers, ptr, &ptr);
385 for (i = 0; i < jit->num_line_numbers; i++) {
386 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
388 write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
389 write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
391 last_il_offset = lne->il_offset;
392 last_native_offset = lne->native_offset;
395 *ptr++ = jit->this_var ? 1 : 0;
397 write_variable (jit->this_var, ptr, &ptr);
399 write_leb128 (jit->num_params, ptr, &ptr);
400 for (i = 0; i < jit->num_params; i++)
401 write_variable (&jit->params [i], ptr, &ptr);
403 write_leb128 (jit->num_locals, ptr, &ptr);
404 for (i = 0; i < jit->num_locals; i++)
405 write_variable (&jit->locals [i], ptr, &ptr);
408 g_assert (size < max_size);
409 total_size = size + sizeof (MonoDebugMethodAddress);
411 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
412 // FIXME: Maybe we should print a warning here.
413 // This should only happen for very big methods, for instance
414 // with more than 40.000 line numbers and more than 5.000
419 allocate_data_item (mono_symbol_table, MONO_DEBUG_DATA_ITEM_METHOD, total_size, (guint8 **) &address);
421 address->size = total_size;
422 address->symfile_id = handle->index;
423 address->domain_id = mono_domain_get_id (domain);
424 address->method_id = minfo->index;
425 address->code_start = jit->code_start;
426 address->code_size = jit->code_size;
427 address->wrapper_addr = jit->wrapper_addr;
429 memcpy (&address->data, oldptr, size);
431 if (max_size > BUFSIZ)
434 hash = g_new0 (MethodHashEntry, 1);
435 hash->symfile_id = address->symfile_id;
436 hash->domain_id = address->domain_id;
437 hash->method_id = address->method_id;
439 g_hash_table_insert (method_hash, hash, address);
441 if (in_the_mono_debugger)
442 mono_debugger_add_method (jit);
444 mono_debugger_unlock ();
449 static inline guint32
450 read_leb128 (guint8 *ptr, guint8 **rptr)
452 guint32 result = 0, shift = 0;
455 guint8 byte = *ptr++;
457 result |= (byte & 0x7f) << shift;
458 if ((byte & 0x80) == 0)
468 read_sleb128 (guint8 *ptr, guint8 **rptr)
474 guint8 byte = *ptr++;
476 result |= (byte & 0x7f) << shift;
482 if ((shift < 32) && (byte & 0x40))
483 result |= - (1 << shift);
492 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
494 var->index = read_leb128 (ptr, &ptr);
495 var->offset = read_sleb128 (ptr, &ptr);
496 var->size = read_leb128 (ptr, &ptr);
497 var->begin_scope = read_leb128 (ptr, &ptr);
498 var->end_scope = read_leb128 (ptr, &ptr);
502 MonoDebugMethodJitInfo *
503 mono_debug_read_method (MonoDebugMethodAddress *address)
505 MonoDebugMethodJitInfo *jit;
506 guint32 i, il_offset = 0, native_offset = 0;
509 jit = g_new0 (MonoDebugMethodJitInfo, 1);
510 jit->code_start = address->code_start;
511 jit->code_size = address->code_size;
512 jit->wrapper_addr = address->wrapper_addr;
514 ptr = (guint8 *) &address->data;
516 jit->prologue_end = read_leb128 (ptr, &ptr);
517 jit->epilogue_begin = read_leb128 (ptr, &ptr);
519 jit->num_line_numbers = read_leb128 (ptr, &ptr);
520 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
521 for (i = 0; i < jit->num_line_numbers; i++) {
522 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
524 il_offset += read_sleb128 (ptr, &ptr);
525 native_offset += read_sleb128 (ptr, &ptr);
527 lne->il_offset = il_offset;
528 lne->native_offset = native_offset;
532 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
533 read_variable (jit->this_var, ptr, &ptr);
536 jit->num_params = read_leb128 (ptr, &ptr);
537 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
538 for (i = 0; i < jit->num_params; i++)
539 read_variable (&jit->params [i], ptr, &ptr);
541 jit->num_locals = read_leb128 (ptr, &ptr);
542 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
543 for (i = 0; i < jit->num_locals; i++)
544 read_variable (&jit->locals [i], ptr, &ptr);
550 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
551 * a new class is initialized.
554 mono_debug_start_add_type (MonoClass *klass)
556 MonoDebugHandle *handle;
558 handle = _mono_debug_get_image (klass->image);
562 if (in_the_mono_debugger)
563 mono_debugger_add_type (handle, klass);
567 get_token (MonoClass *klass)
570 klass = klass->element_class;
572 return klass->type_token;
576 mono_debug_add_type (MonoClass *klass)
578 MonoDebugHandle *handle;
579 MonoDebugClassEntry *entry;
580 char buffer [BUFSIZ];
581 guint8 *ptr, *oldptr;
582 guint32 token, i, size, total_size, max_size;
585 handle = _mono_debug_get_image (klass->image);
589 if (klass->generic_class ||
590 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
593 max_size = 12 + sizeof (gpointer);
594 if (max_size > BUFSIZ)
595 ptr = oldptr = g_malloc (max_size);
597 ptr = oldptr = buffer;
599 token = get_token (klass);
602 if (klass->valuetype)
603 base_offset = - (int)(sizeof (MonoObject));
605 write_leb128 (token, ptr, &ptr);
606 write_leb128 (klass->rank, ptr, &ptr);
607 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
608 * ((gpointer *) ptr)++ = klass;
611 g_assert (size < max_size);
612 total_size = size + sizeof (MonoDebugClassEntry);
614 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
615 // FIXME: Maybe we should print a warning here.
616 // This should only happen for very big methods, for instance
617 // with more than 40.000 line numbers and more than 5.000
622 allocate_data_item (mono_symbol_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size, (guint8 **) &entry);
624 entry->size = total_size;
625 entry->symfile_id = handle->index;
627 memcpy (&entry->data, oldptr, size);
629 if (max_size > BUFSIZ)
632 mono_debugger_start_add_type (handle, klass);
635 static MonoDebugMethodJitInfo *
636 find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain)
638 MethodHashEntry lookup;
639 MonoDebugMethodAddress *address;
641 lookup.symfile_id = minfo->handle->index;
642 lookup.domain_id = mono_domain_get_id (domain);
643 lookup.method_id = minfo->index;
645 address = g_hash_table_lookup (method_hash, &lookup);
649 return mono_debug_read_method (address);
653 il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset)
655 MonoDebugMethodJitInfo *jit;
658 jit = find_method (minfo, domain);
659 if (!jit || !jit->line_numbers)
662 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
663 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
665 if (lne.native_offset <= native_offset)
666 return lne.il_offset;
673 * mono_debug_source_location_from_address:
679 * Used by the exception code to get a source location from a machine address.
681 * Returns: a textual representation of the specified address which is suitable to be displayed to
682 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
684 * If the optional @line_number argument is not NULL, the line number is stored there and just the
685 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
686 * line number 8 in the variable pointed to by @line_number).
689 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
692 MonoDebugMethodInfo *minfo;
697 minfo = _mono_debug_lookup_method (method);
698 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
699 mono_loader_unlock ();
703 offset = il_offset_from_address (minfo, domain, address);
706 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
708 mono_loader_unlock ();
713 * mono_debug_source_location_from_il_offset:
718 * Used by the exception code to get a source location from an IL offset.
720 * Returns a textual representation of the specified address which is suitable to be displayed to
721 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
723 * If the optional @line_number argument is not NULL, the line number is stored there and just the
724 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
725 * line number 8 in the variable pointed to by @line_number).
728 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
731 MonoDebugMethodInfo *minfo;
734 minfo = _mono_debug_lookup_method (method);
735 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
736 mono_loader_unlock ();
740 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
741 mono_loader_unlock ();
746 * mono_debug_il_offset_from_address:
751 * Returns: the IL offset corresponding to machine address @address which is an offset
752 * relative to the beginning of the method @method.
755 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
757 MonoDebugMethodInfo *minfo;
764 minfo = _mono_debug_lookup_method (method);
765 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
766 !minfo->handle->symfile->offset_table) {
767 mono_loader_unlock ();
771 res = il_offset_from_address (minfo, domain, address);
772 mono_loader_unlock ();
777 * mono_debug_address_from_il_offset:
782 * Returns: the machine address corresponding to IL offset @il_offset.
783 * The returned value is an offset relative to the beginning of the method @method.
786 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
788 MonoDebugMethodInfo *minfo;
789 MonoDebugMethodJitInfo *jit;
796 minfo = _mono_debug_lookup_method (method);
797 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
798 !minfo->handle->symfile->offset_table) {
799 mono_loader_unlock ();
803 jit = find_method (minfo, domain);
805 mono_loader_unlock ();
809 res = _mono_debug_address_from_il_offset (jit, il_offset);
810 mono_loader_unlock ();