5 * Mono Project (http://www.mono-project.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
12 #include <mono/metadata/assembly.h>
13 #include <mono/metadata/tabledefs.h>
14 #include <mono/metadata/tokentype.h>
15 #include <mono/metadata/appdomain.h>
16 #include <mono/metadata/class-internals.h>
17 #include <mono/metadata/mono-debug.h>
18 #include <mono/metadata/mono-debug-debugger.h>
19 #include <mono/metadata/mono-endian.h>
22 #define DATA_TABLE_CHUNK_SIZE 16384
24 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
26 #if NO_UNALIGNED_ACCESS
27 #define RETURN_UNALIGNED(type, addr) \
30 memcpy(&val, p + offset, sizeof(val)); \
33 #define WRITE_UNALIGNED(type, addr, val) \
34 memcpy(addr, &val, sizeof(type))
35 #define READ_UNALIGNED(type, addr, val) \
36 memcpy(&val, addr, sizeof(type))
38 #define RETURN_UNALIGNED(type, addr) \
39 return *(type*)(p + offset);
40 #define WRITE_UNALIGNED(type, addr, val) \
41 (*(type *)(addr) = (val))
42 #define READ_UNALIGNED(type, addr, val) \
43 val = (*(type *)(addr))
47 MONO_DEBUG_DATA_ITEM_UNKNOWN = 0,
48 MONO_DEBUG_DATA_ITEM_CLASS,
49 MONO_DEBUG_DATA_ITEM_METHOD,
50 MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE
51 } MonoDebugDataItemType;
53 typedef struct _MonoDebugDataChunk MonoDebugDataChunk;
55 struct _MonoDebugDataChunk {
57 guint32 allocated_size;
58 guint32 current_offset;
60 MonoDebugDataChunk *next;
61 guint8 data [MONO_ZERO_LEN_ARRAY];
64 struct _MonoDebugDataTable {
66 gint32 _dummy; /* alignment for next field. */
67 MonoDebugDataChunk *first_chunk;
68 MonoDebugDataChunk *current_chunk;
69 GHashTable *method_hash;
70 GHashTable *method_address_hash;
74 const gchar *method_name;
75 const gchar *obsolete_cil_code;
77 } MonoDebugWrapperData;
84 MonoDebugWrapperData *wrapper_data;
87 } MonoDebugMethodHeader;
89 struct _MonoDebugMethodAddress {
90 MonoDebugMethodHeader header;
91 const guint8 *code_start;
92 const guint8 *wrapper_addr;
94 guint8 data [MONO_ZERO_LEN_ARRAY];
97 struct _MonoDebugClassEntry {
99 guint8 data [MONO_ZERO_LEN_ARRAY];
105 } MonoDebugDelegateTrampolineEntry;
107 MonoSymbolTable *mono_symbol_table = NULL;
108 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
109 gint32 mono_debug_debugger_version = 5;
110 gint32 _mono_debug_using_mono_debugger = 0;
112 static gboolean mono_debug_initialized = FALSE;
113 GHashTable *mono_debug_handles = NULL;
115 static GHashTable *data_table_hash = NULL;
116 static int next_symbol_file_id = 0;
118 static MonoDebugHandle *mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size);
120 static MonoDebugHandle *_mono_debug_get_image (MonoImage *image);
121 static void mono_debug_add_assembly (MonoAssembly *assembly,
123 static void mono_debug_add_type (MonoClass *klass);
125 void _mono_debug_init_corlib (MonoDomain *domain);
127 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
128 extern void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass);
130 static MonoDebugDataTable *
131 create_data_table (MonoDomain *domain)
133 MonoDebugDataTable *table;
134 MonoDebugDataChunk *chunk;
136 table = g_new0 (MonoDebugDataTable, 1);
137 table->domain = domain ? mono_domain_get_id (domain) : -1;
139 table->method_address_hash = g_hash_table_new (NULL, NULL);
140 table->method_hash = g_hash_table_new (NULL, NULL);
142 chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + DATA_TABLE_CHUNK_SIZE);
143 chunk->total_size = DATA_TABLE_CHUNK_SIZE;
145 table->first_chunk = table->current_chunk = chunk;
148 mono_debug_list_add (&mono_symbol_table->data_tables, table);
149 g_hash_table_insert (data_table_hash, domain, table);
156 free_header_data (gpointer key, gpointer value, gpointer user_data)
158 MonoDebugMethodHeader *header = (MonoDebugMethodHeader*)value;
160 if (header->wrapper_data) {
161 g_free ((gpointer)header->wrapper_data->method_name);
162 g_slist_free (header->address_list);
163 g_free (header->wrapper_data);
168 free_data_table (MonoDebugDataTable *table)
170 MonoDebugDataChunk *chunk, *next_chunk;
172 g_hash_table_foreach (table->method_hash, free_header_data, NULL);
173 g_hash_table_destroy (table->method_hash);
174 g_hash_table_destroy (table->method_address_hash);
176 table->method_hash = NULL;
177 table->method_address_hash = NULL;
179 chunk = table->first_chunk;
181 next_chunk = chunk->next;
186 table->first_chunk = table->current_chunk = NULL;
187 mono_debug_list_remove (&mono_symbol_table->data_tables, table);
191 static MonoDebugDataTable *
192 lookup_data_table (MonoDomain *domain)
194 MonoDebugDataTable *table;
196 table = g_hash_table_lookup (data_table_hash, domain);
202 free_debug_handle (MonoDebugHandle *handle)
205 mono_debug_close_mono_symbol_file (handle->symfile);
206 /* decrease the refcount added with mono_image_addref () */
207 free_data_table (handle->type_table);
208 mono_image_close (handle->image);
209 g_free (handle->image_file);
214 * Initialize debugging support.
216 * This method must be called after loading corlib,
217 * but before opening the application's main assembly because we need to set some
221 mono_debug_init (MonoDebugFormat format)
223 g_assert (!mono_debug_initialized);
225 if (_mono_debug_using_mono_debugger)
226 format = MONO_DEBUG_FORMAT_DEBUGGER;
228 mono_debug_initialized = TRUE;
229 mono_debug_format = format;
231 mono_debugger_initialize (_mono_debug_using_mono_debugger);
233 mono_debugger_lock ();
235 mono_symbol_table = g_new0 (MonoSymbolTable, 1);
236 mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
237 mono_symbol_table->version = MONO_DEBUGGER_MAJOR_VERSION;
238 mono_symbol_table->total_size = sizeof (MonoSymbolTable);
240 mono_debug_handles = g_hash_table_new_full
241 (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
243 data_table_hash = g_hash_table_new_full (
244 NULL, NULL, NULL, (GDestroyNotify) free_data_table);
246 mono_debugger_class_init_func = mono_debug_add_type;
247 mono_debugger_class_loaded_methods_func = mono_debugger_class_initialized;
248 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
250 mono_symbol_table->global_data_table = create_data_table (NULL);
252 mono_debugger_unlock ();
256 * INTERNAL USE ONLY !
259 _mono_debug_init_corlib (MonoDomain *domain)
261 if (!mono_debug_initialized)
264 mono_symbol_table->corlib = mono_debug_open_image (mono_defaults.corlib, NULL, 0);
265 mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_CORLIB,
266 (guint64) (gsize) mono_symbol_table->corlib, 0);
270 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
272 mono_debug_open_image (image, raw_contents, size);
277 mono_debug_using_mono_debugger (void)
279 return _mono_debug_using_mono_debugger;
283 mono_debug_cleanup (void)
285 if (mono_debug_handles)
286 g_hash_table_destroy (mono_debug_handles);
287 mono_debug_handles = NULL;
289 if (data_table_hash) {
290 g_hash_table_destroy (data_table_hash);
291 data_table_hash = NULL;
294 g_free (mono_symbol_table);
295 mono_symbol_table = NULL;
299 mono_debug_domain_create (MonoDomain *domain)
301 MonoDebugDataTable *table;
303 if (!mono_debug_initialized)
306 mono_debugger_lock ();
308 table = create_data_table (domain);
310 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_CREATE, (guint64) (gsize) table,
311 mono_domain_get_id (domain));
313 mono_debugger_unlock ();
317 mono_debug_domain_unload (MonoDomain *domain)
319 MonoDebugDataTable *table;
321 if (!mono_debug_initialized)
324 mono_debugger_lock ();
326 table = g_hash_table_lookup (data_table_hash, domain);
328 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
329 domain, mono_domain_get_id (domain));
330 mono_debugger_unlock ();
334 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, (guint64) (gsize) table,
335 mono_domain_get_id (domain));
337 g_hash_table_remove (data_table_hash, domain);
339 mono_debugger_unlock ();
343 * LOCKING: Assumes the debug lock is held.
345 static MonoDebugHandle *
346 _mono_debug_get_image (MonoImage *image)
348 return g_hash_table_lookup (mono_debug_handles, image);
352 mono_debug_close_image (MonoImage *image)
354 MonoDebugHandle *handle;
356 if (!mono_debug_initialized)
359 mono_debugger_lock ();
361 handle = _mono_debug_get_image (image);
363 mono_debugger_unlock ();
367 mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
370 mono_debug_list_remove (&mono_symbol_table->symbol_files, handle);
371 g_hash_table_remove (mono_debug_handles, image);
373 mono_debugger_unlock ();
376 static MonoDebugHandle *
377 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
379 MonoDebugHandle *handle;
381 if (mono_image_is_dynamic (image))
384 mono_debugger_lock ();
386 handle = _mono_debug_get_image (image);
387 if (handle != NULL) {
388 mono_debugger_unlock ();
392 handle = g_new0 (MonoDebugHandle, 1);
393 handle->index = ++next_symbol_file_id;
395 handle->image = image;
396 mono_image_addref (image);
397 handle->image_file = g_strdup (mono_image_get_filename (image));
399 handle->type_table = create_data_table (NULL);
401 handle->symfile = mono_debug_open_mono_symbols (
402 handle, raw_contents, size, _mono_debug_using_mono_debugger);
404 mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
406 g_hash_table_insert (mono_debug_handles, image, handle);
408 if (mono_symbol_table->corlib)
409 mono_debugger_event (MONO_DEBUGGER_EVENT_LOAD_MODULE,
410 (guint64) (gsize) handle, 0);
412 mono_debugger_unlock ();
418 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
420 mono_debugger_lock ();
421 mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
422 mono_debugger_unlock ();
426 allocate_data_item (MonoDebugDataTable *table, MonoDebugDataItemType type, guint32 size)
431 size = ALIGN_TO (size, sizeof (gpointer));
433 if (size + 16 < DATA_TABLE_CHUNK_SIZE)
434 chunk_size = DATA_TABLE_CHUNK_SIZE;
436 chunk_size = size + 16;
438 g_assert (table->current_chunk->current_offset == table->current_chunk->allocated_size);
440 if (table->current_chunk->allocated_size + size + 8 >= table->current_chunk->total_size) {
441 MonoDebugDataChunk *new_chunk;
443 new_chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + chunk_size);
444 new_chunk->total_size = chunk_size;
446 table->current_chunk->next = new_chunk;
447 table->current_chunk = new_chunk;
450 data = &table->current_chunk->data [table->current_chunk->allocated_size];
451 table->current_chunk->allocated_size += size + 8;
453 * ((guint32 *) data) = size;
455 * ((guint32 *) data) = type;
461 write_data_item (MonoDebugDataTable *table, const guint8 *data)
463 MonoDebugDataChunk *current_chunk = table->current_chunk;
464 guint32 size = * ((guint32 *) (data - 8));
466 g_assert (current_chunk->current_offset + size + 8 == current_chunk->allocated_size);
467 current_chunk->current_offset = current_chunk->allocated_size;
470 struct LookupMethodData
472 MonoDebugMethodInfo *minfo;
477 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
479 MonoDebugHandle *handle = (MonoDebugHandle *) value;
480 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
486 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
489 static MonoDebugMethodInfo *
490 _mono_debug_lookup_method (MonoMethod *method)
492 struct LookupMethodData data;
495 data.method = method;
497 if (!mono_debug_handles)
500 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
505 * mono_debug_lookup_method:
507 * Lookup symbol file information for the method @method. The returned
508 * `MonoDebugMethodInfo' is a private structure, but it can be passed to
509 * mono_debug_symfile_lookup_location().
511 MonoDebugMethodInfo *
512 mono_debug_lookup_method (MonoMethod *method)
514 MonoDebugMethodInfo *minfo;
516 mono_debugger_lock ();
517 minfo = _mono_debug_lookup_method (method);
518 mono_debugger_unlock ();
523 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
526 guint8 byte = value & 0x7f;
537 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
542 guint8 byte = value & 0x7f;
545 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
556 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
558 write_leb128 (var->index, ptr, &ptr);
559 write_sleb128 (var->offset, ptr, &ptr);
560 write_leb128 (var->size, ptr, &ptr);
561 write_leb128 (var->begin_scope, ptr, &ptr);
562 write_leb128 (var->end_scope, ptr, &ptr);
563 WRITE_UNALIGNED (gpointer, ptr, var->type);
564 ptr += sizeof (gpointer);
568 MonoDebugMethodAddress *
569 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
571 MonoMethod *declaring;
572 MonoDebugDataTable *table;
573 MonoDebugMethodHeader *header;
574 MonoDebugMethodAddress *address;
575 MonoDebugMethodInfo *minfo;
576 MonoDebugHandle *handle;
577 guint8 buffer [BUFSIZ];
578 guint8 *ptr, *oldptr;
579 guint32 i, size, total_size, max_size;
580 gboolean is_wrapper = FALSE;
582 mono_debugger_lock ();
584 table = lookup_data_table (domain);
586 handle = _mono_debug_get_image (method->klass->image);
587 minfo = _mono_debug_lookup_method (method);
589 if (!minfo || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
590 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
591 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
592 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
593 (method->wrapper_type != MONO_WRAPPER_NONE)) {
597 max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
598 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
600 if (max_size > BUFSIZ)
601 ptr = oldptr = g_malloc (max_size);
603 ptr = oldptr = buffer;
605 write_leb128 (jit->prologue_end, ptr, &ptr);
606 write_leb128 (jit->epilogue_begin, ptr, &ptr);
608 write_leb128 (jit->num_line_numbers, ptr, &ptr);
609 for (i = 0; i < jit->num_line_numbers; i++) {
610 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
612 write_sleb128 (lne->il_offset, ptr, &ptr);
613 write_sleb128 (lne->native_offset, ptr, &ptr);
616 *ptr++ = jit->this_var ? 1 : 0;
618 write_variable (jit->this_var, ptr, &ptr);
620 write_leb128 (jit->num_params, ptr, &ptr);
621 for (i = 0; i < jit->num_params; i++)
622 write_variable (&jit->params [i], ptr, &ptr);
624 write_leb128 (jit->num_locals, ptr, &ptr);
625 for (i = 0; i < jit->num_locals; i++)
626 write_variable (&jit->locals [i], ptr, &ptr);
629 g_assert (size < max_size);
630 total_size = size + sizeof (MonoDebugMethodAddress);
632 address = (MonoDebugMethodAddress *) allocate_data_item (
633 table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
635 address->header.size = total_size;
636 address->header.symfile_id = handle ? handle->index : 0;
637 address->header.domain_id = mono_domain_get_id (domain);
638 address->header.method_id = is_wrapper ? 0 : minfo->index;
639 address->header.method = method;
641 address->code_start = jit->code_start;
642 address->code_size = jit->code_size;
644 memcpy (&address->data, oldptr, size);
645 if (max_size > BUFSIZ)
648 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
649 header = g_hash_table_lookup (table->method_hash, declaring);
652 header = &address->header;
653 g_hash_table_insert (table->method_hash, declaring, header);
656 MonoDebugWrapperData *wrapper;
658 header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
660 wrapper->wrapper_type = method->wrapper_type;
661 wrapper->method_name = mono_method_full_name (declaring, TRUE);
662 wrapper->obsolete_cil_code = "";
665 address->header.wrapper_data = header->wrapper_data;
666 header->address_list = g_slist_prepend (header->address_list, address);
669 g_hash_table_insert (table->method_address_hash, method, address);
671 write_data_item (table, (guint8 *) address);
673 mono_debugger_unlock ();
678 mono_debug_add_delegate_trampoline (gpointer code, int size)
680 MonoDebugDelegateTrampolineEntry *entry;
682 if (!mono_debug_initialized)
685 mono_debugger_lock ();
687 entry = (MonoDebugDelegateTrampolineEntry *) allocate_data_item (
688 mono_symbol_table->global_data_table, MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE,
689 sizeof (MonoDebugDelegateTrampolineEntry));
693 write_data_item (mono_symbol_table->global_data_table, (guint8 *) entry);
695 mono_debugger_unlock ();
698 static inline guint32
699 read_leb128 (guint8 *ptr, guint8 **rptr)
701 guint32 result = 0, shift = 0;
704 guint8 byte = *ptr++;
706 result |= (byte & 0x7f) << shift;
707 if ((byte & 0x80) == 0)
717 read_sleb128 (guint8 *ptr, guint8 **rptr)
723 guint8 byte = *ptr++;
725 result |= (byte & 0x7f) << shift;
731 if ((shift < 32) && (byte & 0x40))
732 result |= - (1 << shift);
741 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
743 var->index = read_leb128 (ptr, &ptr);
744 var->offset = read_sleb128 (ptr, &ptr);
745 var->size = read_leb128 (ptr, &ptr);
746 var->begin_scope = read_leb128 (ptr, &ptr);
747 var->end_scope = read_leb128 (ptr, &ptr);
748 READ_UNALIGNED (gpointer, ptr, var->type);
749 ptr += sizeof (gpointer);
754 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
758 g_free (jit->line_numbers);
759 g_free (jit->this_var);
760 g_free (jit->params);
761 g_free (jit->locals);
765 static MonoDebugMethodJitInfo *
766 mono_debug_read_method (MonoDebugMethodAddress *address)
768 MonoDebugMethodJitInfo *jit;
772 jit = g_new0 (MonoDebugMethodJitInfo, 1);
773 jit->code_start = address->code_start;
774 jit->code_size = address->code_size;
775 jit->wrapper_addr = address->wrapper_addr;
777 ptr = (guint8 *) &address->data;
779 jit->prologue_end = read_leb128 (ptr, &ptr);
780 jit->epilogue_begin = read_leb128 (ptr, &ptr);
782 jit->num_line_numbers = read_leb128 (ptr, &ptr);
783 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
784 for (i = 0; i < jit->num_line_numbers; i++) {
785 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
787 lne->il_offset = read_sleb128 (ptr, &ptr);
788 lne->native_offset = read_sleb128 (ptr, &ptr);
792 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
793 read_variable (jit->this_var, ptr, &ptr);
796 jit->num_params = read_leb128 (ptr, &ptr);
797 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
798 for (i = 0; i < jit->num_params; i++)
799 read_variable (&jit->params [i], ptr, &ptr);
801 jit->num_locals = read_leb128 (ptr, &ptr);
802 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
803 for (i = 0; i < jit->num_locals; i++)
804 read_variable (&jit->locals [i], ptr, &ptr);
810 mono_debug_add_type (MonoClass *klass)
812 MonoDebugHandle *handle;
813 MonoDebugClassEntry *entry;
814 guint8 buffer [BUFSIZ];
815 guint8 *ptr, *oldptr;
816 guint32 size, total_size, max_size;
819 if (klass->generic_class || klass->rank ||
820 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
823 mono_debugger_lock ();
825 handle = _mono_debug_get_image (klass->image);
827 mono_debugger_unlock ();
831 max_size = 12 + sizeof (gpointer);
832 if (max_size > BUFSIZ)
833 ptr = oldptr = g_malloc (max_size);
835 ptr = oldptr = buffer;
837 if (klass->valuetype)
838 base_offset = - (int)(sizeof (MonoObject));
840 write_leb128 (klass->type_token, ptr, &ptr);
841 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
842 WRITE_UNALIGNED (gpointer, ptr, klass);
843 ptr += sizeof (gpointer);
846 g_assert (size < max_size);
847 total_size = size + sizeof (MonoDebugClassEntry);
849 g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
851 entry = (MonoDebugClassEntry *) allocate_data_item (
852 handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size);
854 entry->size = total_size;
856 memcpy (&entry->data, oldptr, size);
858 write_data_item (handle->type_table, (guint8 *) entry);
860 if (max_size > BUFSIZ)
863 mono_debugger_unlock ();
866 static MonoDebugMethodJitInfo *
867 find_method (MonoMethod *method, MonoDomain *domain)
869 MonoDebugDataTable *table;
870 MonoDebugMethodAddress *address;
872 table = lookup_data_table (domain);
873 address = g_hash_table_lookup (table->method_address_hash, method);
878 return mono_debug_read_method (address);
881 MonoDebugMethodJitInfo *
882 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
884 MonoDebugMethodJitInfo *res;
886 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
889 mono_debugger_lock ();
890 res = find_method (method, domain);
891 mono_debugger_unlock ();
895 struct LookupMethodAddressData
898 MonoDebugMethodHeader *result;
902 lookup_method_address_func (gpointer key, gpointer value, gpointer user_data)
904 MonoDebugDataTable *table = (MonoDebugDataTable *) value;
905 struct LookupMethodAddressData *data = (struct LookupMethodAddressData *) user_data;
906 MonoDebugMethodHeader *header;
908 header = g_hash_table_lookup (table->method_hash, data->method);
910 data->result = header;
913 MonoDebugMethodAddressList *
914 mono_debug_lookup_method_addresses (MonoMethod *method)
916 MonoDebugMethodAddressList *info;
917 MonoDebugMethodHeader *header = NULL;
918 struct LookupMethodAddressData data;
919 MonoMethod *declaring;
924 g_assert ((mono_debug_debugger_version == 4) || (mono_debug_debugger_version == 5));
926 mono_debugger_lock ();
928 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
930 data.method = declaring;
933 g_hash_table_foreach (data_table_hash, lookup_method_address_func, &data);
934 header = data.result;
937 mono_debugger_unlock ();
941 count = g_slist_length (header->address_list) + 1;
942 size = sizeof (MonoDebugMethodAddressList) + count * sizeof (gpointer);
944 info = g_malloc0 (size);
950 WRITE_UNALIGNED (gpointer, ptr, header);
951 ptr += sizeof (gpointer);
953 for (list = header->address_list; list; list = list->next) {
954 WRITE_UNALIGNED (gpointer, ptr, list->data);
955 ptr += sizeof (gpointer);
958 mono_debugger_unlock ();
963 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
965 MonoDebugMethodJitInfo *jit;
968 jit = find_method (method, domain);
969 if (!jit || !jit->line_numbers)
970 goto cleanup_and_fail;
972 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
973 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
975 if (lne.native_offset <= native_offset) {
976 mono_debug_free_method_jit_info (jit);
977 return lne.il_offset;
982 mono_debug_free_method_jit_info (jit);
987 * mono_debug_il_offset_from_address:
989 * Compute the IL offset corresponding to NATIVE_OFFSET inside the native
990 * code of METHOD in DOMAIN.
993 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
997 mono_debugger_lock ();
999 res = il_offset_from_address (method, domain, native_offset);
1001 mono_debugger_unlock ();
1007 * mono_debug_lookup_source_location:
1008 * @address: Native offset within the @method's machine code.
1010 * Lookup the source code corresponding to the machine instruction located at
1011 * native offset @address within @method.
1013 * The returned `MonoDebugSourceLocation' contains both file / line number
1014 * information and the corresponding IL offset. It must be freed by
1015 * mono_debug_free_source_location().
1017 MonoDebugSourceLocation *
1018 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
1020 MonoDebugMethodInfo *minfo;
1021 MonoDebugSourceLocation *location;
1024 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
1027 mono_debugger_lock ();
1028 minfo = _mono_debug_lookup_method (method);
1029 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
1030 mono_debugger_unlock ();
1034 offset = il_offset_from_address (method, domain, address);
1036 mono_debugger_unlock ();
1040 location = mono_debug_symfile_lookup_location (minfo, offset);
1041 mono_debugger_unlock ();
1046 * mono_debug_lookup_locals:
1048 * Return information about the local variables of MINFO.
1049 * NAMES and INDEXES are set to g_malloc-ed arrays containing the local names and
1051 * Returns: the number of elements placed into the arrays, or -1 if there is no
1052 * local variable info.
1055 mono_debug_lookup_locals (MonoMethod *method, char ***names, int **indexes)
1057 MonoDebugMethodInfo *minfo;
1063 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
1066 mono_debugger_lock ();
1067 minfo = _mono_debug_lookup_method (method);
1068 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
1069 mono_debugger_unlock ();
1073 res = mono_debug_symfile_lookup_locals (minfo, names, indexes);
1074 mono_debugger_unlock ();
1080 * mono_debug_free_source_location:
1081 * @location: A `MonoDebugSourceLocation'.
1083 * Frees the @location.
1086 mono_debug_free_source_location (MonoDebugSourceLocation *location)
1089 g_free (location->source_file);
1095 * mono_debug_print_stack_frame:
1096 * @native_offset: Native offset within the @method's machine code.
1098 * Conventient wrapper around mono_debug_lookup_source_location() which can be
1099 * used if you only want to use the location to print a stack frame.
1102 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
1104 MonoDebugSourceLocation *location;
1105 gchar *fname, *ptr, *res;
1108 fname = mono_method_full_name (method, TRUE);
1109 for (ptr = fname; *ptr; ptr++) {
1110 if (*ptr == ':') *ptr = '.';
1113 location = mono_debug_lookup_source_location (method, native_offset, domain);
1116 if (mono_debug_initialized) {
1117 mono_debugger_lock ();
1118 offset = il_offset_from_address (method, domain, native_offset);
1119 mono_debugger_unlock ();
1125 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
1127 res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
1132 res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
1133 location->source_file, location->row);
1136 mono_debug_free_source_location (location);
1141 mono_debug_list_add (MonoDebugList **list, gconstpointer data)
1143 MonoDebugList *element, **ptr;
1145 element = g_new0 (MonoDebugList, 1);
1146 element->data = data;
1148 for (ptr = list; *ptr; ptr = &(*ptr)->next)
1155 mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
1157 MonoDebugList **ptr;
1158 MonoDebugList *next;
1160 for (ptr = list; *ptr; ptr = &(*ptr)->next) {
1161 if ((*ptr)->data != data)
1164 next = (*ptr)->next;
1171 static gboolean is_attached = FALSE;
1174 mono_set_is_debugger_attached (gboolean attached)
1176 is_attached = attached;
1180 mono_is_debugger_attached (void)