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 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 if (mono_image_is_dynamic (image))
160 handle = _mono_debug_get_image (image);
164 handle = allocate_debug_handle (mono_symbol_table);
166 handle->image = image;
167 mono_image_addref (image);
168 handle->image_file = g_strdup (mono_image_get_filename (image));
170 g_hash_table_insert (mono_debug_handles, image, handle);
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 g_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 (MonoDebugDataItemType type, guint32 size)
210 g_assert (mono_symbol_table);
212 if (size + 12 < DATA_TABLE_CHUNK_SIZE)
213 chunk_size = DATA_TABLE_CHUNK_SIZE;
215 chunk_size = size + 12;
217 /* Initialize things if necessary. */
218 if (!mono_symbol_table->current_data_table) {
219 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
220 mono_symbol_table->current_data_table_size = chunk_size;
221 mono_symbol_table->current_data_table_offset = 4;
223 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
227 /* First let's check whether there's still enough room in the current_data_table. */
228 if (mono_symbol_table->current_data_table_offset + size + 8 < mono_symbol_table->current_data_table_size) {
229 data = ((guint8 *) mono_symbol_table->current_data_table) + mono_symbol_table->current_data_table_offset;
230 mono_symbol_table->current_data_table_offset += size + 8;
232 * ((guint32 *) data) = size;
234 * ((guint32 *) data) = type;
239 /* Add the current_data_table to the data_tables vector and ... */
240 if (!mono_symbol_table->data_tables) {
241 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE;
242 mono_symbol_table->data_tables = g_malloc0 (tsize);
245 if (!((mono_symbol_table->num_data_tables + 1) % DATA_TABLE_PTR_CHUNK_SIZE)) {
246 guint32 chunks = (mono_symbol_table->num_data_tables + 1) / DATA_TABLE_PTR_CHUNK_SIZE;
247 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
249 mono_symbol_table->data_tables = g_realloc (mono_symbol_table->data_tables, tsize);
252 mono_symbol_table->data_tables [mono_symbol_table->num_data_tables++] = mono_symbol_table->current_data_table;
254 /* .... allocate a new current_data_table. */
255 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
256 mono_symbol_table->current_data_table_size = chunk_size;
257 mono_symbol_table->current_data_table_offset = 4;
258 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
263 struct LookupMethodData
265 MonoDebugMethodInfo *minfo;
270 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
272 MonoDebugHandle *handle = (MonoDebugHandle *) value;
273 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
279 data->minfo = mono_debug_find_method (handle, data->method);
282 static MonoDebugMethodInfo *
283 _mono_debug_lookup_method (MonoMethod *method)
285 struct LookupMethodData data;
288 data.method = method;
290 if (!mono_debug_handles)
293 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
298 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
301 guint8 byte = value & 0x7f;
312 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
317 guint8 byte = value & 0x7f;
320 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
331 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
333 write_leb128 (var->index, ptr, &ptr);
334 write_sleb128 (var->offset, ptr, &ptr);
335 write_leb128 (var->size, ptr, &ptr);
336 write_leb128 (var->begin_scope, ptr, &ptr);
337 write_leb128 (var->end_scope, ptr, &ptr);
342 * This is called by the JIT to tell the debugging code about a newly
345 MonoDebugMethodAddress *
346 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
348 MonoDebugMethodAddress *address;
349 char buffer [BUFSIZ];
350 guint8 *ptr, *oldptr;
351 guint32 i, size, total_size, max_size;
352 gint32 last_il_offset = 0, last_native_offset = 0;
353 MonoDebugHandle *handle;
354 MonoDebugMethodInfo *minfo;
355 MethodHashEntry *hash;
357 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
358 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
359 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
360 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
363 if (method->wrapper_type != MONO_WRAPPER_NONE)
366 mono_debugger_lock ();
368 handle = _mono_debug_get_image (method->klass->image);
369 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
370 mono_debugger_unlock ();
374 minfo = _mono_debug_lookup_method (method);
376 mono_debugger_unlock ();
380 max_size = 24 + 8 * jit->num_line_numbers + 16 * minfo->num_lexical_blocks + 20 * (1 + jit->num_params + jit->num_locals);
381 if (max_size > BUFSIZ)
382 ptr = oldptr = g_malloc (max_size);
384 ptr = oldptr = buffer;
386 write_leb128 (jit->prologue_end, ptr, &ptr);
387 write_leb128 (jit->epilogue_begin, ptr, &ptr);
389 write_leb128 (jit->num_line_numbers, ptr, &ptr);
390 for (i = 0; i < jit->num_line_numbers; i++) {
391 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
393 write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
394 write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
396 last_il_offset = lne->il_offset;
397 last_native_offset = lne->native_offset;
400 jit->num_lexical_blocks = minfo->num_lexical_blocks;
401 jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
402 for (i = 0; i < jit->num_lexical_blocks; i ++) {
403 MonoDebugLexicalBlockEntry *jit_lbe = &jit->lexical_blocks [i];
404 MonoSymbolFileLexicalBlockEntry *minfo_lbe = &minfo->lexical_blocks [i];
406 jit_lbe->il_start_offset = minfo_lbe->_start_offset;
407 jit_lbe->native_start_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_start_offset);
409 jit_lbe->il_end_offset = minfo_lbe->_end_offset;
410 jit_lbe->native_end_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_end_offset);
414 last_native_offset = 0;
415 write_leb128 (jit->num_lexical_blocks, ptr, &ptr);
416 for (i = 0; i < jit->num_lexical_blocks; i++) {
417 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
419 write_sleb128 (lbe->il_start_offset - last_il_offset, ptr, &ptr);
420 write_sleb128 (lbe->native_start_offset - last_native_offset, ptr, &ptr);
422 last_il_offset = lbe->il_start_offset;
423 last_native_offset = lbe->native_start_offset;
425 write_sleb128 (lbe->il_end_offset - last_il_offset, ptr, &ptr);
426 write_sleb128 (lbe->native_end_offset - last_native_offset, ptr, &ptr);
428 last_il_offset = lbe->il_end_offset;
429 last_native_offset = lbe->native_end_offset;
432 *ptr++ = jit->this_var ? 1 : 0;
434 write_variable (jit->this_var, ptr, &ptr);
436 write_leb128 (jit->num_params, ptr, &ptr);
437 for (i = 0; i < jit->num_params; i++)
438 write_variable (&jit->params [i], ptr, &ptr);
440 write_leb128 (jit->num_locals, ptr, &ptr);
441 for (i = 0; i < jit->num_locals; i++)
442 write_variable (&jit->locals [i], ptr, &ptr);
445 g_assert (size < max_size);
446 total_size = size + sizeof (MonoDebugMethodAddress);
448 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
449 // FIXME: Maybe we should print a warning here.
450 // This should only happen for very big methods, for instance
451 // with more than 40.000 line numbers and more than 5.000
456 address = (MonoDebugMethodAddress *) allocate_data_item (MONO_DEBUG_DATA_ITEM_METHOD, total_size);
458 address->size = total_size;
459 address->symfile_id = handle->index;
460 address->domain_id = mono_domain_get_id (domain);
461 address->method_id = minfo->index;
462 address->code_start = jit->code_start;
463 address->code_size = jit->code_size;
464 address->wrapper_addr = jit->wrapper_addr;
466 memcpy (&address->data, oldptr, size);
468 if (max_size > BUFSIZ)
471 hash = g_new0 (MethodHashEntry, 1);
472 hash->symfile_id = address->symfile_id;
473 hash->domain_id = address->domain_id;
474 hash->method_id = address->method_id;
476 g_hash_table_insert (method_hash, hash, address);
478 if (in_the_mono_debugger)
479 mono_debugger_add_method (jit);
481 mono_debugger_unlock ();
486 static inline guint32
487 read_leb128 (guint8 *ptr, guint8 **rptr)
489 guint32 result = 0, shift = 0;
492 guint8 byte = *ptr++;
494 result |= (byte & 0x7f) << shift;
495 if ((byte & 0x80) == 0)
505 read_sleb128 (guint8 *ptr, guint8 **rptr)
511 guint8 byte = *ptr++;
513 result |= (byte & 0x7f) << shift;
519 if ((shift < 32) && (byte & 0x40))
520 result |= - (1 << shift);
529 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
531 var->index = read_leb128 (ptr, &ptr);
532 var->offset = read_sleb128 (ptr, &ptr);
533 var->size = read_leb128 (ptr, &ptr);
534 var->begin_scope = read_leb128 (ptr, &ptr);
535 var->end_scope = read_leb128 (ptr, &ptr);
539 MonoDebugMethodJitInfo *
540 mono_debug_read_method (MonoDebugMethodAddress *address)
542 MonoDebugMethodJitInfo *jit;
543 guint32 i, il_offset = 0, native_offset = 0;
549 jit = address->jit = g_new0 (MonoDebugMethodJitInfo, 1);
550 jit->code_start = address->code_start;
551 jit->code_size = address->code_size;
552 jit->wrapper_addr = address->wrapper_addr;
554 ptr = (guint8 *) &address->data;
556 jit->prologue_end = read_leb128 (ptr, &ptr);
557 jit->epilogue_begin = read_leb128 (ptr, &ptr);
559 jit->num_line_numbers = read_leb128 (ptr, &ptr);
560 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
561 for (i = 0; i < jit->num_line_numbers; i++) {
562 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
564 il_offset += read_sleb128 (ptr, &ptr);
565 native_offset += read_sleb128 (ptr, &ptr);
567 lne->il_offset = il_offset;
568 lne->native_offset = native_offset;
573 jit->num_lexical_blocks = read_leb128 (ptr, &ptr);
574 jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
575 for (i = 0; i < jit->num_lexical_blocks; i ++) {
576 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
578 il_offset += read_sleb128 (ptr, &ptr);
579 native_offset += read_sleb128 (ptr, &ptr);
581 lbe->il_start_offset = il_offset;
582 lbe->native_start_offset = native_offset;
584 il_offset += read_sleb128 (ptr, &ptr);
585 native_offset += read_sleb128 (ptr, &ptr);
587 lbe->il_end_offset = il_offset;
588 lbe->native_end_offset = native_offset;
592 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
593 read_variable (jit->this_var, ptr, &ptr);
596 jit->num_params = read_leb128 (ptr, &ptr);
597 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
598 for (i = 0; i < jit->num_params; i++)
599 read_variable (&jit->params [i], ptr, &ptr);
601 jit->num_locals = read_leb128 (ptr, &ptr);
602 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
603 for (i = 0; i < jit->num_locals; i++)
604 read_variable (&jit->locals [i], ptr, &ptr);
610 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
613 jit->address->jit = NULL;
615 g_free (jit->line_numbers);
616 g_free (jit->this_var);
617 g_free (jit->params);
618 g_free (jit->locals);
623 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
624 * a new class is initialized.
627 mono_debug_start_add_type (MonoClass *klass)
629 MonoDebugHandle *handle;
631 handle = _mono_debug_get_image (klass->image);
635 if (in_the_mono_debugger)
636 mono_debugger_add_type (handle, klass);
640 get_token (MonoClass *klass)
643 klass = klass->element_class;
645 return klass->type_token;
649 mono_debug_add_type (MonoClass *klass)
651 MonoDebugHandle *handle;
652 MonoDebugClassEntry *entry;
653 char buffer [BUFSIZ];
654 guint8 *ptr, *oldptr;
655 guint32 token, size, total_size, max_size;
658 handle = _mono_debug_get_image (klass->image);
662 if (klass->generic_class ||
663 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
666 max_size = 12 + sizeof (gpointer);
667 if (max_size > BUFSIZ)
668 ptr = oldptr = g_malloc (max_size);
670 ptr = oldptr = buffer;
672 token = get_token (klass);
676 if (klass->valuetype)
677 base_offset = - (int)(sizeof (MonoObject));
679 write_leb128 (token, ptr, &ptr);
680 write_leb128 (klass->rank, ptr, &ptr);
681 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
682 * ((gpointer *) ptr) = klass;
683 ptr += sizeof (gpointer);
686 g_assert (size < max_size);
687 total_size = size + sizeof (MonoDebugClassEntry);
689 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
690 // FIXME: Maybe we should print a warning here.
691 // This should only happen for very big methods, for instance
692 // with more than 40.000 line numbers and more than 5.000
697 entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size);
699 entry->size = total_size;
700 entry->symfile_id = handle->index;
702 memcpy (&entry->data, oldptr, size);
704 if (max_size > BUFSIZ)
707 mono_debugger_start_add_type (handle, klass);
710 static MonoDebugMethodJitInfo *
711 find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain)
713 MethodHashEntry lookup;
714 MonoDebugMethodAddress *address;
716 lookup.symfile_id = minfo->handle->index;
717 lookup.domain_id = mono_domain_get_id (domain);
718 lookup.method_id = minfo->index;
720 address = g_hash_table_lookup (method_hash, &lookup);
724 return mono_debug_read_method (address);
728 il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset)
730 MonoDebugMethodJitInfo *jit;
733 jit = find_method (minfo, domain);
734 if (!jit || !jit->line_numbers)
737 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
738 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
740 if (lne.native_offset <= native_offset)
741 return lne.il_offset;
748 * mono_debug_source_location_from_address:
754 * Used by the exception code to get a source location from a machine address.
756 * Returns: a textual representation of the specified address which is suitable to be displayed to
757 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
759 * If the optional @line_number argument is not NULL, the line number is stored there and just the
760 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
761 * line number 8 in the variable pointed to by @line_number).
764 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
767 MonoDebugMethodInfo *minfo;
772 minfo = _mono_debug_lookup_method (method);
773 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
774 mono_loader_unlock ();
778 offset = il_offset_from_address (minfo, domain, address);
781 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
783 mono_loader_unlock ();
788 * mono_debug_source_location_from_il_offset:
793 * Used by the exception code to get a source location from an IL offset.
795 * Returns a textual representation of the specified address which is suitable to be displayed to
796 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
798 * If the optional @line_number argument is not NULL, the line number is stored there and just the
799 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
800 * line number 8 in the variable pointed to by @line_number).
803 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
806 MonoDebugMethodInfo *minfo;
809 minfo = _mono_debug_lookup_method (method);
810 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
811 mono_loader_unlock ();
815 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
816 mono_loader_unlock ();
821 * mono_debug_il_offset_from_address:
826 * Returns: the IL offset corresponding to machine address @address which is an offset
827 * relative to the beginning of the method @method.
830 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
832 MonoDebugMethodInfo *minfo;
839 minfo = _mono_debug_lookup_method (method);
840 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
841 !minfo->handle->symfile->offset_table) {
842 mono_loader_unlock ();
846 res = il_offset_from_address (minfo, domain, address);
847 mono_loader_unlock ();
852 * mono_debug_address_from_il_offset:
857 * Returns: the machine address corresponding to IL offset @il_offset.
858 * The returned value is an offset relative to the beginning of the method @method.
861 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
863 MonoDebugMethodInfo *minfo;
864 MonoDebugMethodJitInfo *jit;
871 minfo = _mono_debug_lookup_method (method);
872 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
873 !minfo->handle->symfile->offset_table) {
874 mono_loader_unlock ();
878 jit = find_method (minfo, domain);
880 mono_loader_unlock ();
884 res = _mono_debug_address_from_il_offset (jit, il_offset);
885 mono_loader_unlock ();