[System] Tweak socket test
[mono-project.git] / mono / metadata / mono-debug.c
blob2eba05b36fa7d16178603afd22dfe74d678f09d0
1 /*
2 * mono-debug.c:
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/tabledefs.h>
16 #include <mono/metadata/tokentype.h>
17 #include <mono/metadata/appdomain.h>
18 #include <mono/metadata/class-internals.h>
19 #include <mono/metadata/mono-debug.h>
20 #include <mono/metadata/mono-debug-debugger.h>
21 #include <mono/metadata/mono-endian.h>
22 #include <mono/metadata/gc-internals.h>
23 #include <mono/metadata/mempool.h>
24 #include <mono/metadata/debug-mono-ppdb.h>
25 #include <mono/metadata/exception-internals.h>
26 #include <mono/metadata/runtime.h>
27 #include <string.h>
29 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
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 if (!mono_debug_initialized)
162 return;
164 mono_debug_open_image (image, raw_contents, size);
167 void
168 mono_debug_cleanup (void)
170 if (mono_debug_handles)
171 g_hash_table_destroy (mono_debug_handles);
172 mono_debug_handles = NULL;
174 if (data_table_hash) {
175 g_hash_table_destroy (data_table_hash);
176 data_table_hash = NULL;
180 void
181 mono_debug_domain_create (MonoDomain *domain)
183 if (!mono_debug_initialized)
184 return;
186 mono_debugger_lock ();
188 create_data_table (domain);
190 mono_debugger_unlock ();
193 void
194 mono_debug_domain_unload (MonoDomain *domain)
196 MonoDebugDataTable *table;
198 if (!mono_debug_initialized)
199 return;
201 mono_debugger_lock ();
203 table = (MonoDebugDataTable *)g_hash_table_lookup (data_table_hash, domain);
204 if (!table) {
205 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
206 domain, mono_domain_get_id (domain));
207 mono_debugger_unlock ();
208 return;
211 g_hash_table_remove (data_table_hash, domain);
213 mono_debugger_unlock ();
217 * LOCKING: Assumes the debug lock is held.
219 static MonoDebugHandle *
220 mono_debug_get_image (MonoImage *image)
222 return (MonoDebugHandle *)g_hash_table_lookup (mono_debug_handles, image);
225 void
226 mono_debug_close_image (MonoImage *image)
228 MonoDebugHandle *handle;
230 if (!mono_debug_initialized)
231 return;
233 mono_debugger_lock ();
235 handle = mono_debug_get_image (image);
236 if (!handle) {
237 mono_debugger_unlock ();
238 return;
241 g_hash_table_remove (mono_debug_handles, image);
243 mono_debugger_unlock ();
246 static MonoDebugHandle *
247 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
249 MonoDebugHandle *handle;
251 if (mono_image_is_dynamic (image))
252 return NULL;
254 mono_debugger_lock ();
256 handle = mono_debug_get_image (image);
257 if (handle != NULL) {
258 mono_debugger_unlock ();
259 return handle;
262 handle = g_new0 (MonoDebugHandle, 1);
264 handle->image = image;
265 mono_image_addref (image);
267 /* Try a ppdb file first */
268 handle->ppdb = mono_ppdb_load_file (handle->image, raw_contents, size);
270 if (!handle->ppdb)
271 handle->symfile = mono_debug_open_mono_symbols (handle, raw_contents, size, FALSE);
273 g_hash_table_insert (mono_debug_handles, image, handle);
275 mono_debugger_unlock ();
277 return handle;
280 static void
281 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
283 MonoDebugHandle *handle;
284 MonoImage *image;
286 mono_debugger_lock ();
287 image = mono_assembly_get_image (assembly);
288 handle = open_symfile_from_bundle (image);
289 if (!handle)
290 mono_debug_open_image (image, NULL, 0);
291 mono_debugger_unlock ();
294 struct LookupMethodData
296 MonoDebugMethodInfo *minfo;
297 MonoMethod *method;
300 static void
301 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
303 MonoDebugHandle *handle = (MonoDebugHandle *) value;
304 struct LookupMethodData *data = (struct LookupMethodData *) user_data;
306 if (data->minfo)
307 return;
309 if (handle->ppdb)
310 data->minfo = mono_ppdb_lookup_method (handle, data->method);
311 else if (handle->symfile)
312 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
315 static MonoDebugMethodInfo *
316 mono_debug_lookup_method_internal (MonoMethod *method)
318 struct LookupMethodData data;
320 data.minfo = NULL;
321 data.method = method;
323 if (!mono_debug_handles)
324 return NULL;
326 g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
327 return data.minfo;
331 * mono_debug_lookup_method:
333 * Lookup symbol file information for the method @method. The returned
334 * `MonoDebugMethodInfo' is a private structure, but it can be passed to
335 * mono_debug_symfile_lookup_location().
337 MonoDebugMethodInfo *
338 mono_debug_lookup_method (MonoMethod *method)
340 MonoDebugMethodInfo *minfo;
342 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
343 return NULL;
345 mono_debugger_lock ();
346 minfo = mono_debug_lookup_method_internal (method);
347 mono_debugger_unlock ();
348 return minfo;
351 typedef struct
353 gboolean found;
354 MonoImage *image;
355 } LookupImageData;
357 static void
358 lookup_image_func (gpointer key, gpointer value, gpointer user_data)
360 MonoDebugHandle *handle = (MonoDebugHandle *) value;
361 LookupImageData *data = (LookupImageData *) user_data;
363 if (data->found)
364 return;
366 if (handle->image == data->image && handle->symfile)
367 data->found = TRUE;
370 gboolean
371 mono_debug_image_has_debug_info (MonoImage *image)
373 LookupImageData data;
375 if (!mono_debug_handles)
376 return FALSE;
378 memset (&data, 0, sizeof (data));
379 data.image = image;
381 mono_debugger_lock ();
382 g_hash_table_foreach (mono_debug_handles, lookup_image_func, &data);
383 mono_debugger_unlock ();
384 return data.found;
387 static inline void
388 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
390 do {
391 guint8 byte = value & 0x7f;
392 value >>= 7;
393 if (value)
394 byte |= 0x80;
395 *ptr++ = byte;
396 } while (value);
398 *rptr = ptr;
401 static inline void
402 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
404 gboolean more = 1;
406 while (more) {
407 guint8 byte = value & 0x7f;
408 value >>= 7;
410 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
411 more = 0;
412 else
413 byte |= 0x80;
414 *ptr++ = byte;
417 *rptr = ptr;
420 static void
421 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
423 write_leb128 (var->index, ptr, &ptr);
424 write_sleb128 (var->offset, ptr, &ptr);
425 write_leb128 (var->size, ptr, &ptr);
426 write_leb128 (var->begin_scope, ptr, &ptr);
427 write_leb128 (var->end_scope, ptr, &ptr);
428 WRITE_UNALIGNED (gpointer, ptr, var->type);
429 ptr += sizeof (gpointer);
430 *rptr = ptr;
433 MonoDebugMethodAddress *
434 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
436 MonoDebugDataTable *table;
437 MonoDebugMethodAddress *address;
438 guint8 buffer [BUFSIZ];
439 guint8 *ptr, *oldptr;
440 guint32 i, size, total_size, max_size;
442 mono_debugger_lock ();
444 table = lookup_data_table (domain);
446 max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
447 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
449 if (max_size > BUFSIZ)
450 ptr = oldptr = (guint8 *)g_malloc (max_size);
451 else
452 ptr = oldptr = buffer;
454 write_leb128 (jit->prologue_end, ptr, &ptr);
455 write_leb128 (jit->epilogue_begin, ptr, &ptr);
457 write_leb128 (jit->num_line_numbers, ptr, &ptr);
458 for (i = 0; i < jit->num_line_numbers; i++) {
459 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
461 write_sleb128 (lne->il_offset, ptr, &ptr);
462 write_sleb128 (lne->native_offset, ptr, &ptr);
464 write_leb128 (jit->has_var_info, ptr, &ptr);
465 if (jit->has_var_info) {
466 *ptr++ = jit->this_var ? 1 : 0;
467 if (jit->this_var)
468 write_variable (jit->this_var, ptr, &ptr);
470 write_leb128 (jit->num_params, ptr, &ptr);
471 for (i = 0; i < jit->num_params; i++)
472 write_variable (&jit->params [i], ptr, &ptr);
474 write_leb128 (jit->num_locals, ptr, &ptr);
475 for (i = 0; i < jit->num_locals; i++)
476 write_variable (&jit->locals [i], ptr, &ptr);
478 *ptr++ = jit->gsharedvt_info_var ? 1 : 0;
479 if (jit->gsharedvt_info_var) {
480 write_variable (jit->gsharedvt_info_var, ptr, &ptr);
481 write_variable (jit->gsharedvt_locals_var, ptr, &ptr);
485 size = ptr - oldptr;
486 g_assert (size < max_size);
487 total_size = size + sizeof (MonoDebugMethodAddress);
489 if (method_is_dynamic (method)) {
490 address = (MonoDebugMethodAddress *)g_malloc0 (total_size);
491 } else {
492 address = (MonoDebugMethodAddress *)mono_mempool_alloc (table->mp, total_size);
495 address->code_start = jit->code_start;
496 address->code_size = jit->code_size;
498 memcpy (&address->data, oldptr, size);
499 if (max_size > BUFSIZ)
500 g_free (oldptr);
502 g_hash_table_insert (table->method_address_hash, method, address);
504 mono_debugger_unlock ();
505 return address;
508 void
509 mono_debug_remove_method (MonoMethod *method, MonoDomain *domain)
511 MonoDebugDataTable *table;
512 MonoDebugMethodAddress *address;
514 if (!mono_debug_initialized)
515 return;
517 g_assert (method_is_dynamic (method));
519 mono_debugger_lock ();
521 table = lookup_data_table (domain);
523 address = (MonoDebugMethodAddress *)g_hash_table_lookup (table->method_address_hash, method);
524 if (address)
525 g_free (address);
527 g_hash_table_remove (table->method_address_hash, method);
529 mono_debugger_unlock ();
532 void
533 mono_debug_add_delegate_trampoline (gpointer code, int size)
537 static inline guint32
538 read_leb128 (guint8 *ptr, guint8 **rptr)
540 guint32 result = 0, shift = 0;
542 while (TRUE) {
543 guint8 byte = *ptr++;
545 result |= (byte & 0x7f) << shift;
546 if ((byte & 0x80) == 0)
547 break;
548 shift += 7;
551 *rptr = ptr;
552 return result;
555 static inline gint32
556 read_sleb128 (guint8 *ptr, guint8 **rptr)
558 gint32 result = 0;
559 guint32 shift = 0;
561 while (TRUE) {
562 guint8 byte = *ptr++;
564 result |= (byte & 0x7f) << shift;
565 shift += 7;
567 if (byte & 0x80)
568 continue;
570 if ((shift < 32) && (byte & 0x40))
571 result |= - (1 << shift);
572 break;
575 *rptr = ptr;
576 return result;
579 static void
580 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
582 var->index = read_leb128 (ptr, &ptr);
583 var->offset = read_sleb128 (ptr, &ptr);
584 var->size = read_leb128 (ptr, &ptr);
585 var->begin_scope = read_leb128 (ptr, &ptr);
586 var->end_scope = read_leb128 (ptr, &ptr);
587 READ_UNALIGNED (MonoType *, ptr, var->type);
588 ptr += sizeof (gpointer);
589 *rptr = ptr;
592 void
593 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
595 if (!jit)
596 return;
597 g_free (jit->line_numbers);
598 g_free (jit->this_var);
599 g_free (jit->params);
600 g_free (jit->locals);
601 g_free (jit->gsharedvt_info_var);
602 g_free (jit->gsharedvt_locals_var);
603 g_free (jit);
606 static MonoDebugMethodJitInfo *
607 mono_debug_read_method (MonoDebugMethodAddress *address)
609 MonoDebugMethodJitInfo *jit;
610 guint32 i;
611 guint8 *ptr;
613 jit = g_new0 (MonoDebugMethodJitInfo, 1);
614 jit->code_start = address->code_start;
615 jit->code_size = address->code_size;
617 ptr = (guint8 *) &address->data;
619 jit->prologue_end = read_leb128 (ptr, &ptr);
620 jit->epilogue_begin = read_leb128 (ptr, &ptr);
622 jit->num_line_numbers = read_leb128 (ptr, &ptr);
623 jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
624 for (i = 0; i < jit->num_line_numbers; i++) {
625 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
627 lne->il_offset = read_sleb128 (ptr, &ptr);
628 lne->native_offset = read_sleb128 (ptr, &ptr);
630 jit->has_var_info = read_leb128 (ptr, &ptr);
631 if (jit->has_var_info) {
632 if (*ptr++) {
633 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
634 read_variable (jit->this_var, ptr, &ptr);
637 jit->num_params = read_leb128 (ptr, &ptr);
638 jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
639 for (i = 0; i < jit->num_params; i++)
640 read_variable (&jit->params [i], ptr, &ptr);
642 jit->num_locals = read_leb128 (ptr, &ptr);
643 jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
644 for (i = 0; i < jit->num_locals; i++)
645 read_variable (&jit->locals [i], ptr, &ptr);
647 if (*ptr++) {
648 jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
649 jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
650 read_variable (jit->gsharedvt_info_var, ptr, &ptr);
651 read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
655 return jit;
658 static MonoDebugMethodJitInfo *
659 find_method (MonoMethod *method, MonoDomain *domain)
661 MonoDebugDataTable *table;
662 MonoDebugMethodAddress *address;
664 table = lookup_data_table (domain);
665 address = (MonoDebugMethodAddress *)g_hash_table_lookup (table->method_address_hash, method);
667 if (!address)
668 return NULL;
670 return mono_debug_read_method (address);
673 MonoDebugMethodJitInfo *
674 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
676 MonoDebugMethodJitInfo *res;
678 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
679 return NULL;
681 mono_debugger_lock ();
682 res = find_method (method, domain);
683 mono_debugger_unlock ();
684 return res;
687 MonoDebugMethodAddressList *
688 mono_debug_lookup_method_addresses (MonoMethod *method)
690 g_assert_not_reached ();
691 return NULL;
694 static gint32
695 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
697 MonoDebugMethodJitInfo *jit;
698 int i;
700 jit = find_method (method, domain);
701 if (!jit || !jit->line_numbers)
702 goto cleanup_and_fail;
704 for (i = jit->num_line_numbers - 1; i >= 0; i--) {
705 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
707 if (lne.native_offset <= native_offset) {
708 mono_debug_free_method_jit_info (jit);
709 return lne.il_offset;
713 cleanup_and_fail:
714 mono_debug_free_method_jit_info (jit);
715 return -1;
719 * mono_debug_il_offset_from_address:
721 * Compute the IL offset corresponding to NATIVE_OFFSET inside the native
722 * code of METHOD in DOMAIN.
724 gint32
725 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
727 gint32 res;
729 mono_debugger_lock ();
731 res = il_offset_from_address (method, domain, native_offset);
733 mono_debugger_unlock ();
735 return res;
739 * mono_debug_lookup_source_location:
740 * @address: Native offset within the @method's machine code.
742 * Lookup the source code corresponding to the machine instruction located at
743 * native offset @address within @method.
745 * The returned `MonoDebugSourceLocation' contains both file / line number
746 * information and the corresponding IL offset. It must be freed by
747 * mono_debug_free_source_location().
749 MonoDebugSourceLocation *
750 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
752 MonoDebugMethodInfo *minfo;
753 MonoDebugSourceLocation *location;
754 gint32 offset;
756 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
757 return NULL;
759 mono_debugger_lock ();
760 minfo = mono_debug_lookup_method_internal (method);
761 if (!minfo || !minfo->handle) {
762 mono_debugger_unlock ();
763 return NULL;
766 if (!minfo->handle->ppdb && (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))) {
767 mono_debugger_unlock ();
768 return NULL;
771 offset = il_offset_from_address (method, domain, address);
772 if (offset < 0) {
773 mono_debugger_unlock ();
774 return NULL;
777 if (minfo->handle->ppdb)
778 location = mono_ppdb_lookup_location (minfo, offset);
779 else
780 location = mono_debug_symfile_lookup_location (minfo, offset);
781 mono_debugger_unlock ();
782 return location;
785 MonoDebugSourceLocation *
786 mono_debug_method_lookup_location (MonoDebugMethodInfo *minfo, int il_offset)
788 MonoDebugSourceLocation *location;
790 mono_debugger_lock ();
791 if (minfo->handle->ppdb)
792 location = mono_ppdb_lookup_location (minfo, il_offset);
793 else
794 location = mono_debug_symfile_lookup_location (minfo, il_offset);
795 mono_debugger_unlock ();
796 return location;
800 * mono_debug_lookup_locals:
802 * Return information about the local variables of MINFO.
803 * The result should be freed using mono_debug_free_locals ().
805 MonoDebugLocalsInfo*
806 mono_debug_lookup_locals (MonoMethod *method)
808 MonoDebugMethodInfo *minfo;
809 MonoDebugLocalsInfo *res;
811 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
812 return NULL;
814 mono_debugger_lock ();
815 minfo = mono_debug_lookup_method_internal (method);
816 if (!minfo || !minfo->handle) {
817 mono_debugger_unlock ();
818 return NULL;
821 if (minfo->handle->ppdb) {
822 res = mono_ppdb_lookup_locals (minfo);
823 } else {
824 if (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))
825 res = NULL;
826 else
827 res = mono_debug_symfile_lookup_locals (minfo);
829 mono_debugger_unlock ();
831 return res;
835 * mono_debug_free_locals:
837 * Free all the data allocated by mono_debug_lookup_locals ().
839 void
840 mono_debug_free_locals (MonoDebugLocalsInfo *info)
842 int i;
844 for (i = 0; i < info->num_locals; ++i)
845 g_free (info->locals [i].name);
846 g_free (info->locals);
847 g_free (info->code_blocks);
848 g_free (info);
852 * mono_debug_lookup_method_async_debug_info:
854 * Return information about the async stepping information of method.
855 * The result should be freed using mono_debug_free_async_debug_info ().
857 MonoDebugMethodAsyncInfo*
858 mono_debug_lookup_method_async_debug_info (MonoMethod *method)
860 MonoDebugMethodInfo *minfo;
861 MonoDebugMethodAsyncInfo *res = NULL;
863 if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
864 return NULL;
866 mono_debugger_lock ();
867 minfo = mono_debug_lookup_method_internal (method);
868 if (!minfo || !minfo->handle) {
869 mono_debugger_unlock ();
870 return NULL;
873 if (minfo->handle->ppdb)
874 res = mono_ppdb_lookup_method_async_debug_info (minfo);
876 mono_debugger_unlock ();
878 return res;
882 * mono_debug_free_method_async_debug_info:
884 * Free all the data allocated by mono_debug_lookup_method_async_debug_info ().
886 void
887 mono_debug_free_method_async_debug_info (MonoDebugMethodAsyncInfo *info)
889 if (info->num_awaits) {
890 g_free (info->yield_offsets);
891 g_free (info->resume_offsets);
892 g_free (info->move_next_method_token);
894 g_free (info);
898 * mono_debug_free_source_location:
899 * @location: A `MonoDebugSourceLocation'.
901 * Frees the @location.
903 void
904 mono_debug_free_source_location (MonoDebugSourceLocation *location)
906 if (location) {
907 g_free (location->source_file);
908 g_free (location);
912 static int (*get_seq_point) (MonoDomain *domain, MonoMethod *method, gint32 native_offset);
914 void
915 mono_install_get_seq_point (MonoGetSeqPointFunc func)
917 get_seq_point = func;
921 * mono_debug_print_stack_frame:
922 * @native_offset: Native offset within the @method's machine code.
924 * Conventient wrapper around mono_debug_lookup_source_location() which can be
925 * used if you only want to use the location to print a stack frame.
927 gchar *
928 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
930 MonoDebugSourceLocation *location;
931 gchar *fname, *ptr, *res;
932 int offset;
934 fname = mono_method_full_name (method, TRUE);
935 for (ptr = fname; *ptr; ptr++) {
936 if (*ptr == ':') *ptr = '.';
939 location = mono_debug_lookup_source_location (method, native_offset, domain);
941 if (!location) {
942 if (mono_debug_initialized) {
943 mono_debugger_lock ();
944 offset = il_offset_from_address (method, domain, native_offset);
945 mono_debugger_unlock ();
946 } else {
947 offset = -1;
950 if (offset < 0 && get_seq_point)
951 offset = get_seq_point (domain, method, native_offset);
953 if (offset < 0)
954 res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
955 else {
956 char *mvid = mono_guid_to_string_minimal ((uint8_t*)method->klass->image->heap_guid.data);
957 char *aotid = mono_runtime_get_aotid ();
958 if (aotid)
959 res = g_strdup_printf ("at %s [0x%05x] in <%s#%s>:0" , fname, offset, mvid, aotid);
960 else
961 res = g_strdup_printf ("at %s [0x%05x] in <%s>:0" , fname, offset, mvid);
963 g_free (aotid);
964 g_free (mvid);
966 g_free (fname);
967 return res;
970 res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
971 location->source_file, location->row);
973 g_free (fname);
974 mono_debug_free_source_location (location);
975 return res;
978 void
979 mono_set_is_debugger_attached (gboolean attached)
981 is_attached = attached;
984 gboolean
985 mono_is_debugger_attached (void)
987 return is_attached;
991 * Bundles
994 typedef struct _BundledSymfile BundledSymfile;
996 struct _BundledSymfile {
997 BundledSymfile *next;
998 const char *aname;
999 const mono_byte *raw_contents;
1000 int size;
1003 static BundledSymfile *bundled_symfiles = NULL;
1005 void
1006 mono_register_symfile_for_assembly (const char *assembly_name, const mono_byte *raw_contents, int size)
1008 BundledSymfile *bsymfile;
1010 bsymfile = g_new0 (BundledSymfile, 1);
1011 bsymfile->aname = assembly_name;
1012 bsymfile->raw_contents = raw_contents;
1013 bsymfile->size = size;
1014 bsymfile->next = bundled_symfiles;
1015 bundled_symfiles = bsymfile;
1018 static MonoDebugHandle *
1019 open_symfile_from_bundle (MonoImage *image)
1021 BundledSymfile *bsymfile;
1023 for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) {
1024 if (strcmp (bsymfile->aname, image->module_name))
1025 continue;
1027 return mono_debug_open_image (image, bsymfile->raw_contents, bsymfile->size);
1030 return NULL;
1033 void
1034 mono_debugger_lock (void)
1036 g_assert (mono_debug_initialized);
1037 mono_os_mutex_lock (&debugger_lock_mutex);
1040 void
1041 mono_debugger_unlock (void)
1043 g_assert (mono_debug_initialized);
1044 mono_os_mutex_unlock (&debugger_lock_mutex);
1048 * mono_debug_enabled:
1050 * Returns true is debug information is enabled. This doesn't relate if a debugger is present or not.
1052 mono_bool
1053 mono_debug_enabled (void)
1055 return mono_debug_format != MONO_DEBUG_FORMAT_NONE;
1058 void
1059 mono_debug_get_seq_points (MonoDebugMethodInfo *minfo, char **source_file, GPtrArray **source_file_list, int **source_files, MonoSymSeqPoint **seq_points, int *n_seq_points)
1061 if (minfo->handle->ppdb)
1062 mono_ppdb_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points);
1063 else
1064 mono_debug_symfile_get_seq_points (minfo, source_file, source_file_list, source_files, seq_points, n_seq_points);