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 32768
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 mono_debugger_initialize (in_the_mono_debugger);
79 mono_debugger_lock ();
81 mono_symbol_table = g_new0 (MonoSymbolTable, 1);
82 mono_symbol_table->magic = MONO_DEBUGGER_MAGIC;
83 mono_symbol_table->version = MONO_DEBUGGER_VERSION;
84 mono_symbol_table->total_size = sizeof (MonoSymbolTable);
86 mono_debug_handles = g_hash_table_new_full
87 (NULL, NULL, NULL, (GDestroyNotify) mono_debug_close_image);
88 method_hash = g_hash_table_new (method_hash_hash, method_hash_equal);
90 mono_debugger_start_class_init_func = mono_debug_start_add_type;
91 mono_debugger_class_init_func = mono_debug_add_type;
92 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
96 mono_debug_init_1 (MonoDomain *domain)
98 MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
100 if (in_the_mono_debugger)
101 mono_debugger_add_builtin_types (handle);
105 * Initialize debugging support - part 2.
107 * This method must be called after loading the application's main assembly.
110 mono_debug_init_2 (MonoAssembly *assembly)
112 mono_debug_open_image (mono_assembly_get_image (assembly));
116 mono_debug_cleanup (void)
118 mono_debugger_cleanup ();
120 if (mono_debug_handles)
121 g_hash_table_destroy (mono_debug_handles);
122 mono_debug_handles = NULL;
125 static MonoDebugHandle *
126 _mono_debug_get_image (MonoImage *image)
128 return g_hash_table_lookup (mono_debug_handles, image);
131 static MonoDebugHandle *
132 allocate_debug_handle (MonoSymbolTable *table)
134 MonoDebugHandle *handle;
136 if (!table->symbol_files)
137 table->symbol_files = g_new0 (MonoDebugHandle *, SYMFILE_TABLE_CHUNK_SIZE);
138 else if (!((table->num_symbol_files + 1) % SYMFILE_TABLE_CHUNK_SIZE)) {
139 guint32 chunks = (table->num_symbol_files + 1) / SYMFILE_TABLE_CHUNK_SIZE;
140 guint32 size = sizeof (MonoDebugHandle *) * SYMFILE_TABLE_CHUNK_SIZE * (chunks + 1);
142 table->symbol_files = g_realloc (table->symbol_files, size);
145 handle = g_new0 (MonoDebugHandle, 1);
146 handle->index = table->num_symbol_files;
147 table->symbol_files [table->num_symbol_files++] = handle;
151 static MonoDebugHandle *
152 mono_debug_open_image (MonoImage *image)
154 MonoDebugHandle *handle;
156 if (mono_image_is_dynamic (image))
159 handle = _mono_debug_get_image (image);
163 handle = allocate_debug_handle (mono_symbol_table);
165 handle->image = image;
166 mono_image_addref (image);
167 handle->image_file = g_strdup (mono_image_get_filename (image));
169 g_hash_table_insert (mono_debug_handles, image, handle);
171 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
172 if (in_the_mono_debugger)
173 mono_debugger_add_symbol_file (handle);
179 mono_debug_close_image (MonoDebugHandle *handle)
182 mono_debug_close_mono_symbol_file (handle->symfile);
183 /* decrease the refcount added with mono_image_addref () */
184 mono_image_close (handle->image);
185 g_free (handle->image_file);
186 g_free (handle->_priv);
191 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
193 mono_debugger_lock ();
194 mono_debug_open_image (mono_assembly_get_image (assembly));
195 mono_debugger_unlock ();
199 * Allocate a new data item of size `size'.
200 * Returns the global offset which is to be used to reference this data item and
201 * a pointer (in the `ptr' argument) which is to be used to write it.
204 allocate_data_item (MonoDebugDataItemType type, guint32 size)
209 g_assert (mono_symbol_table);
211 if (size + 12 < DATA_TABLE_CHUNK_SIZE)
212 chunk_size = DATA_TABLE_CHUNK_SIZE;
214 chunk_size = size + 12;
216 /* Initialize things if necessary. */
217 if (!mono_symbol_table->current_data_table) {
218 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
219 mono_symbol_table->current_data_table_size = chunk_size;
220 mono_symbol_table->current_data_table_offset = 4;
222 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
226 /* First let's check whether there's still enough room in the current_data_table. */
227 if (mono_symbol_table->current_data_table_offset + size + 8 < mono_symbol_table->current_data_table_size) {
228 data = ((guint8 *) mono_symbol_table->current_data_table) + mono_symbol_table->current_data_table_offset;
229 mono_symbol_table->current_data_table_offset += size + 8;
231 * ((guint32 *) data) = size;
233 * ((guint32 *) data) = type;
238 /* Add the current_data_table to the data_tables vector and ... */
239 if (!mono_symbol_table->data_tables) {
240 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE;
241 mono_symbol_table->data_tables = g_malloc0 (tsize);
244 if (!((mono_symbol_table->num_data_tables + 1) % DATA_TABLE_PTR_CHUNK_SIZE)) {
245 guint32 chunks = (mono_symbol_table->num_data_tables + 1) / DATA_TABLE_PTR_CHUNK_SIZE;
246 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
248 mono_symbol_table->data_tables = g_realloc (mono_symbol_table->data_tables, tsize);
251 mono_symbol_table->data_tables [mono_symbol_table->num_data_tables++] = mono_symbol_table->current_data_table;
253 /* .... allocate a new current_data_table. */
254 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
255 mono_symbol_table->current_data_table_size = chunk_size;
256 mono_symbol_table->current_data_table_offset = 4;
257 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
262 struct LookupMethodData
264 MonoDebugMethodInfo *minfo;
269 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
271 MonoDebugHandle *handle = (MonoDebugHandle *) value;
272 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
278 data->minfo = mono_debug_find_method (handle, data->method);
281 static MonoDebugMethodInfo *
282 _mono_debug_lookup_method (MonoMethod *method)
284 struct LookupMethodData data;
287 data.method = method;
289 if (!mono_debug_handles)
292 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
297 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
300 guint8 byte = value & 0x7f;
311 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
316 guint8 byte = value & 0x7f;
319 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
330 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
332 write_leb128 (var->index, ptr, &ptr);
333 write_sleb128 (var->offset, ptr, &ptr);
334 write_leb128 (var->size, ptr, &ptr);
335 write_leb128 (var->begin_scope, ptr, &ptr);
336 write_leb128 (var->end_scope, ptr, &ptr);
341 * This is called by the JIT to tell the debugging code about a newly
344 MonoDebugMethodAddress *
345 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
347 MonoDebugMethodAddress *address;
348 char buffer [BUFSIZ];
349 guint8 *ptr, *oldptr;
350 guint32 i, size, total_size, max_size;
351 gint32 last_il_offset = 0, last_native_offset = 0;
352 MonoDebugHandle *handle;
353 MonoDebugMethodInfo *minfo;
354 MethodHashEntry *hash;
356 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
357 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
358 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
359 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
362 if (method->wrapper_type != MONO_WRAPPER_NONE)
365 mono_debugger_lock ();
367 handle = _mono_debug_get_image (method->klass->image);
368 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
369 mono_debugger_unlock ();
373 minfo = _mono_debug_lookup_method (method);
375 mono_debugger_unlock ();
379 max_size = 24 + 8 * jit->num_line_numbers + 16 * minfo->num_lexical_blocks + 20 * (1 + jit->num_params + jit->num_locals);
380 if (max_size > BUFSIZ)
381 ptr = oldptr = g_malloc (max_size);
383 ptr = oldptr = buffer;
385 write_leb128 (jit->prologue_end, ptr, &ptr);
386 write_leb128 (jit->epilogue_begin, ptr, &ptr);
388 write_leb128 (jit->num_line_numbers, ptr, &ptr);
389 for (i = 0; i < jit->num_line_numbers; i++) {
390 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
392 write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
393 write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
395 last_il_offset = lne->il_offset;
396 last_native_offset = lne->native_offset;
399 jit->num_lexical_blocks = minfo->num_lexical_blocks;
400 jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
401 for (i = 0; i < jit->num_lexical_blocks; i ++) {
402 MonoDebugLexicalBlockEntry *jit_lbe = &jit->lexical_blocks [i];
403 MonoSymbolFileLexicalBlockEntry *minfo_lbe = &minfo->lexical_blocks [i];
405 jit_lbe->il_start_offset = minfo_lbe->_start_offset;
406 jit_lbe->native_start_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_start_offset);
408 jit_lbe->il_end_offset = minfo_lbe->_end_offset;
409 jit_lbe->native_end_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_end_offset);
413 last_native_offset = 0;
414 write_leb128 (jit->num_lexical_blocks, ptr, &ptr);
415 for (i = 0; i < jit->num_lexical_blocks; i++) {
416 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
418 write_sleb128 (lbe->il_start_offset - last_il_offset, ptr, &ptr);
419 write_sleb128 (lbe->native_start_offset - last_native_offset, ptr, &ptr);
421 last_il_offset = lbe->il_start_offset;
422 last_native_offset = lbe->native_start_offset;
424 write_sleb128 (lbe->il_end_offset - last_il_offset, ptr, &ptr);
425 write_sleb128 (lbe->native_end_offset - last_native_offset, ptr, &ptr);
427 last_il_offset = lbe->il_end_offset;
428 last_native_offset = lbe->native_end_offset;
431 *ptr++ = jit->this_var ? 1 : 0;
433 write_variable (jit->this_var, ptr, &ptr);
435 write_leb128 (jit->num_params, ptr, &ptr);
436 for (i = 0; i < jit->num_params; i++)
437 write_variable (&jit->params [i], ptr, &ptr);
439 write_leb128 (jit->num_locals, ptr, &ptr);
440 for (i = 0; i < jit->num_locals; i++)
441 write_variable (&jit->locals [i], ptr, &ptr);
444 g_assert (size < max_size);
445 total_size = size + sizeof (MonoDebugMethodAddress);
447 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
448 // FIXME: Maybe we should print a warning here.
449 // This should only happen for very big methods, for instance
450 // with more than 40.000 line numbers and more than 5.000
455 address = (MonoDebugMethodAddress *) allocate_data_item (MONO_DEBUG_DATA_ITEM_METHOD, total_size);
457 address->size = total_size;
458 address->symfile_id = handle->index;
459 address->domain_id = mono_domain_get_id (domain);
460 address->method_id = minfo->index;
461 address->code_start = jit->code_start;
462 address->code_size = jit->code_size;
463 address->wrapper_addr = jit->wrapper_addr;
465 memcpy (&address->data, oldptr, size);
467 if (max_size > BUFSIZ)
470 hash = g_new0 (MethodHashEntry, 1);
471 hash->symfile_id = address->symfile_id;
472 hash->domain_id = address->domain_id;
473 hash->method_id = address->method_id;
475 g_hash_table_insert (method_hash, hash, address);
477 if (in_the_mono_debugger)
478 mono_debugger_add_method (jit);
480 mono_debugger_unlock ();
485 static inline guint32
486 read_leb128 (guint8 *ptr, guint8 **rptr)
488 guint32 result = 0, shift = 0;
491 guint8 byte = *ptr++;
493 result |= (byte & 0x7f) << shift;
494 if ((byte & 0x80) == 0)
504 read_sleb128 (guint8 *ptr, guint8 **rptr)
510 guint8 byte = *ptr++;
512 result |= (byte & 0x7f) << shift;
518 if ((shift < 32) && (byte & 0x40))
519 result |= - (1 << shift);
528 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
530 var->index = read_leb128 (ptr, &ptr);
531 var->offset = read_sleb128 (ptr, &ptr);
532 var->size = read_leb128 (ptr, &ptr);
533 var->begin_scope = read_leb128 (ptr, &ptr);
534 var->end_scope = read_leb128 (ptr, &ptr);
538 MonoDebugMethodJitInfo *
539 mono_debug_read_method (MonoDebugMethodAddress *address)
541 MonoDebugMethodJitInfo *jit;
542 guint32 i, il_offset = 0, native_offset = 0;
548 jit = address->jit = g_new0 (MonoDebugMethodJitInfo, 1);
549 jit->code_start = address->code_start;
550 jit->code_size = address->code_size;
551 jit->wrapper_addr = address->wrapper_addr;
553 ptr = (guint8 *) &address->data;
555 jit->prologue_end = read_leb128 (ptr, &ptr);
556 jit->epilogue_begin = read_leb128 (ptr, &ptr);
558 jit->num_line_numbers = read_leb128 (ptr, &ptr);
559 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
560 for (i = 0; i < jit->num_line_numbers; i++) {
561 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
563 il_offset += read_sleb128 (ptr, &ptr);
564 native_offset += read_sleb128 (ptr, &ptr);
566 lne->il_offset = il_offset;
567 lne->native_offset = native_offset;
572 jit->num_lexical_blocks = read_leb128 (ptr, &ptr);
573 jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
574 for (i = 0; i < jit->num_lexical_blocks; i ++) {
575 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
577 il_offset += read_sleb128 (ptr, &ptr);
578 native_offset += read_sleb128 (ptr, &ptr);
580 lbe->il_start_offset = il_offset;
581 lbe->native_start_offset = native_offset;
583 il_offset += read_sleb128 (ptr, &ptr);
584 native_offset += read_sleb128 (ptr, &ptr);
586 lbe->il_end_offset = il_offset;
587 lbe->native_end_offset = native_offset;
591 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
592 read_variable (jit->this_var, ptr, &ptr);
595 jit->num_params = read_leb128 (ptr, &ptr);
596 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
597 for (i = 0; i < jit->num_params; i++)
598 read_variable (&jit->params [i], ptr, &ptr);
600 jit->num_locals = read_leb128 (ptr, &ptr);
601 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
602 for (i = 0; i < jit->num_locals; i++)
603 read_variable (&jit->locals [i], ptr, &ptr);
609 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
612 jit->address->jit = NULL;
614 g_free (jit->line_numbers);
615 g_free (jit->this_var);
616 g_free (jit->params);
617 g_free (jit->locals);
622 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
623 * a new class is initialized.
626 mono_debug_start_add_type (MonoClass *klass)
628 MonoDebugHandle *handle;
630 handle = _mono_debug_get_image (klass->image);
634 if (in_the_mono_debugger)
635 mono_debugger_add_type (handle, klass);
639 get_token (MonoClass *klass)
642 klass = klass->element_class;
644 return klass->type_token;
648 mono_debug_add_type (MonoClass *klass)
650 MonoDebugHandle *handle;
651 MonoDebugClassEntry *entry;
652 char buffer [BUFSIZ];
653 guint8 *ptr, *oldptr;
654 guint32 token, size, total_size, max_size;
657 handle = _mono_debug_get_image (klass->image);
661 if (klass->generic_class ||
662 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
665 max_size = 12 + sizeof (gpointer);
666 if (max_size > BUFSIZ)
667 ptr = oldptr = g_malloc (max_size);
669 ptr = oldptr = buffer;
671 token = get_token (klass);
675 if (klass->valuetype)
676 base_offset = - (int)(sizeof (MonoObject));
678 write_leb128 (token, ptr, &ptr);
679 write_leb128 (klass->rank, ptr, &ptr);
680 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
681 * ((gpointer *) ptr) = klass;
682 ptr += sizeof (gpointer);
685 g_assert (size < max_size);
686 total_size = size + sizeof (MonoDebugClassEntry);
688 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
689 // FIXME: Maybe we should print a warning here.
690 // This should only happen for very big methods, for instance
691 // with more than 40.000 line numbers and more than 5.000
696 entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size);
698 entry->size = total_size;
699 entry->symfile_id = handle->index;
701 memcpy (&entry->data, oldptr, size);
703 if (max_size > BUFSIZ)
706 mono_debugger_start_add_type (handle, klass);
709 static MonoDebugMethodJitInfo *
710 find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain)
712 MethodHashEntry lookup;
713 MonoDebugMethodAddress *address;
715 lookup.symfile_id = minfo->handle->index;
716 lookup.domain_id = mono_domain_get_id (domain);
717 lookup.method_id = minfo->index;
719 address = g_hash_table_lookup (method_hash, &lookup);
723 return mono_debug_read_method (address);
727 il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset)
729 MonoDebugMethodJitInfo *jit;
732 jit = find_method (minfo, domain);
733 if (!jit || !jit->line_numbers)
736 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
737 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
739 if (lne.native_offset <= native_offset)
740 return lne.il_offset;
747 * mono_debug_source_location_from_address:
753 * Used by the exception code to get a source location from a machine address.
755 * Returns: a textual representation of the specified address which is suitable to be displayed to
756 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
758 * If the optional @line_number argument is not NULL, the line number is stored there and just the
759 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
760 * line number 8 in the variable pointed to by @line_number).
763 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
766 MonoDebugMethodInfo *minfo;
771 minfo = _mono_debug_lookup_method (method);
772 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
773 mono_loader_unlock ();
777 offset = il_offset_from_address (minfo, domain, address);
780 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
782 mono_loader_unlock ();
787 * mono_debug_source_location_from_il_offset:
792 * Used by the exception code to get a source location from an IL offset.
794 * Returns a textual representation of the specified address which is suitable to be displayed to
795 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
797 * If the optional @line_number argument is not NULL, the line number is stored there and just the
798 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
799 * line number 8 in the variable pointed to by @line_number).
802 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
805 MonoDebugMethodInfo *minfo;
808 minfo = _mono_debug_lookup_method (method);
809 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
810 mono_loader_unlock ();
814 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
815 mono_loader_unlock ();
820 * mono_debug_il_offset_from_address:
825 * Returns: the IL offset corresponding to machine address @address which is an offset
826 * relative to the beginning of the method @method.
829 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
831 MonoDebugMethodInfo *minfo;
838 minfo = _mono_debug_lookup_method (method);
839 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
840 !minfo->handle->symfile->offset_table) {
841 mono_loader_unlock ();
845 res = il_offset_from_address (minfo, domain, address);
846 mono_loader_unlock ();
851 * mono_debug_address_from_il_offset:
856 * Returns: the machine address corresponding to IL offset @il_offset.
857 * The returned value is an offset relative to the beginning of the method @method.
860 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
862 MonoDebugMethodInfo *minfo;
863 MonoDebugMethodJitInfo *jit;
870 minfo = _mono_debug_lookup_method (method);
871 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
872 !minfo->handle->symfile->offset_table) {
873 mono_loader_unlock ();
877 jit = find_method (minfo, domain);
879 mono_loader_unlock ();
883 res = _mono_debug_address_from_il_offset (jit, il_offset);
884 mono_loader_unlock ();