[crash] Crash Reporter V2 (#10532)
[mono-project.git] / mono / metadata / mono-debug.c
blob93203b52f1d3abcaf5c554c529272db8b89f8bbb
1 /**
2 * \file
4 * Author:
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)
9 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
10 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
13 #include <config.h>
14 #include <mono/metadata/assembly.h>
15 #include <mono/metadata/assembly-internals.h>
16 #include <mono/metadata/tabledefs.h>
17 #include <mono/metadata/tokentype.h>
18 #include <mono/metadata/appdomain.h>
19 #include <mono/metadata/class-internals.h>
20 #include <mono/metadata/mono-debug.h>
21 #include <mono/metadata/debug-internals.h>
22 #include <mono/metadata/mono-endian.h>
23 #include <mono/metadata/gc-internals.h>
24 #include <mono/metadata/mempool.h>
25 #include <mono/metadata/debug-mono-symfile.h>
26 #include <mono/metadata/debug-mono-ppdb.h>
27 #include <mono/metadata/exception-internals.h>
28 #include <mono/metadata/runtime.h>
29 #include <string.h>
31 #if NO_UNALIGNED_ACCESS
32 #define WRITE_UNALIGNED(type, addr, val) \
33 memcpy(addr, &val, sizeof(type))
34 #define READ_UNALIGNED(type, addr, val) \
35 memcpy(&val, addr, sizeof(type))
36 #else
37 #define WRITE_UNALIGNED(type, addr, val) \
38 (*(type *)(addr) = (val))
39 #define READ_UNALIGNED(type, addr, val) \
40 val = (*(type *)(addr))
41 #endif
43 /* This contains per-domain info */
44 struct _MonoDebugDataTable {
45 MonoMemPool *mp;
46 GHashTable *method_address_hash;
49 /* This contains JIT debugging information about a method in serialized format */
50 struct _MonoDebugMethodAddress {
51 const guint8 *code_start;
52 guint32 code_size;
53 guint8 data [MONO_ZERO_LEN_ARRAY];
56 static MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
58 static gboolean mono_debug_initialized = FALSE;
59 /* Maps MonoImage -> MonoMonoDebugHandle */
60 static GHashTable *mono_debug_handles;
61 /* Maps MonoDomain -> MonoDataTable */
62 static GHashTable *data_table_hash;
64 static mono_mutex_t debugger_lock_mutex;
66 static gboolean is_attached = FALSE;
68 static MonoDebugHandle *mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size);
70 static MonoDebugHandle *mono_debug_get_image (MonoImage *image);
71 static void mono_debug_add_assembly (MonoAssembly *assembly,
72 gpointer user_data);
74 static MonoDebugHandle *open_symfile_from_bundle (MonoImage *image);
76 static MonoDebugDataTable *
77 create_data_table (MonoDomain *domain)
79 MonoDebugDataTable *table;
81 table = g_new0 (MonoDebugDataTable, 1);
83 table->mp = mono_mempool_new ();
84 table->method_address_hash = g_hash_table_new (NULL, NULL);
86 if (domain)
87 g_hash_table_insert (data_table_hash, domain, table);
89 return table;
92 static void
93 free_data_table (MonoDebugDataTable *table)
95 mono_mempool_destroy (table->mp);
96 g_hash_table_destroy (table->method_address_hash);
98 g_free (table);
101 static MonoDebugDataTable *
102 lookup_data_table (MonoDomain *domain)
104 MonoDebugDataTable *table;
106 table = (MonoDebugDataTable *)g_hash_table_lookup (data_table_hash, domain);
107 if (!table) {
108 g_error ("lookup_data_table () failed for %p\n", domain);
109 g_assert (table);
111 return table;
114 static void
115 free_debug_handle (MonoDebugHandle *handle)
117 if (handle->ppdb)
118 mono_ppdb_close (handle);
119 if (handle->symfile)
120 mono_debug_close_mono_symbol_file (handle->symfile);
121 /* decrease the refcount added with mono_image_addref () */
122 mono_image_close (handle->image);
123 g_free (handle);
127 * Initialize debugging support.
129 * This method must be called after loading corlib,
130 * but before opening the application's main assembly because we need to set some
131 * callbacks here.
133 void
134 mono_debug_init (MonoDebugFormat format)
136 g_assert (!mono_debug_initialized);
137 if (format == MONO_DEBUG_FORMAT_DEBUGGER)
138 g_error ("The mdb debugger is no longer supported.");
140 mono_debug_initialized = TRUE;
141 mono_debug_format = format;
143 mono_os_mutex_init_recursive (&debugger_lock_mutex);
145 mono_debugger_lock ();
147 mono_debug_handles = g_hash_table_new_full
148 (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
150 data_table_hash = g_hash_table_new_full (
151 NULL, NULL, NULL, (GDestroyNotify) free_data_table);
153 mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
155 mono_debugger_unlock ();
158 void
159 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
161 MONO_ENTER_GC_UNSAFE;
162 if (!mono_debug_initialized)
163 goto leave;
165 mono_debug_open_image (image, raw_contents, size);
166 leave:
167 MONO_EXIT_GC_UNSAFE;
170 void
171 mono_debug_cleanup (void)
173 if (mono_debug_handles)
174 g_hash_table_destroy (mono_debug_handles);
175 mono_debug_handles = NULL;
177 if (data_table_hash) {
178 g_hash_table_destroy (data_table_hash);
179 data_table_hash = NULL;
184 * mono_debug_domain_create:
186 void
187 mono_debug_domain_create (MonoDomain *domain)
189 if (!mono_debug_initialized)
190 return;
192 mono_debugger_lock ();
194 create_data_table (domain);
196 mono_debugger_unlock ();
199 void
200 mono_debug_domain_unload (MonoDomain *domain)
202 MonoDebugDataTable *table;
204 if (!mono_debug_initialized)
205 return;
207 mono_debugger_lock ();
209 table = (MonoDebugDataTable *)g_hash_table_lookup (data_table_hash, domain);
210 if (!table) {
211 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
212 domain, mono_domain_get_id (domain));
213 mono_debugger_unlock ();
214 return;
217 g_hash_table_remove (data_table_hash, domain);
219 mono_debugger_unlock ();
223 * LOCKING: Assumes the debug lock is held.
225 static MonoDebugHandle *
226 mono_debug_get_image (MonoImage *image)
228 return (MonoDebugHandle *)g_hash_table_lookup (mono_debug_handles, image);
232 * mono_debug_close_image:
234 void
235 mono_debug_close_image (MonoImage *image)
237 MonoDebugHandle *handle;
239 if (!mono_debug_initialized)
240 return;
242 mono_debugger_lock ();
244 handle = mono_debug_get_image (image);
245 if (!handle) {
246 mono_debugger_unlock ();
247 return;
250 g_hash_table_remove (mono_debug_handles, image);
252 mono_debugger_unlock ();
255 MonoDebugHandle *
256 mono_debug_get_handle (MonoImage *image)
258 return mono_debug_open_image (image, NULL, 0);
261 static MonoDebugHandle *
262 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
264 MonoDebugHandle *handle;
266 if (mono_image_is_dynamic (image))
267 return NULL;
269 mono_debugger_lock ();
271 handle = mono_debug_get_image (image);
272 if (handle != NULL) {
273 mono_debugger_unlock ();
274 return handle;
277 handle = g_new0 (MonoDebugHandle, 1);
279 handle->image = image;
280 mono_image_addref (image);
282 /* Try a ppdb file first */
283 handle->ppdb = mono_ppdb_load_file (handle->image, raw_contents, size);
285 if (!handle->ppdb)
286 handle->symfile = mono_debug_open_mono_symbols (handle, raw_contents, size, FALSE);
288 g_hash_table_insert (mono_debug_handles, image, handle);
290 mono_debugger_unlock ();
292 return handle;
295 static void
296 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
298 MonoDebugHandle *handle;
299 MonoImage *image;
301 mono_debugger_lock ();
302 image = mono_assembly_get_image_internal (assembly);
303 handle = open_symfile_from_bundle (image);
304 if (!handle)
305 mono_debug_open_image (image, NULL, 0);
306 mono_debugger_unlock ();
309 struct LookupMethodData
311 MonoDebugMethodInfo *minfo;
312 MonoMethod *method;
315 static void
316 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
318 MonoDebugHandle *handle = (MonoDebugHandle *) value;
319 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
321 if (data->minfo)
322 return;
324 if (handle->ppdb)
325 data->minfo = mono_ppdb_lookup_method (handle, data->method);
326 else if (handle->symfile)
327 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
330 static MonoDebugMethodInfo *
331 mono_debug_lookup_method_internal (MonoMethod *method)
333 struct LookupMethodData data;
335 data.minfo = NULL;
336 data.method = method;
338 if (!mono_debug_handles)
339 return NULL;
341 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
342 return data.minfo;
346 * mono_debug_lookup_method:
348 * Lookup symbol file information for the method \p method. The returned
349 * \c MonoDebugMethodInfo is a private structure, but it can be passed to
350 * \c mono_debug_symfile_lookup_location.
352 MonoDebugMethodInfo *
353 mono_debug_lookup_method (MonoMethod *method)
355 MonoDebugMethodInfo *minfo;
357 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
358 return NULL;
360 mono_debugger_lock ();
361 minfo = mono_debug_lookup_method_internal (method);
362 mono_debugger_unlock ();
363 return minfo;
366 typedef struct
368 gboolean found;
369 MonoImage *image;
370 } LookupImageData;
372 static void
373 lookup_image_func (gpointer key, gpointer value, gpointer user_data)
375 MonoDebugHandle *handle = (MonoDebugHandle *) value;
376 LookupImageData *data = (LookupImageData *) user_data;
378 if (data->found)
379 return;
381 if (handle->image == data->image && handle->symfile)
382 data->found = TRUE;
385 gboolean
386 mono_debug_image_has_debug_info (MonoImage *image)
388 LookupImageData data;
390 if (!mono_debug_handles)
391 return FALSE;
393 memset (&data, 0, sizeof (data));
394 data.image = image;
396 mono_debugger_lock ();
397 g_hash_table_foreach (mono_debug_handles, lookup_image_func, &data);
398 mono_debugger_unlock ();
399 return data.found;
402 static inline void
403 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
405 do {
406 guint8 byte = value & 0x7f;
407 value >>= 7;
408 if (value)
409 byte |= 0x80;
410 *ptr++ = byte;
411 } while (value);
413 *rptr = ptr;
416 static inline void
417 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
419 gboolean more = 1;
421 while (more) {
422 guint8 byte = value & 0x7f;
423 value >>= 7;
425 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
426 more = 0;
427 else
428 byte |= 0x80;
429 *ptr++ = byte;
432 *rptr = ptr;
435 static void
436 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
438 write_leb128 (var->index, ptr, &ptr);
439 write_sleb128 (var->offset, ptr, &ptr);
440 write_leb128 (var->size, ptr, &ptr);
441 write_leb128 (var->begin_scope, ptr, &ptr);
442 write_leb128 (var->end_scope, ptr, &ptr);
443 WRITE_UNALIGNED (gpointer, ptr, var->type);
444 ptr += sizeof (gpointer);
445 *rptr = ptr;
449 * mono_debug_add_method:
451 MonoDebugMethodAddress *
452 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
454 MonoDebugDataTable *table;
455 MonoDebugMethodAddress *address;
456 guint8 buffer [BUFSIZ];
457 guint8 *ptr, *oldptr;
458 guint32 i, size, total_size, max_size;
460 mono_debugger_lock ();
462 table = lookup_data_table (domain);
464 max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
465 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
467 if (max_size > BUFSIZ)
468 ptr = oldptr = (guint8 *)g_malloc (max_size);
469 else
470 ptr = oldptr = buffer;
472 write_leb128 (jit->prologue_end, ptr, &ptr);
473 write_leb128 (jit->epilogue_begin, ptr, &ptr);
475 write_leb128 (jit->num_line_numbers, ptr, &ptr);
476 for (i = 0; i < jit->num_line_numbers; i++) {
477 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
479 write_sleb128 (lne->il_offset, ptr, &ptr);
480 write_sleb128 (lne->native_offset, ptr, &ptr);
482 write_leb128 (jit->has_var_info, ptr, &ptr);
483 if (jit->has_var_info) {
484 *ptr++ = jit->this_var ? 1 : 0;
485 if (jit->this_var)
486 write_variable (jit->this_var, ptr, &ptr);
488 write_leb128 (jit->num_params, ptr, &ptr);
489 for (i = 0; i < jit->num_params; i++)
490 write_variable (&jit->params [i], ptr, &ptr);
492 write_leb128 (jit->num_locals, ptr, &ptr);
493 for (i = 0; i < jit->num_locals; i++)
494 write_variable (&jit->locals [i], ptr, &ptr);
496 *ptr++ = jit->gsharedvt_info_var ? 1 : 0;
497 if (jit->gsharedvt_info_var) {
498 write_variable (jit->gsharedvt_info_var, ptr, &ptr);
499 write_variable (jit->gsharedvt_locals_var, ptr, &ptr);
503 size = ptr - oldptr;
504 g_assert (size < max_size);
505 total_size = size + sizeof (MonoDebugMethodAddress);
507 if (method_is_dynamic (method)) {
508 address = (MonoDebugMethodAddress *)g_malloc0 (total_size);
509 } else {
510 address = (MonoDebugMethodAddress *)mono_mempool_alloc (table->mp, total_size);
513 address->code_start = jit->code_start;
514 address->code_size = jit->code_size;
516 memcpy (&address->data, oldptr, size);
517 if (max_size > BUFSIZ)
518 g_free (oldptr);
520 g_hash_table_insert (table->method_address_hash, method, address);
522 mono_debugger_unlock ();
523 return address;
526 void
527 mono_debug_remove_method (MonoMethod *method, MonoDomain *domain)
529 MonoDebugDataTable *table;
530 MonoDebugMethodAddress *address;
532 if (!mono_debug_initialized)
533 return;
535 g_assert (method_is_dynamic (method));
537 mono_debugger_lock ();
539 table = lookup_data_table (domain);
541 address = (MonoDebugMethodAddress *)g_hash_table_lookup (table->method_address_hash, method);
542 if (address)
543 g_free (address);
545 g_hash_table_remove (table->method_address_hash, method);
547 mono_debugger_unlock ();
551 * mono_debug_add_delegate_trampoline:
553 void
554 mono_debug_add_delegate_trampoline (gpointer code, int size)
558 static inline guint32
559 read_leb128 (guint8 *ptr, guint8 **rptr)
561 guint32 result = 0, shift = 0;
563 while (TRUE) {
564 guint8 byte = *ptr++;
566 result |= (byte & 0x7f) << shift;
567 if ((byte & 0x80) == 0)
568 break;
569 shift += 7;
572 *rptr = ptr;
573 return result;
576 static inline gint32
577 read_sleb128 (guint8 *ptr, guint8 **rptr)
579 gint32 result = 0;
580 guint32 shift = 0;
582 while (TRUE) {
583 guint8 byte = *ptr++;
585 result |= (byte & 0x7f) << shift;
586 shift += 7;
588 if (byte & 0x80)
589 continue;
591 if ((shift < 32) && (byte & 0x40))
592 result |= - (1 << shift);
593 break;
596 *rptr = ptr;
597 return result;
600 static void
601 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
603 var->index = read_leb128 (ptr, &ptr);
604 var->offset = read_sleb128 (ptr, &ptr);
605 var->size = read_leb128 (ptr, &ptr);
606 var->begin_scope = read_leb128 (ptr, &ptr);
607 var->end_scope = read_leb128 (ptr, &ptr);
608 READ_UNALIGNED (MonoType *, ptr, var->type);
609 ptr += sizeof (gpointer);
610 *rptr = ptr;
613 static void
614 mono_debug_free_method_jit_info_full (MonoDebugMethodJitInfo *jit, gboolean stack)
616 if (!jit)
617 return;
618 g_free (jit->line_numbers);
619 g_free (jit->this_var);
620 g_free (jit->params);
621 g_free (jit->locals);
622 g_free (jit->gsharedvt_info_var);
623 g_free (jit->gsharedvt_locals_var);
624 if (!stack)
625 g_free (jit);
628 void
629 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
631 return mono_debug_free_method_jit_info_full (jit, FALSE);
634 static MonoDebugMethodJitInfo *
635 mono_debug_read_method (MonoDebugMethodAddress *address, MonoDebugMethodJitInfo *jit)
637 guint32 i;
638 guint8 *ptr;
640 memset (jit, 0, sizeof (*jit));
641 jit->code_start = address->code_start;
642 jit->code_size = address->code_size;
644 ptr = (guint8 *) &address->data;
646 jit->prologue_end = read_leb128 (ptr, &ptr);
647 jit->epilogue_begin = read_leb128 (ptr, &ptr);
649 jit->num_line_numbers = read_leb128 (ptr, &ptr);
650 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
651 for (i = 0; i < jit->num_line_numbers; i++) {
652 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
654 lne->il_offset = read_sleb128 (ptr, &ptr);
655 lne->native_offset = read_sleb128 (ptr, &ptr);
657 jit->has_var_info = read_leb128 (ptr, &ptr);
658 if (jit->has_var_info) {
659 if (*ptr++) {
660 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
661 read_variable (jit->this_var, ptr, &ptr);
664 jit->num_params = read_leb128 (ptr, &ptr);
665 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
666 for (i = 0; i < jit->num_params; i++)
667 read_variable (&jit->params [i], ptr, &ptr);
669 jit->num_locals = read_leb128 (ptr, &ptr);
670 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
671 for (i = 0; i < jit->num_locals; i++)
672 read_variable (&jit->locals [i], ptr, &ptr);
674 if (*ptr++) {
675 jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
676 jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
677 read_variable (jit->gsharedvt_info_var, ptr, &ptr);
678 read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
682 return jit;
685 static MonoDebugMethodJitInfo *
686 find_method (MonoMethod *method, MonoDomain *domain, MonoDebugMethodJitInfo *jit)
688 MonoDebugDataTable *table;
689 MonoDebugMethodAddress *address;
691 table = lookup_data_table (domain);
692 address = (MonoDebugMethodAddress *)g_hash_table_lookup (table->method_address_hash, method);
694 if (!address)
695 return NULL;
697 return mono_debug_read_method (address, jit);
700 MonoDebugMethodJitInfo *
701 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
703 MonoDebugMethodJitInfo *res = g_new0 (MonoDebugMethodJitInfo, 1);
705 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
706 return NULL;
708 mono_debugger_lock ();
709 find_method (method, domain, res);
710 mono_debugger_unlock ();
711 return res;
714 MonoDebugMethodAddressList *
715 mono_debug_lookup_method_addresses (MonoMethod *method)
717 g_assert_not_reached ();
718 return NULL;
721 static gint32
722 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
724 MonoDebugMethodJitInfo mem;
725 int i;
727 MonoDebugMethodJitInfo *jit = find_method (method, domain, &mem);
728 if (!jit || !jit->line_numbers)
729 goto cleanup_and_fail;
731 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
732 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
734 if (lne.native_offset <= native_offset) {
735 mono_debug_free_method_jit_info_full (jit, TRUE);
736 return lne.il_offset;
740 cleanup_and_fail:
741 mono_debug_free_method_jit_info_full (jit, TRUE);
742 return -1;
746 * mono_debug_il_offset_from_address:
748 * Compute the IL offset corresponding to \p native_offset inside the native
749 * code of \p method in \p domain.
751 gint32
752 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
754 gint32 res;
756 mono_debugger_lock ();
758 res = il_offset_from_address (method, domain, native_offset);
760 mono_debugger_unlock ();
762 return res;
766 * mono_debug_lookup_source_location:
767 * \param address Native offset within the \p method's machine code.
768 * Lookup the source code corresponding to the machine instruction located at
769 * native offset \p address within \p method.
770 * The returned \c MonoDebugSourceLocation contains both file / line number
771 * information and the corresponding IL offset. It must be freed by
772 * \c mono_debug_free_source_location.
774 MonoDebugSourceLocation *
775 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
777 MonoDebugMethodInfo *minfo;
778 MonoDebugSourceLocation *location;
779 gint32 offset;
781 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
782 return NULL;
784 mono_debugger_lock ();
785 minfo = mono_debug_lookup_method_internal (method);
786 if (!minfo || !minfo->handle) {
787 mono_debugger_unlock ();
788 return NULL;
791 if (!minfo->handle->ppdb && (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))) {
792 mono_debugger_unlock ();
793 return NULL;
796 offset = il_offset_from_address (method, domain, address);
797 if (offset < 0) {
798 mono_debugger_unlock ();
799 return NULL;
802 if (minfo->handle->ppdb)
803 location = mono_ppdb_lookup_location (minfo, offset);
804 else
805 location = mono_debug_symfile_lookup_location (minfo, offset);
806 mono_debugger_unlock ();
807 return location;
811 * mono_debug_lookup_source_location_by_il:
813 * Same as mono_debug_lookup_source_location but take an IL_OFFSET argument.
815 MonoDebugSourceLocation *
816 mono_debug_lookup_source_location_by_il (MonoMethod *method, guint32 il_offset, MonoDomain *domain)
818 MonoDebugMethodInfo *minfo;
819 MonoDebugSourceLocation *location;
821 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
822 return NULL;
824 mono_debugger_lock ();
825 minfo = mono_debug_lookup_method_internal (method);
826 if (!minfo || !minfo->handle) {
827 mono_debugger_unlock ();
828 return NULL;
831 if (!minfo->handle->ppdb && (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))) {
832 mono_debugger_unlock ();
833 return NULL;
836 if (minfo->handle->ppdb)
837 location = mono_ppdb_lookup_location (minfo, il_offset);
838 else
839 location = mono_debug_symfile_lookup_location (minfo, il_offset);
840 mono_debugger_unlock ();
841 return location;
844 MonoDebugSourceLocation *
845 mono_debug_method_lookup_location (MonoDebugMethodInfo *minfo, int il_offset)
847 MonoDebugSourceLocation *location;
849 mono_debugger_lock ();
850 if (minfo->handle->ppdb)
851 location = mono_ppdb_lookup_location (minfo, il_offset);
852 else
853 location = mono_debug_symfile_lookup_location (minfo, il_offset);
854 mono_debugger_unlock ();
855 return location;
859 * mono_debug_lookup_locals:
861 * Return information about the local variables of MINFO.
862 * The result should be freed using mono_debug_free_locals ().
864 MonoDebugLocalsInfo*
865 mono_debug_lookup_locals (MonoMethod *method)
867 MonoDebugMethodInfo *minfo;
868 MonoDebugLocalsInfo *res;
870 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
871 return NULL;
873 mono_debugger_lock ();
874 minfo = mono_debug_lookup_method_internal (method);
875 if (!minfo || !minfo->handle) {
876 mono_debugger_unlock ();
877 return NULL;
880 if (minfo->handle->ppdb) {
881 res = mono_ppdb_lookup_locals (minfo);
882 } else {
883 if (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))
884 res = NULL;
885 else
886 res = mono_debug_symfile_lookup_locals (minfo);
888 mono_debugger_unlock ();
890 return res;
894 * mono_debug_free_locals:
896 * Free all the data allocated by mono_debug_lookup_locals ().
898 void
899 mono_debug_free_locals (MonoDebugLocalsInfo *info)
901 int i;
903 for (i = 0; i < info->num_locals; ++i)
904 g_free (info->locals [i].name);
905 g_free (info->locals);
906 g_free (info->code_blocks);
907 g_free (info);
911 * mono_debug_lookup_method_async_debug_info:
913 * Return information about the async stepping information of method.
914 * The result should be freed using mono_debug_free_async_debug_info ().
916 MonoDebugMethodAsyncInfo*
917 mono_debug_lookup_method_async_debug_info (MonoMethod *method)
919 MonoDebugMethodInfo *minfo;
920 MonoDebugMethodAsyncInfo *res = NULL;
922 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
923 return NULL;
925 mono_debugger_lock ();
926 minfo = mono_debug_lookup_method_internal (method);
927 if (!minfo || !minfo->handle) {
928 mono_debugger_unlock ();
929 return NULL;
932 if (minfo->handle->ppdb)
933 res = mono_ppdb_lookup_method_async_debug_info (minfo);
935 mono_debugger_unlock ();
937 return res;
941 * mono_debug_free_method_async_debug_info:
943 * Free all the data allocated by mono_debug_lookup_method_async_debug_info ().
945 void
946 mono_debug_free_method_async_debug_info (MonoDebugMethodAsyncInfo *info)
948 if (info->num_awaits) {
949 g_free (info->yield_offsets);
950 g_free (info->resume_offsets);
951 g_free (info->move_next_method_token);
953 g_free (info);
957 * mono_debug_free_source_location:
958 * \param location A \c MonoDebugSourceLocation
959 * Frees the \p location.
961 void
962 mono_debug_free_source_location (MonoDebugSourceLocation *location)
964 if (location) {
965 g_free (location->source_file);
966 g_free (location);
970 static int (*get_seq_point) (MonoDomain *domain, MonoMethod *method, gint32 native_offset);
972 void
973 mono_install_get_seq_point (MonoGetSeqPointFunc func)
975 get_seq_point = func;
979 * mono_debug_print_stack_frame:
980 * \param native_offset Native offset within the \p method's machine code.
981 * Conventient wrapper around \c mono_debug_lookup_source_location which can be
982 * used if you only want to use the location to print a stack frame.
984 gchar *
985 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
987 MonoDebugSourceLocation *location;
988 gchar *fname, *ptr, *res;
989 int offset;
991 fname = mono_method_full_name (method, TRUE);
992 for (ptr = fname; *ptr; ptr++) {
993 if (*ptr == ':') *ptr = '.';
996 location = mono_debug_lookup_source_location (method, native_offset, domain);
998 if (!location) {
999 if (mono_debug_initialized) {
1000 mono_debugger_lock ();
1001 offset = il_offset_from_address (method, domain, native_offset);
1002 mono_debugger_unlock ();
1003 } else {
1004 offset = -1;
1007 if (offset < 0 && get_seq_point)
1008 offset = get_seq_point (domain, method, native_offset);
1010 if (offset < 0)
1011 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
1012 else {
1013 char *mvid = mono_guid_to_string_minimal ((uint8_t*)m_class_get_image (method->klass)->heap_guid.data);
1014 char *aotid = mono_runtime_get_aotid ();
1015 if (aotid)
1016 res = g_strdup_printf ("at %s [0x%05x] in <%s#%s>:0" , fname, offset, mvid, aotid);
1017 else
1018 res = g_strdup_printf ("at %s [0x%05x] in <%s>:0" , fname, offset, mvid);
1020 g_free (aotid);
1021 g_free (mvid);
1023 g_free (fname);
1024 return res;
1027 res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
1028 location->source_file, location->row);
1030 g_free (fname);
1031 mono_debug_free_source_location (location);
1032 return res;
1035 void
1036 mono_set_is_debugger_attached (gboolean attached)
1038 is_attached = attached;
1041 gboolean
1042 mono_is_debugger_attached (void)
1044 return is_attached;
1048 * Bundles
1051 typedef struct _BundledSymfile BundledSymfile;
1053 struct _BundledSymfile {
1054 BundledSymfile *next;
1055 const char *aname;
1056 const mono_byte *raw_contents;
1057 int size;
1060 static BundledSymfile *bundled_symfiles = NULL;
1063 * mono_register_symfile_for_assembly:
1065 void
1066 mono_register_symfile_for_assembly (const char *assembly_name, const mono_byte *raw_contents, int size)
1068 BundledSymfile *bsymfile;
1070 bsymfile = g_new0 (BundledSymfile, 1);
1071 bsymfile->aname = assembly_name;
1072 bsymfile->raw_contents = raw_contents;
1073 bsymfile->size = size;
1074 bsymfile->next = bundled_symfiles;
1075 bundled_symfiles = bsymfile;
1078 static MonoDebugHandle *
1079 open_symfile_from_bundle (MonoImage *image)
1081 BundledSymfile *bsymfile;
1083 for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) {
1084 if (strcmp (bsymfile->aname, image->module_name))
1085 continue;
1087 return mono_debug_open_image (image, bsymfile->raw_contents, bsymfile->size);
1090 return NULL;
1093 void
1094 mono_debugger_lock (void)
1096 g_assert (mono_debug_initialized);
1097 mono_os_mutex_lock (&debugger_lock_mutex);
1100 void
1101 mono_debugger_unlock (void)
1103 g_assert (mono_debug_initialized);
1104 mono_os_mutex_unlock (&debugger_lock_mutex);
1108 * mono_debug_enabled:
1110 * Returns true is debug information is enabled. This doesn't relate if a debugger is present or not.
1112 mono_bool
1113 mono_debug_enabled (void)
1115 return mono_debug_format != MONO_DEBUG_FORMAT_NONE;
1118 void
1119 mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points)
1121 if (minfo->handle->ppdb)
1122 mono_ppdb_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points);
1123 else
1124 mono_debug_symfile_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points);