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);
94 if (!in_the_mono_debugger)
95 mono_debugger_unlock ();
99 mono_debug_init_1 (MonoDomain *domain)
101 MonoDebugHandle *handle = mono_debug_open_image (mono_get_corlib ());
103 if (in_the_mono_debugger)
104 mono_debugger_add_builtin_types (handle);
108 * Initialize debugging support - part 2.
110 * This method must be called after loading the application's main assembly.
113 mono_debug_init_2 (MonoAssembly *assembly)
115 mono_debug_open_image (mono_assembly_get_image (assembly));
119 mono_debug_cleanup (void)
121 mono_debugger_cleanup ();
123 if (mono_debug_handles)
124 g_hash_table_destroy (mono_debug_handles);
125 mono_debug_handles = NULL;
128 static MonoDebugHandle *
129 _mono_debug_get_image (MonoImage *image)
131 return g_hash_table_lookup (mono_debug_handles, image);
134 static MonoDebugHandle *
135 allocate_debug_handle (MonoSymbolTable *table)
137 MonoDebugHandle *handle;
139 if (!table->symbol_files)
140 table->symbol_files = g_new0 (MonoDebugHandle *, SYMFILE_TABLE_CHUNK_SIZE);
141 else if (!((table->num_symbol_files + 1) % SYMFILE_TABLE_CHUNK_SIZE)) {
142 guint32 chunks = (table->num_symbol_files + 1) / SYMFILE_TABLE_CHUNK_SIZE;
143 guint32 size = sizeof (MonoDebugHandle *) * SYMFILE_TABLE_CHUNK_SIZE * (chunks + 1);
145 table->symbol_files = g_realloc (table->symbol_files, size);
148 handle = g_new0 (MonoDebugHandle, 1);
149 handle->index = table->num_symbol_files;
150 table->symbol_files [table->num_symbol_files++] = handle;
154 static MonoDebugHandle *
155 mono_debug_open_image (MonoImage *image)
157 MonoDebugHandle *handle;
159 if (mono_image_is_dynamic (image))
162 handle = _mono_debug_get_image (image);
166 handle = allocate_debug_handle (mono_symbol_table);
168 handle->image = image;
169 mono_image_addref (image);
170 handle->image_file = g_strdup (mono_image_get_filename (image));
172 g_hash_table_insert (mono_debug_handles, image, handle);
174 handle->symfile = mono_debug_open_mono_symbol_file (handle, in_the_mono_debugger);
175 if (in_the_mono_debugger)
176 mono_debugger_add_symbol_file (handle);
182 mono_debug_close_image (MonoDebugHandle *handle)
185 mono_debug_close_mono_symbol_file (handle->symfile);
186 /* decrease the refcount added with mono_image_addref () */
187 mono_image_close (handle->image);
188 g_free (handle->image_file);
189 g_free (handle->_priv);
194 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
196 mono_debugger_lock ();
197 mono_debug_open_image (mono_assembly_get_image (assembly));
198 mono_debugger_unlock ();
202 * Allocate a new data item of size `size'.
203 * Returns the global offset which is to be used to reference this data item and
204 * a pointer (in the `ptr' argument) which is to be used to write it.
207 allocate_data_item (MonoDebugDataItemType type, guint32 size)
212 g_assert (mono_symbol_table);
214 if (size + 12 < DATA_TABLE_CHUNK_SIZE)
215 chunk_size = DATA_TABLE_CHUNK_SIZE;
217 chunk_size = size + 12;
219 /* Initialize things if necessary. */
220 if (!mono_symbol_table->current_data_table) {
221 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
222 mono_symbol_table->current_data_table_size = chunk_size;
223 mono_symbol_table->current_data_table_offset = 4;
225 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
229 /* First let's check whether there's still enough room in the current_data_table. */
230 if (mono_symbol_table->current_data_table_offset + size + 8 < mono_symbol_table->current_data_table_size) {
231 data = ((guint8 *) mono_symbol_table->current_data_table) + mono_symbol_table->current_data_table_offset;
232 mono_symbol_table->current_data_table_offset += size + 8;
234 * ((guint32 *) data) = size;
236 * ((guint32 *) data) = type;
241 /* Add the current_data_table to the data_tables vector and ... */
242 if (!mono_symbol_table->data_tables) {
243 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE;
244 mono_symbol_table->data_tables = g_malloc0 (tsize);
247 if (!((mono_symbol_table->num_data_tables + 1) % DATA_TABLE_PTR_CHUNK_SIZE)) {
248 guint32 chunks = (mono_symbol_table->num_data_tables + 1) / DATA_TABLE_PTR_CHUNK_SIZE;
249 guint32 tsize = sizeof (gpointer) * DATA_TABLE_PTR_CHUNK_SIZE * (chunks + 1);
251 mono_symbol_table->data_tables = g_realloc (mono_symbol_table->data_tables, tsize);
254 mono_symbol_table->data_tables [mono_symbol_table->num_data_tables++] = mono_symbol_table->current_data_table;
256 /* .... allocate a new current_data_table. */
257 mono_symbol_table->current_data_table = g_malloc0 (chunk_size);
258 mono_symbol_table->current_data_table_size = chunk_size;
259 mono_symbol_table->current_data_table_offset = 4;
260 * ((guint32 *) mono_symbol_table->current_data_table) = chunk_size;
265 struct LookupMethodData
267 MonoDebugMethodInfo *minfo;
272 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
274 MonoDebugHandle *handle = (MonoDebugHandle *) value;
275 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
281 data->minfo = mono_debug_find_method (handle, data->method);
284 static MonoDebugMethodInfo *
285 _mono_debug_lookup_method (MonoMethod *method)
287 struct LookupMethodData data;
290 data.method = method;
292 if (!mono_debug_handles)
295 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
300 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
303 guint8 byte = value & 0x7f;
314 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
319 guint8 byte = value & 0x7f;
322 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
333 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
335 write_leb128 (var->index, ptr, &ptr);
336 write_sleb128 (var->offset, ptr, &ptr);
337 write_leb128 (var->size, ptr, &ptr);
338 write_leb128 (var->begin_scope, ptr, &ptr);
339 write_leb128 (var->end_scope, ptr, &ptr);
344 * This is called by the JIT to tell the debugging code about a newly
347 MonoDebugMethodAddress *
348 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
350 MonoDebugMethodAddress *address;
351 char buffer [BUFSIZ];
352 guint8 *ptr, *oldptr;
353 guint32 i, size, total_size, max_size;
354 gint32 last_il_offset = 0, last_native_offset = 0;
355 MonoDebugHandle *handle;
356 MonoDebugMethodInfo *minfo;
357 MethodHashEntry *hash;
359 if ((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
360 (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) ||
361 (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) ||
362 (method->flags & METHOD_ATTRIBUTE_ABSTRACT))
365 if (method->wrapper_type != MONO_WRAPPER_NONE)
368 mono_debugger_lock ();
370 handle = _mono_debug_get_image (method->klass->image);
371 if (!handle || !handle->symfile || !handle->symfile->offset_table) {
372 mono_debugger_unlock ();
376 minfo = _mono_debug_lookup_method (method);
378 mono_debugger_unlock ();
382 max_size = 24 + 8 * jit->num_line_numbers + 16 * minfo->num_lexical_blocks + 20 * (1 + jit->num_params + jit->num_locals);
383 if (max_size > BUFSIZ)
384 ptr = oldptr = g_malloc (max_size);
386 ptr = oldptr = buffer;
388 write_leb128 (jit->prologue_end, ptr, &ptr);
389 write_leb128 (jit->epilogue_begin, ptr, &ptr);
391 write_leb128 (jit->num_line_numbers, ptr, &ptr);
392 for (i = 0; i < jit->num_line_numbers; i++) {
393 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
395 write_sleb128 (lne->il_offset - last_il_offset, ptr, &ptr);
396 write_sleb128 (lne->native_offset - last_native_offset, ptr, &ptr);
398 last_il_offset = lne->il_offset;
399 last_native_offset = lne->native_offset;
402 jit->num_lexical_blocks = minfo->num_lexical_blocks;
403 jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
404 for (i = 0; i < jit->num_lexical_blocks; i ++) {
405 MonoDebugLexicalBlockEntry *jit_lbe = &jit->lexical_blocks [i];
406 MonoSymbolFileLexicalBlockEntry *minfo_lbe = &minfo->lexical_blocks [i];
408 jit_lbe->il_start_offset = minfo_lbe->_start_offset;
409 jit_lbe->native_start_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_start_offset);
411 jit_lbe->il_end_offset = minfo_lbe->_end_offset;
412 jit_lbe->native_end_offset = _mono_debug_address_from_il_offset (jit, jit_lbe->il_end_offset);
416 last_native_offset = 0;
417 write_leb128 (jit->num_lexical_blocks, ptr, &ptr);
418 for (i = 0; i < jit->num_lexical_blocks; i++) {
419 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
421 write_sleb128 (lbe->il_start_offset - last_il_offset, ptr, &ptr);
422 write_sleb128 (lbe->native_start_offset - last_native_offset, ptr, &ptr);
424 last_il_offset = lbe->il_start_offset;
425 last_native_offset = lbe->native_start_offset;
427 write_sleb128 (lbe->il_end_offset - last_il_offset, ptr, &ptr);
428 write_sleb128 (lbe->native_end_offset - last_native_offset, ptr, &ptr);
430 last_il_offset = lbe->il_end_offset;
431 last_native_offset = lbe->native_end_offset;
434 *ptr++ = jit->this_var ? 1 : 0;
436 write_variable (jit->this_var, ptr, &ptr);
438 write_leb128 (jit->num_params, ptr, &ptr);
439 for (i = 0; i < jit->num_params; i++)
440 write_variable (&jit->params [i], ptr, &ptr);
442 write_leb128 (jit->num_locals, ptr, &ptr);
443 for (i = 0; i < jit->num_locals; i++)
444 write_variable (&jit->locals [i], ptr, &ptr);
447 g_assert (size < max_size);
448 total_size = size + sizeof (MonoDebugMethodAddress);
450 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
451 // FIXME: Maybe we should print a warning here.
452 // This should only happen for very big methods, for instance
453 // with more than 40.000 line numbers and more than 5.000
455 mono_debugger_unlock ();
459 address = (MonoDebugMethodAddress *) allocate_data_item (MONO_DEBUG_DATA_ITEM_METHOD, total_size);
461 address->size = total_size;
462 address->symfile_id = handle->index;
463 address->domain_id = mono_domain_get_id (domain);
464 address->method_id = minfo->index;
465 address->code_start = jit->code_start;
466 address->code_size = jit->code_size;
467 address->wrapper_addr = jit->wrapper_addr;
469 memcpy (&address->data, oldptr, size);
471 if (max_size > BUFSIZ)
474 hash = g_new0 (MethodHashEntry, 1);
475 hash->symfile_id = address->symfile_id;
476 hash->domain_id = address->domain_id;
477 hash->method_id = address->method_id;
479 g_hash_table_insert (method_hash, hash, address);
481 if (in_the_mono_debugger)
482 mono_debugger_add_method (jit);
484 mono_debugger_unlock ();
489 static inline guint32
490 read_leb128 (guint8 *ptr, guint8 **rptr)
492 guint32 result = 0, shift = 0;
495 guint8 byte = *ptr++;
497 result |= (byte & 0x7f) << shift;
498 if ((byte & 0x80) == 0)
508 read_sleb128 (guint8 *ptr, guint8 **rptr)
514 guint8 byte = *ptr++;
516 result |= (byte & 0x7f) << shift;
522 if ((shift < 32) && (byte & 0x40))
523 result |= - (1 << shift);
532 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
534 var->index = read_leb128 (ptr, &ptr);
535 var->offset = read_sleb128 (ptr, &ptr);
536 var->size = read_leb128 (ptr, &ptr);
537 var->begin_scope = read_leb128 (ptr, &ptr);
538 var->end_scope = read_leb128 (ptr, &ptr);
542 MonoDebugMethodJitInfo *
543 mono_debug_read_method (MonoDebugMethodAddress *address)
545 MonoDebugMethodJitInfo *jit;
546 guint32 i, il_offset = 0, native_offset = 0;
552 jit = address->jit = g_new0 (MonoDebugMethodJitInfo, 1);
553 jit->code_start = address->code_start;
554 jit->code_size = address->code_size;
555 jit->wrapper_addr = address->wrapper_addr;
557 ptr = (guint8 *) &address->data;
559 jit->prologue_end = read_leb128 (ptr, &ptr);
560 jit->epilogue_begin = read_leb128 (ptr, &ptr);
562 jit->num_line_numbers = read_leb128 (ptr, &ptr);
563 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
564 for (i = 0; i < jit->num_line_numbers; i++) {
565 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
567 il_offset += read_sleb128 (ptr, &ptr);
568 native_offset += read_sleb128 (ptr, &ptr);
570 lne->il_offset = il_offset;
571 lne->native_offset = native_offset;
576 jit->num_lexical_blocks = read_leb128 (ptr, &ptr);
577 jit->lexical_blocks = g_new0 (MonoDebugLexicalBlockEntry, jit->num_lexical_blocks);
578 for (i = 0; i < jit->num_lexical_blocks; i ++) {
579 MonoDebugLexicalBlockEntry *lbe = &jit->lexical_blocks [i];
581 il_offset += read_sleb128 (ptr, &ptr);
582 native_offset += read_sleb128 (ptr, &ptr);
584 lbe->il_start_offset = il_offset;
585 lbe->native_start_offset = native_offset;
587 il_offset += read_sleb128 (ptr, &ptr);
588 native_offset += read_sleb128 (ptr, &ptr);
590 lbe->il_end_offset = il_offset;
591 lbe->native_end_offset = native_offset;
595 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
596 read_variable (jit->this_var, ptr, &ptr);
599 jit->num_params = read_leb128 (ptr, &ptr);
600 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
601 for (i = 0; i < jit->num_params; i++)
602 read_variable (&jit->params [i], ptr, &ptr);
604 jit->num_locals = read_leb128 (ptr, &ptr);
605 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
606 for (i = 0; i < jit->num_locals; i++)
607 read_variable (&jit->locals [i], ptr, &ptr);
613 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
616 jit->address->jit = NULL;
618 g_free (jit->line_numbers);
619 g_free (jit->this_var);
620 g_free (jit->params);
621 g_free (jit->locals);
626 * This is called via the `mono_debugger_class_init_func' from mono_class_init() each time
627 * a new class is initialized.
630 mono_debug_start_add_type (MonoClass *klass)
632 MonoDebugHandle *handle;
634 handle = _mono_debug_get_image (klass->image);
638 if (in_the_mono_debugger)
639 mono_debugger_add_type (handle, klass);
643 get_token (MonoClass *klass)
646 klass = klass->element_class;
648 return klass->type_token;
652 mono_debug_add_type (MonoClass *klass)
654 MonoDebugHandle *handle;
655 MonoDebugClassEntry *entry;
656 char buffer [BUFSIZ];
657 guint8 *ptr, *oldptr;
658 guint32 token, size, total_size, max_size;
661 handle = _mono_debug_get_image (klass->image);
665 if (klass->generic_class ||
666 (klass->byval_arg.type == MONO_TYPE_VAR) || (klass->byval_arg.type == MONO_TYPE_MVAR))
669 max_size = 12 + sizeof (gpointer);
670 if (max_size > BUFSIZ)
671 ptr = oldptr = g_malloc (max_size);
673 ptr = oldptr = buffer;
675 token = get_token (klass);
679 if (klass->valuetype)
680 base_offset = - (int)(sizeof (MonoObject));
682 write_leb128 (token, ptr, &ptr);
683 write_leb128 (klass->rank, ptr, &ptr);
684 write_leb128 (klass->instance_size + base_offset, ptr, &ptr);
685 * ((gpointer *) ptr) = klass;
686 ptr += sizeof (gpointer);
689 g_assert (size < max_size);
690 total_size = size + sizeof (MonoDebugClassEntry);
692 if (total_size + 9 >= DATA_TABLE_CHUNK_SIZE) {
693 // FIXME: Maybe we should print a warning here.
694 // This should only happen for very big methods, for instance
695 // with more than 40.000 line numbers and more than 5.000
700 entry = (MonoDebugClassEntry *) allocate_data_item (MONO_DEBUG_DATA_ITEM_CLASS, total_size);
702 entry->size = total_size;
703 entry->symfile_id = handle->index;
705 memcpy (&entry->data, oldptr, size);
707 if (max_size > BUFSIZ)
710 mono_debugger_start_add_type (handle, klass);
713 static MonoDebugMethodJitInfo *
714 find_method (MonoDebugMethodInfo *minfo, MonoDomain *domain)
716 MethodHashEntry lookup;
717 MonoDebugMethodAddress *address;
719 lookup.symfile_id = minfo->handle->index;
720 lookup.domain_id = mono_domain_get_id (domain);
721 lookup.method_id = minfo->index;
723 address = g_hash_table_lookup (method_hash, &lookup);
727 return mono_debug_read_method (address);
731 il_offset_from_address (MonoDebugMethodInfo *minfo, MonoDomain *domain, guint32 native_offset)
733 MonoDebugMethodJitInfo *jit;
736 jit = find_method (minfo, domain);
737 if (!jit || !jit->line_numbers)
740 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
741 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
743 if (lne.native_offset <= native_offset)
744 return lne.il_offset;
751 * mono_debug_source_location_from_address:
757 * Used by the exception code to get a source location from a machine address.
759 * Returns: a textual representation of the specified address which is suitable to be displayed to
760 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
762 * If the optional @line_number argument is not NULL, the line number is stored there and just the
763 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
764 * line number 8 in the variable pointed to by @line_number).
767 mono_debug_source_location_from_address (MonoMethod *method, guint32 address, guint32 *line_number,
770 MonoDebugMethodInfo *minfo;
775 minfo = _mono_debug_lookup_method (method);
776 if (!minfo || !minfo->handle || !minfo->handle->symfile || !minfo->handle->symfile->offset_table) {
777 mono_loader_unlock ();
781 offset = il_offset_from_address (minfo, domain, address);
784 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
786 mono_loader_unlock ();
791 * mono_debug_source_location_from_il_offset:
796 * Used by the exception code to get a source location from an IL offset.
798 * Returns a textual representation of the specified address which is suitable to be displayed to
799 * the user (for instance "/home/martin/monocvs/debugger/test/Y.cs:8").
801 * If the optional @line_number argument is not NULL, the line number is stored there and just the
802 * source file is returned (ie. it'd return "/home/martin/monocvs/debugger/test/Y.cs" and store the
803 * line number 8 in the variable pointed to by @line_number).
806 mono_debug_source_location_from_il_offset (MonoMethod *method, guint32 offset, guint32 *line_number)
809 MonoDebugMethodInfo *minfo;
812 minfo = _mono_debug_lookup_method (method);
813 if (!minfo || !minfo->handle || !minfo->handle->symfile) {
814 mono_loader_unlock ();
818 res = mono_debug_find_source_location (minfo->handle->symfile, method, offset, line_number);
819 mono_loader_unlock ();
824 * mono_debug_il_offset_from_address:
829 * Returns: the IL offset corresponding to machine address @address which is an offset
830 * relative to the beginning of the method @method.
833 mono_debug_il_offset_from_address (MonoMethod *method, gint32 address, MonoDomain *domain)
835 MonoDebugMethodInfo *minfo;
842 minfo = _mono_debug_lookup_method (method);
843 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
844 !minfo->handle->symfile->offset_table) {
845 mono_loader_unlock ();
849 res = il_offset_from_address (minfo, domain, address);
850 mono_loader_unlock ();
855 * mono_debug_address_from_il_offset:
860 * Returns: the machine address corresponding to IL offset @il_offset.
861 * The returned value is an offset relative to the beginning of the method @method.
864 mono_debug_address_from_il_offset (MonoMethod *method, gint32 il_offset, MonoDomain *domain)
866 MonoDebugMethodInfo *minfo;
867 MonoDebugMethodJitInfo *jit;
874 minfo = _mono_debug_lookup_method (method);
875 if (!minfo || !minfo->il_offsets || !minfo->handle || !minfo->handle->symfile ||
876 !minfo->handle->symfile->offset_table) {
877 mono_loader_unlock ();
881 jit = find_method (minfo, domain);
883 mono_loader_unlock ();
887 res = _mono_debug_address_from_il_offset (jit, il_offset);
888 mono_loader_unlock ();