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 DATA_TABLE_CHUNK_SIZE 16384
14 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
16 #if NO_UNALIGNED_ACCESS
17 #define RETURN_UNALIGNED(type, addr) \
20 memcpy(&val, p + offset, sizeof(val)); \
23 #define WRITE_UNALIGNED(type, addr, val) \
24 memcpy(addr, &val, sizeof(type))
25 #define READ_UNALIGNED(type, addr, val) \
26 memcpy(&val, addr, sizeof(type))
28 #define RETURN_UNALIGNED(type, addr) \
29 return *(type*)(p + offset);
30 #define WRITE_UNALIGNED(type, addr, val) \
31 (*(type *)(addr) = (val))
32 #define READ_UNALIGNED(type, addr, val) \
33 val = (*(type *)(addr))
37 MONO_DEBUG_DATA_ITEM_UNKNOWN = 0,
38 MONO_DEBUG_DATA_ITEM_CLASS,
39 MONO_DEBUG_DATA_ITEM_METHOD,
40 MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE
41 } MonoDebugDataItemType;
43 typedef struct _MonoDebugDataChunk MonoDebugDataChunk;
45 struct _MonoDebugDataChunk {
47 guint32 allocated_size;
48 guint32 current_offset;
50 MonoDebugDataChunk *next;
51 guint8 data [MONO_ZERO_LEN_ARRAY];
54 struct _MonoDebugDataTable {
56 gint32 _dummy; /* alignment for next field. */
57 MonoDebugDataChunk *first_chunk;
58 MonoDebugDataChunk *current_chunk;
59 GHashTable *method_hash;
60 GHashTable *method_address_hash;
64 const gchar *method_name;
65 const gchar *cil_code;
67 } MonoDebugWrapperData;
74 MonoDebugWrapperData *wrapper_data;
77 } MonoDebugMethodHeader;
79 struct _MonoDebugMethodAddress {
80 MonoDebugMethodHeader header;
81 const guint8 *code_start;
82 const guint8 *wrapper_addr;
84 guint8 data [MONO_ZERO_LEN_ARRAY];
87 struct _MonoDebugClassEntry {
89 guint8 data [MONO_ZERO_LEN_ARRAY];
95 } MonoDebugDelegateTrampolineEntry;
97 MonoSymbolTable *mono_symbol_table = NULL;
98 MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
99 gint32 mono_debug_debugger_version = 4;
100 gint32 _mono_debug_using_mono_debugger = 0;
102 static gboolean mono_debug_initialized = FALSE;
103 GHashTable *mono_debug_handles = NULL;
105 static GHashTable *data_table_hash = NULL;
106 static int next_symbol_file_id = 0;
108 static MonoDebugHandle *mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size);
110 static MonoDebugHandle *_mono_debug_get_image (MonoImage *image);
111 static void mono_debug_add_assembly (MonoAssembly *assembly,
113 static void mono_debug_add_type (MonoClass *klass);
115 void _mono_debug_init_corlib (MonoDomain *domain);
117 extern void (*mono_debugger_class_init_func) (MonoClass *klass);
118 extern void (*mono_debugger_class_loaded_methods_func) (MonoClass *klass);
120 static MonoDebugDataTable *
121 create_data_table (MonoDomain *domain)
123 MonoDebugDataTable *table;
124 MonoDebugDataChunk *chunk;
126 table = g_new0 (MonoDebugDataTable, 1);
127 table->domain = domain ? mono_domain_get_id (domain) : -1;
129 table->method_address_hash = g_hash_table_new (NULL, NULL);
130 table->method_hash = g_hash_table_new (NULL, NULL);
132 chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + DATA_TABLE_CHUNK_SIZE);
133 chunk->total_size = DATA_TABLE_CHUNK_SIZE;
135 table->first_chunk = table->current_chunk = chunk;
138 mono_debug_list_add (&mono_symbol_table->data_tables, table);
139 g_hash_table_insert (data_table_hash, domain, table);
146 free_header_data (gpointer key, gpointer value, gpointer user_data)
148 MonoDebugMethodHeader *header = (MonoDebugMethodHeader*)value;
150 if (header->wrapper_data) {
151 g_free ((gpointer)header->wrapper_data->method_name);
152 g_free ((gpointer)header->wrapper_data->cil_code);
153 g_slist_free (header->address_list);
154 g_free (header->wrapper_data);
159 free_data_table (MonoDebugDataTable *table)
161 MonoDebugDataChunk *chunk, *next_chunk;
163 g_hash_table_foreach (table->method_hash, free_header_data, NULL);
164 g_hash_table_destroy (table->method_hash);
165 g_hash_table_destroy (table->method_address_hash);
167 table->method_hash = NULL;
168 table->method_address_hash = NULL;
170 chunk = table->first_chunk;
172 next_chunk = chunk->next;
177 table->first_chunk = table->current_chunk = NULL;
178 mono_debug_list_remove (&mono_symbol_table->data_tables, table);
182 static MonoDebugDataTable *
183 lookup_data_table (MonoDomain *domain)
185 MonoDebugDataTable *table;
187 table = g_hash_table_lookup (data_table_hash, domain);
193 free_debug_handle (MonoDebugHandle *handle)
196 mono_debug_close_mono_symbol_file (handle->symfile);
197 /* decrease the refcount added with mono_image_addref () */
198 free_data_table (handle->type_table);
199 mono_image_close (handle->image);
200 g_free (handle->image_file);
205 * Initialize debugging support.
207 * This method must be called after loading corlib,
208 * but before opening the application's main assembly because we need to set some
212 mono_debug_init (MonoDebugFormat format)
214 g_assert (!mono_debug_initialized);
216 mono_debug_initialized = TRUE;
217 mono_debug_format = format;
219 mono_debugger_initialize (_mono_debug_using_mono_debugger);
221 mono_debugger_lock ();
223 mono_symbol_table = g_new0 (MonoSymbolTable, 1);
224 mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
225 mono_symbol_table->version = MONO_DEBUGGER_MAJOR_VERSION;
226 mono_symbol_table->total_size = sizeof (MonoSymbolTable);
228 mono_debug_handles = g_hash_table_new_full
229 (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
231 data_table_hash = g_hash_table_new_full (
232 NULL, NULL, NULL, (GDestroyNotify) free_data_table);
234 mono_debugger_class_init_func = mono_debug_add_type;
235 mono_debugger_class_loaded_methods_func = mono_debugger_class_initialized;
236 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
238 mono_symbol_table->global_data_table = create_data_table (NULL);
240 mono_debugger_unlock ();
244 * INTERNAL USE ONLY !
247 _mono_debug_init_corlib (MonoDomain *domain)
249 if (!mono_debug_initialized)
252 mono_symbol_table->corlib = mono_debug_open_image (mono_defaults.corlib, NULL, 0);
253 mono_debugger_event (MONO_DEBUGGER_EVENT_INITIALIZE_CORLIB,
254 (guint64) (gsize) mono_symbol_table->corlib, 0);
258 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
260 mono_debug_open_image (image, raw_contents, size);
265 mono_debug_using_mono_debugger (void)
267 return _mono_debug_using_mono_debugger;
271 mono_debug_cleanup (void)
273 if (mono_debug_handles)
274 g_hash_table_destroy (mono_debug_handles);
275 mono_debug_handles = NULL;
277 if (data_table_hash) {
278 g_hash_table_destroy (data_table_hash);
279 data_table_hash = NULL;
282 g_free (mono_symbol_table);
283 mono_symbol_table = NULL;
287 mono_debug_domain_create (MonoDomain *domain)
289 MonoDebugDataTable *table;
291 if (!mono_debug_initialized)
294 mono_debugger_lock ();
296 table = create_data_table (domain);
298 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_CREATE, (guint64) (gsize) table,
299 mono_domain_get_id (domain));
301 mono_debugger_unlock ();
305 mono_debug_domain_unload (MonoDomain *domain)
307 MonoDebugDataTable *table;
309 if (!mono_debug_initialized)
312 mono_debugger_lock ();
314 table = g_hash_table_lookup (data_table_hash, domain);
316 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
317 domain, mono_domain_get_id (domain));
318 mono_debugger_unlock ();
322 mono_debugger_event (MONO_DEBUGGER_EVENT_DOMAIN_UNLOAD, (guint64) (gsize) table,
323 mono_domain_get_id (domain));
325 g_hash_table_remove (data_table_hash, domain);
327 mono_debugger_unlock ();
330 static MonoDebugHandle *
331 _mono_debug_get_image (MonoImage *image)
333 return g_hash_table_lookup (mono_debug_handles, image);
337 mono_debug_close_image (MonoImage *image)
339 MonoDebugHandle *handle;
341 if (!mono_debug_initialized)
344 handle = _mono_debug_get_image (image);
348 mono_debugger_lock ();
350 mono_debugger_event (MONO_DEBUGGER_EVENT_UNLOAD_MODULE, (guint64) (gsize) handle,
353 mono_debug_list_remove (&mono_symbol_table->symbol_files, handle);
354 g_hash_table_remove (mono_debug_handles, image);
356 mono_debugger_unlock ();
359 static MonoDebugHandle *
360 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
362 MonoDebugHandle *handle;
364 if (mono_image_is_dynamic (image))
367 handle = _mono_debug_get_image (image);
371 mono_debugger_lock ();
373 handle = g_new0 (MonoDebugHandle, 1);
374 handle->index = ++next_symbol_file_id;
376 handle->image = image;
377 mono_image_addref (image);
378 handle->image_file = g_strdup (mono_image_get_filename (image));
380 handle->type_table = create_data_table (NULL);
382 handle->symfile = mono_debug_open_mono_symbols (
383 handle, raw_contents, size, _mono_debug_using_mono_debugger);
385 mono_debug_list_add (&mono_symbol_table->symbol_files, handle);
387 g_hash_table_insert (mono_debug_handles, image, handle);
389 if (mono_symbol_table->corlib)
390 mono_debugger_event (MONO_DEBUGGER_EVENT_LOAD_MODULE,
391 (guint64) (gsize) handle, 0);
393 mono_debugger_unlock ();
399 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
401 mono_debugger_lock ();
402 mono_debug_open_image (mono_assembly_get_image (assembly), NULL, 0);
403 mono_debugger_unlock ();
407 allocate_data_item (MonoDebugDataTable *table, MonoDebugDataItemType type, guint32 size)
412 size = ALIGN_TO (size, sizeof (gpointer));
414 if (size + 16 < DATA_TABLE_CHUNK_SIZE)
415 chunk_size = DATA_TABLE_CHUNK_SIZE;
417 chunk_size = size + 16;
419 g_assert (table->current_chunk->current_offset == table->current_chunk->allocated_size);
421 if (table->current_chunk->allocated_size + size + 8 >= table->current_chunk->total_size) {
422 MonoDebugDataChunk *new_chunk;
424 new_chunk = g_malloc0 (sizeof (MonoDebugDataChunk) + chunk_size);
425 new_chunk->total_size = chunk_size;
427 table->current_chunk->next = new_chunk;
428 table->current_chunk = new_chunk;
431 data = &table->current_chunk->data [table->current_chunk->allocated_size];
432 table->current_chunk->allocated_size += size + 8;
434 * ((guint32 *) data) = size;
436 * ((guint32 *) data) = type;
442 write_data_item (MonoDebugDataTable *table, const guint8 *data)
444 MonoDebugDataChunk *current_chunk = table->current_chunk;
445 guint32 size = * ((guint32 *) (data - 8));
447 g_assert (current_chunk->current_offset + size + 8 == current_chunk->allocated_size);
448 current_chunk->current_offset = current_chunk->allocated_size;
451 struct LookupMethodData
453 MonoDebugMethodInfo *minfo;
458 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
460 MonoDebugHandle *handle = (MonoDebugHandle *) value;
461 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
467 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
470 static MonoDebugMethodInfo *
471 _mono_debug_lookup_method (MonoMethod *method)
473 struct LookupMethodData data;
476 data.method = method;
478 if (!mono_debug_handles)
481 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
486 * mono_debug_lookup_method:
488 * Lookup symbol file information for the method @method. The returned
489 * `MonoDebugMethodInfo' is a private structure, but it can be passed to
490 * mono_debug_symfile_lookup_location().
492 MonoDebugMethodInfo *
493 mono_debug_lookup_method (MonoMethod *method)
495 MonoDebugMethodInfo *minfo;
497 mono_debugger_lock ();
498 minfo = _mono_debug_lookup_method (method);
499 mono_debugger_unlock ();
504 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
507 guint8 byte = value & 0x7f;
518 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
523 guint8 byte = value & 0x7f;
526 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
537 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
539 write_leb128 (var->index, ptr, &ptr);
540 write_sleb128 (var->offset, ptr, &ptr);
541 write_leb128 (var->size, ptr, &ptr);
542 write_leb128 (var->begin_scope, ptr, &ptr);
543 write_leb128 (var->end_scope, ptr, &ptr);
544 WRITE_UNALIGNED (gpointer, ptr, var->type);
545 ptr += sizeof (gpointer);
549 MonoDebugMethodAddress *
550 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
552 MonoMethod *declaring;
553 MonoDebugDataTable *table;
554 MonoDebugMethodHeader *header;
555 MonoDebugMethodAddress *address;
556 MonoDebugMethodInfo *minfo;
557 MonoDebugHandle *handle;
558 guint8 buffer [BUFSIZ];
559 guint8 *ptr, *oldptr;
560 guint32 i, size, total_size, max_size;
561 gboolean is_wrapper = FALSE;
563 mono_debugger_lock ();
565 table = lookup_data_table (domain);
567 handle = _mono_debug_get_image (method->klass->image);
568 minfo = _mono_debug_lookup_method (method);
570 if (!minfo || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
571 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
572 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
573 (method->flags & METHOD_ATTRIBUTE_ABSTRACT) ||
574 (method->wrapper_type != MONO_WRAPPER_NONE)) {
578 max_size = 24 + 8 * jit->num_line_numbers +
579 (20 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
581 if (max_size > BUFSIZ)
582 ptr = oldptr = g_malloc (max_size);
584 ptr = oldptr = buffer;
586 write_leb128 (jit->prologue_end, ptr, &ptr);
587 write_leb128 (jit->epilogue_begin, ptr, &ptr);
589 write_leb128 (jit->num_line_numbers, ptr, &ptr);
590 for (i = 0; i < jit->num_line_numbers; i++) {
591 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
593 write_sleb128 (lne->il_offset, ptr, &ptr);
594 write_sleb128 (lne->native_offset, ptr, &ptr);
597 *ptr++ = jit->this_var ? 1 : 0;
599 write_variable (jit->this_var, ptr, &ptr);
601 write_leb128 (jit->num_params, ptr, &ptr);
602 for (i = 0; i < jit->num_params; i++)
603 write_variable (&jit->params [i], ptr, &ptr);
605 write_leb128 (jit->num_locals, ptr, &ptr);
606 for (i = 0; i < jit->num_locals; i++)
607 write_variable (&jit->locals [i], ptr, &ptr);
610 g_assert (size < max_size);
611 total_size = size + sizeof (MonoDebugMethodAddress);
613 address = (MonoDebugMethodAddress *) allocate_data_item (
614 table, MONO_DEBUG_DATA_ITEM_METHOD, total_size);
616 address->header.size = total_size;
617 address->header.symfile_id = handle ? handle->index : 0;
618 address->header.domain_id = mono_domain_get_id (domain);
619 address->header.method_id = is_wrapper ? 0 : minfo->index;
620 address->header.method = method;
622 address->code_start = jit->code_start;
623 address->code_size = jit->code_size;
625 memcpy (&address->data, oldptr, size);
626 if (max_size > BUFSIZ)
629 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
630 header = g_hash_table_lookup (table->method_hash, declaring);
633 header = &address->header;
634 g_hash_table_insert (table->method_hash, declaring, header);
637 const unsigned char* il_code;
638 MonoMethodHeader *mheader;
639 MonoDebugWrapperData *wrapper;
642 mheader = mono_method_get_header (declaring);
643 il_code = mono_method_header_get_code (mheader, &il_codesize, NULL);
645 header->wrapper_data = wrapper = g_new0 (MonoDebugWrapperData, 1);
647 wrapper->wrapper_type = method->wrapper_type;
648 wrapper->method_name = mono_method_full_name (declaring, TRUE);
649 wrapper->cil_code = mono_disasm_code (
650 NULL, declaring, il_code, il_code + il_codesize);
653 address->header.wrapper_data = header->wrapper_data;
654 header->address_list = g_slist_prepend (header->address_list, address);
657 g_hash_table_insert (table->method_address_hash, method, address);
659 write_data_item (table, (guint8 *) address);
661 mono_debugger_unlock ();
666 mono_debug_add_delegate_trampoline (gpointer code, int size)
668 MonoDebugDelegateTrampolineEntry *entry;
670 if (!mono_debug_initialized)
673 mono_debugger_lock ();
675 entry = (MonoDebugDelegateTrampolineEntry *) allocate_data_item (
676 mono_symbol_table->global_data_table, MONO_DEBUG_DATA_ITEM_DELEGATE_TRAMPOLINE,
677 sizeof (MonoDebugDelegateTrampolineEntry));
681 write_data_item (mono_symbol_table->global_data_table, (guint8 *) entry);
683 mono_debugger_unlock ();
686 static inline guint32
687 read_leb128 (guint8 *ptr, guint8 **rptr)
689 guint32 result = 0, shift = 0;
692 guint8 byte = *ptr++;
694 result |= (byte & 0x7f) << shift;
695 if ((byte & 0x80) == 0)
705 read_sleb128 (guint8 *ptr, guint8 **rptr)
711 guint8 byte = *ptr++;
713 result |= (byte & 0x7f) << shift;
719 if ((shift < 32) && (byte & 0x40))
720 result |= - (1 << shift);
729 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
731 var->index = read_leb128 (ptr, &ptr);
732 var->offset = read_sleb128 (ptr, &ptr);
733 var->size = read_leb128 (ptr, &ptr);
734 var->begin_scope = read_leb128 (ptr, &ptr);
735 var->end_scope = read_leb128 (ptr, &ptr);
736 READ_UNALIGNED (gpointer, ptr, var->type);
737 ptr += sizeof (gpointer);
742 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
746 g_free (jit->line_numbers);
747 g_free (jit->this_var);
748 g_free (jit->params);
749 g_free (jit->locals);
753 static MonoDebugMethodJitInfo *
754 mono_debug_read_method (MonoDebugMethodAddress *address)
756 MonoDebugMethodJitInfo *jit;
760 jit = g_new0 (MonoDebugMethodJitInfo, 1);
761 jit->code_start = address->code_start;
762 jit->code_size = address->code_size;
763 jit->wrapper_addr = address->wrapper_addr;
765 ptr = (guint8 *) &address->data;
767 jit->prologue_end = read_leb128 (ptr, &ptr);
768 jit->epilogue_begin = read_leb128 (ptr, &ptr);
770 jit->num_line_numbers = read_leb128 (ptr, &ptr);
771 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
772 for (i = 0; i < jit->num_line_numbers; i++) {
773 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
775 lne->il_offset = read_sleb128 (ptr, &ptr);
776 lne->native_offset = read_sleb128 (ptr, &ptr);
780 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
781 read_variable (jit->this_var, ptr, &ptr);
784 jit->num_params = read_leb128 (ptr, &ptr);
785 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
786 for (i = 0; i < jit->num_params; i++)
787 read_variable (&jit->params [i], ptr, &ptr);
789 jit->num_locals = read_leb128 (ptr, &ptr);
790 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
791 for (i = 0; i < jit->num_locals; i++)
792 read_variable (&jit->locals [i], ptr, &ptr);
798 mono_debug_add_type (MonoClass *klass)
800 MonoDebugHandle *handle;
801 MonoDebugClassEntry *entry;
802 guint8 buffer [BUFSIZ];
803 guint8 *ptr, *oldptr;
804 guint32 size, total_size, max_size;
807 handle = _mono_debug_get_image (klass->image);
811 if (klass->generic_class || klass->rank ||
812 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
815 mono_debugger_lock ();
817 max_size = 12 + sizeof (gpointer);
818 if (max_size > BUFSIZ)
819 ptr = oldptr = g_malloc (max_size);
821 ptr = oldptr = buffer;
823 if (klass->valuetype)
824 base_offset = - (int)(sizeof (MonoObject));
826 write_leb128 (klass->type_token, ptr, &ptr);
827 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
828 WRITE_UNALIGNED (gpointer, ptr, klass);
829 ptr += sizeof (gpointer);
832 g_assert (size < max_size);
833 total_size = size + sizeof (MonoDebugClassEntry);
835 g_assert (total_size + 9 < DATA_TABLE_CHUNK_SIZE);
837 entry = (MonoDebugClassEntry *) allocate_data_item (
838 handle->type_table, MONO_DEBUG_DATA_ITEM_CLASS, total_size);
840 entry->size = total_size;
842 memcpy (&entry->data, oldptr, size);
844 write_data_item (handle->type_table, (guint8 *) entry);
846 if (max_size > BUFSIZ)
849 mono_debugger_unlock ();
852 static MonoDebugMethodJitInfo *
853 find_method (MonoMethod *method, MonoDomain *domain)
855 MonoDebugDataTable *table;
856 MonoDebugMethodAddress *address;
858 table = lookup_data_table (domain);
859 address = g_hash_table_lookup (table->method_address_hash, method);
864 return mono_debug_read_method (address);
867 MonoDebugMethodJitInfo *
868 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
870 MonoDebugMethodJitInfo *res;
872 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
875 mono_debugger_lock ();
876 res = find_method (method, domain);
877 mono_debugger_unlock ();
881 struct LookupMethodAddressData
884 MonoDebugMethodHeader *result;
888 lookup_method_address_func (gpointer key, gpointer value, gpointer user_data)
890 MonoDebugDataTable *table = (MonoDebugDataTable *) value;
891 struct LookupMethodAddressData *data = (struct LookupMethodAddressData *) user_data;
892 MonoDebugMethodHeader *header;
894 header = g_hash_table_lookup (table->method_hash, data->method);
896 data->result = header;
899 MonoDebugMethodAddressList *
900 mono_debug_lookup_method_addresses (MonoMethod *method)
902 MonoDebugMethodAddressList *info;
903 MonoDebugMethodHeader *header = NULL;
904 struct LookupMethodAddressData data;
905 MonoMethod *declaring;
910 g_assert (mono_debug_debugger_version == 4);
912 mono_debugger_lock ();
914 declaring = method->is_inflated ? ((MonoMethodInflated *) method)->declaring : method;
916 data.method = declaring;
919 g_hash_table_foreach (data_table_hash, lookup_method_address_func, &data);
920 header = data.result;
923 mono_debugger_unlock ();
927 count = g_slist_length (header->address_list) + 1;
928 size = sizeof (MonoDebugMethodAddressList) + count * sizeof (gpointer);
930 info = g_malloc0 (size);
936 WRITE_UNALIGNED (gpointer, ptr, header);
937 ptr += sizeof (gpointer);
939 for (list = header->address_list; list; list = list->next) {
940 WRITE_UNALIGNED (gpointer, ptr, list->data);
941 ptr += sizeof (gpointer);
944 mono_debugger_unlock ();
949 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
951 MonoDebugMethodJitInfo *jit;
954 jit = find_method (method, domain);
955 if (!jit || !jit->line_numbers)
956 goto cleanup_and_fail;
958 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
959 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
961 if (lne.native_offset <= native_offset) {
962 mono_debug_free_method_jit_info (jit);
963 return lne.il_offset;
968 mono_debug_free_method_jit_info (jit);
973 * mono_debug_lookup_source_location:
974 * @address: Native offset within the @method's machine code.
976 * Lookup the source code corresponding to the machine instruction located at
977 * native offset @address within @method.
979 * The returned `MonoDebugSourceLocation' contains both file / line number
980 * information and the corresponding IL offset. It must be freed by
981 * mono_debug_free_source_location().
983 MonoDebugSourceLocation *
984 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
986 MonoDebugMethodInfo *minfo;
987 MonoDebugSourceLocation *location;
990 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
993 mono_debugger_lock ();
994 minfo = _mono_debug_lookup_method (method);
995 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
996 mono_debugger_unlock ();
1000 offset = il_offset_from_address (method, domain, address);
1002 mono_debugger_unlock ();
1006 location = mono_debug_symfile_lookup_location (minfo, offset);
1007 mono_debugger_unlock ();
1012 * mono_debug_free_source_location:
1013 * @location: A `MonoDebugSourceLocation'.
1015 * Frees the @location.
1018 mono_debug_free_source_location (MonoDebugSourceLocation *location)
1021 g_free (location->source_file);
1027 * mono_debug_print_stack_frame:
1028 * @native_offset: Native offset within the @method's machine code.
1030 * Conventient wrapper around mono_debug_lookup_source_location() which can be
1031 * used if you only want to use the location to print a stack frame.
1034 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
1036 MonoDebugSourceLocation *location;
1037 gchar *fname, *ptr, *res;
1039 fname = mono_method_full_name (method, TRUE);
1040 for (ptr = fname; *ptr; ptr++) {
1041 if (*ptr == ':') *ptr = '.';
1044 location = mono_debug_lookup_source_location (method, native_offset, domain);
1047 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
1052 res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
1053 location->source_file, location->row);
1056 mono_debug_free_source_location (location);
1061 mono_debug_list_add (MonoDebugList **list, gconstpointer data)
1063 MonoDebugList *element, **ptr;
1065 element = g_new0 (MonoDebugList, 1);
1066 element->data = data;
1068 for (ptr = list; *ptr; ptr = &(*ptr)->next)
1075 mono_debug_list_remove (MonoDebugList **list, gconstpointer data)
1077 MonoDebugList **ptr;
1078 MonoDebugList *next;
1080 for (ptr = list; *ptr; ptr = &(*ptr)->next) {
1081 if ((*ptr)->data != data)
1084 next = (*ptr)->next;