Merge pull request #1606 from alexanderkyte/debug-finalizers
[mono.git] / mono / metadata / mono-debug.c
1 /*
2  * mono-debug.c: 
3  *
4  * Author:
5  *      Mono Project (http://www.mono-project.com)
6  *
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  */
11
12 #include <config.h>
13 #include <mono/metadata/assembly.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/tokentype.h>
16 #include <mono/metadata/appdomain.h>
17 #include <mono/metadata/class-internals.h>
18 #include <mono/metadata/mono-debug.h>
19 #include <mono/metadata/mono-debug-debugger.h>
20 #include <mono/metadata/mono-endian.h>
21 #include <mono/metadata/gc-internal.h>
22 #include <mono/metadata/mempool.h>
23 #include <string.h>
24
25 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
26
27 #if NO_UNALIGNED_ACCESS
28 #define WRITE_UNALIGNED(type, addr, val) \
29         memcpy(addr, &val, sizeof(type))
30 #define READ_UNALIGNED(type, addr, val) \
31         memcpy(&val, addr, sizeof(type))
32 #else
33 #define WRITE_UNALIGNED(type, addr, val) \
34         (*(type *)(addr) = (val))
35 #define READ_UNALIGNED(type, addr, val) \
36         val = (*(type *)(addr))
37 #endif
38
39 /* This contains per-domain info */
40 struct _MonoDebugDataTable {
41         MonoMemPool *mp;
42         GHashTable *method_address_hash;
43 };
44
45 /* This contains JIT debugging information about a method in serialized format */
46 struct _MonoDebugMethodAddress {
47         const guint8 *code_start;
48         guint32 code_size;
49         guint8 data [MONO_ZERO_LEN_ARRAY];
50 };
51
52 static MonoDebugFormat mono_debug_format = MONO_DEBUG_FORMAT_NONE;
53
54 static gboolean mono_debug_initialized = FALSE;
55 /* Maps MonoImage -> MonoMonoDebugHandle */
56 static GHashTable *mono_debug_handles;
57 /* Maps MonoDomain -> MonoDataTable */
58 static GHashTable *data_table_hash;
59
60 static mono_mutex_t debugger_lock_mutex;
61
62 static int initialized = 0;
63 static gboolean is_attached = FALSE;
64
65 static MonoDebugHandle     *mono_debug_open_image      (MonoImage *image, const guint8 *raw_contents, int size);
66
67 static MonoDebugHandle     *mono_debug_get_image      (MonoImage *image);
68 static void                 mono_debug_add_assembly    (MonoAssembly *assembly,
69                                                         gpointer user_data);
70
71 static MonoDebugHandle     *open_symfile_from_bundle   (MonoImage *image);
72
73 static MonoDebugDataTable *
74 create_data_table (MonoDomain *domain)
75 {
76         MonoDebugDataTable *table;
77
78         table = g_new0 (MonoDebugDataTable, 1);
79
80         table->mp = mono_mempool_new ();
81         table->method_address_hash = g_hash_table_new (NULL, NULL);
82
83         if (domain)
84                 g_hash_table_insert (data_table_hash, domain, table);
85
86         return table;
87 }
88
89 static void
90 free_data_table (MonoDebugDataTable *table)
91 {
92         mono_mempool_destroy (table->mp);
93         g_hash_table_destroy (table->method_address_hash);
94
95         g_free (table);
96 }
97
98 static MonoDebugDataTable *
99 lookup_data_table (MonoDomain *domain)
100 {
101         MonoDebugDataTable *table;
102
103         table = g_hash_table_lookup (data_table_hash, domain);
104         if (!table) {
105                 g_error ("lookup_data_table () failed for %p\n", domain);
106                 g_assert (table);
107         }
108         return table;
109 }
110
111 static void
112 free_debug_handle (MonoDebugHandle *handle)
113 {
114         if (handle->symfile)
115                 mono_debug_close_mono_symbol_file (handle->symfile);
116         /* decrease the refcount added with mono_image_addref () */
117         mono_image_close (handle->image);
118         g_free (handle);
119 }
120
121 /*
122  * Initialize debugging support.
123  *
124  * This method must be called after loading corlib,
125  * but before opening the application's main assembly because we need to set some
126  * callbacks here.
127  */
128 void
129 mono_debug_init (MonoDebugFormat format)
130 {
131         g_assert (!mono_debug_initialized);
132         if (format == MONO_DEBUG_FORMAT_DEBUGGER)
133                 g_error ("The mdb debugger is no longer supported.");
134
135         mono_debug_initialized = TRUE;
136         mono_debug_format = format;
137
138         mono_debugger_initialize ();
139
140         mono_debugger_lock ();
141
142         mono_debug_handles = g_hash_table_new_full
143                 (NULL, NULL, NULL, (GDestroyNotify) free_debug_handle);
144
145         data_table_hash = g_hash_table_new_full (
146                 NULL, NULL, NULL, (GDestroyNotify) free_data_table);
147
148         mono_install_assembly_load_hook (mono_debug_add_assembly, NULL);
149
150         mono_debugger_unlock ();
151 }
152
153 void
154 mono_debug_open_image_from_memory (MonoImage *image, const guint8 *raw_contents, int size)
155 {
156         if (!mono_debug_initialized)
157                 return;
158
159         mono_debug_open_image (image, raw_contents, size);
160 }
161
162 void
163 mono_debug_cleanup (void)
164 {
165         if (mono_debug_handles)
166                 g_hash_table_destroy (mono_debug_handles);
167         mono_debug_handles = NULL;
168
169         if (data_table_hash) {
170                 g_hash_table_destroy (data_table_hash);
171                 data_table_hash = NULL;
172         }
173 }
174
175 void
176 mono_debug_domain_create (MonoDomain *domain)
177 {
178         if (!mono_debug_initialized)
179                 return;
180
181         mono_debugger_lock ();
182
183         create_data_table (domain);
184
185         mono_debugger_unlock ();
186 }
187
188 void
189 mono_debug_domain_unload (MonoDomain *domain)
190 {
191         MonoDebugDataTable *table;
192
193         if (!mono_debug_initialized)
194                 return;
195
196         mono_debugger_lock ();
197
198         table = g_hash_table_lookup (data_table_hash, domain);
199         if (!table) {
200                 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
201                            domain, mono_domain_get_id (domain));
202                 mono_debugger_unlock ();
203                 return;
204         }
205
206         g_hash_table_remove (data_table_hash, domain);
207
208         mono_debugger_unlock ();
209 }
210
211 /*
212  * LOCKING: Assumes the debug lock is held.
213  */
214 static MonoDebugHandle *
215 mono_debug_get_image (MonoImage *image)
216 {
217         return g_hash_table_lookup (mono_debug_handles, image);
218 }
219
220 void
221 mono_debug_close_image (MonoImage *image)
222 {
223         MonoDebugHandle *handle;
224
225         if (!mono_debug_initialized)
226                 return;
227
228         mono_debugger_lock ();
229
230         handle = mono_debug_get_image (image);
231         if (!handle) {
232                 mono_debugger_unlock ();
233                 return;
234         }
235
236         g_hash_table_remove (mono_debug_handles, image);
237
238         mono_debugger_unlock ();
239 }
240
241 static MonoDebugHandle *
242 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
243 {
244         MonoDebugHandle *handle;
245
246         if (mono_image_is_dynamic (image))
247                 return NULL;
248
249         mono_debugger_lock ();
250
251         handle = mono_debug_get_image (image);
252         if (handle != NULL) {
253                 mono_debugger_unlock ();
254                 return handle;
255         }
256
257         handle = g_new0 (MonoDebugHandle, 1);
258
259         handle->image = image;
260         mono_image_addref (image);
261
262         handle->symfile = mono_debug_open_mono_symbols (
263                 handle, raw_contents, size, FALSE);
264
265         g_hash_table_insert (mono_debug_handles, image, handle);
266
267         mono_debugger_unlock ();
268
269         return handle;
270 }
271
272 static void
273 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
274 {
275         MonoDebugHandle *handle;
276         MonoImage *image;
277
278         mono_debugger_lock ();
279         image = mono_assembly_get_image (assembly);
280         handle = open_symfile_from_bundle (image);
281         if (!handle)
282                 mono_debug_open_image (image, NULL, 0);
283         mono_debugger_unlock ();
284 }
285
286 struct LookupMethodData
287 {
288         MonoDebugMethodInfo *minfo;
289         MonoMethod *method;
290 };
291
292 static void
293 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
294 {
295         MonoDebugHandle *handle = (MonoDebugHandle *) value;
296         struct LookupMethodData *data = (struct LookupMethodData *) user_data;
297
298         if (data->minfo)
299                 return;
300
301         if (handle->symfile)
302                 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
303 }
304
305 static MonoDebugMethodInfo *
306 mono_debug_lookup_method_internal (MonoMethod *method)
307 {
308         struct LookupMethodData data;
309
310         data.minfo = NULL;
311         data.method = method;
312
313         if (!mono_debug_handles)
314                 return NULL;
315
316         g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
317         return data.minfo;
318 }
319
320 /**
321  * mono_debug_lookup_method:
322  *
323  * Lookup symbol file information for the method @method.  The returned
324  * `MonoDebugMethodInfo' is a private structure, but it can be passed to
325  * mono_debug_symfile_lookup_location().
326  */
327 MonoDebugMethodInfo *
328 mono_debug_lookup_method (MonoMethod *method)
329 {
330         MonoDebugMethodInfo *minfo;
331
332         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
333                 return NULL;
334
335         mono_debugger_lock ();
336         minfo = mono_debug_lookup_method_internal (method);
337         mono_debugger_unlock ();
338         return minfo;
339 }
340
341 typedef struct
342 {
343         gboolean found;
344         MonoImage *image;
345 } LookupImageData;
346
347 static void
348 lookup_image_func (gpointer key, gpointer value, gpointer user_data)
349 {
350         MonoDebugHandle *handle = (MonoDebugHandle *) value;
351         LookupImageData *data = (LookupImageData *) user_data;
352
353         if (data->found)
354                 return;
355
356         if (handle->image == data->image && handle->symfile)
357                 data->found = TRUE;
358 }
359
360 gboolean
361 mono_debug_image_has_debug_info (MonoImage *image)
362 {
363         LookupImageData data;
364
365         if (!mono_debug_handles)
366                 return FALSE;
367
368         memset (&data, 0, sizeof (data));
369         data.image = image;
370
371         mono_debugger_lock ();
372         g_hash_table_foreach (mono_debug_handles, lookup_image_func, &data);
373         mono_debugger_unlock ();
374         return data.found;
375 }
376
377 static inline void
378 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
379 {
380         do {
381                 guint8 byte = value & 0x7f;
382                 value >>= 7;
383                 if (value)
384                         byte |= 0x80;
385                 *ptr++ = byte;
386         } while (value);
387
388         *rptr = ptr;
389 }
390
391 static inline void
392 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
393 {
394         gboolean more = 1;
395
396         while (more) {
397                 guint8 byte = value & 0x7f;
398                 value >>= 7;
399
400                 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
401                         more = 0;
402                 else
403                         byte |= 0x80;
404                 *ptr++ = byte;
405         }
406
407         *rptr = ptr;
408 }
409
410 static void
411 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
412 {
413         write_leb128 (var->index, ptr, &ptr);
414         write_sleb128 (var->offset, ptr, &ptr);
415         write_leb128 (var->size, ptr, &ptr);
416         write_leb128 (var->begin_scope, ptr, &ptr);
417         write_leb128 (var->end_scope, ptr, &ptr);
418         WRITE_UNALIGNED (gpointer, ptr, var->type);
419         ptr += sizeof (gpointer);
420         *rptr = ptr;
421 }
422
423 MonoDebugMethodAddress *
424 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
425 {
426         MonoDebugDataTable *table;
427         MonoDebugMethodAddress *address;
428         guint8 buffer [BUFSIZ];
429         guint8 *ptr, *oldptr;
430         guint32 i, size, total_size, max_size;
431
432         mono_debugger_lock ();
433
434         table = lookup_data_table (domain);
435
436         max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
437                 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
438
439         if (max_size > BUFSIZ)
440                 ptr = oldptr = g_malloc (max_size);
441         else
442                 ptr = oldptr = buffer;
443
444         write_leb128 (jit->prologue_end, ptr, &ptr);
445         write_leb128 (jit->epilogue_begin, ptr, &ptr);
446
447         write_leb128 (jit->num_line_numbers, ptr, &ptr);
448         for (i = 0; i < jit->num_line_numbers; i++) {
449                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
450
451                 write_sleb128 (lne->il_offset, ptr, &ptr);
452                 write_sleb128 (lne->native_offset, ptr, &ptr);
453         }
454
455         *ptr++ = jit->this_var ? 1 : 0;
456         if (jit->this_var)
457                 write_variable (jit->this_var, ptr, &ptr);
458
459         write_leb128 (jit->num_params, ptr, &ptr);
460         for (i = 0; i < jit->num_params; i++)
461                 write_variable (&jit->params [i], ptr, &ptr);
462
463         write_leb128 (jit->num_locals, ptr, &ptr);
464         for (i = 0; i < jit->num_locals; i++)
465                 write_variable (&jit->locals [i], ptr, &ptr);
466
467         *ptr++ = jit->gsharedvt_info_var ? 1 : 0;
468         if (jit->gsharedvt_info_var) {
469                 write_variable (jit->gsharedvt_info_var, ptr, &ptr);
470                 write_variable (jit->gsharedvt_locals_var, ptr, &ptr);
471         }
472
473         size = ptr - oldptr;
474         g_assert (size < max_size);
475         total_size = size + sizeof (MonoDebugMethodAddress);
476
477         if (method_is_dynamic (method)) {
478                 address = g_malloc0 (total_size);
479         } else {
480                 address = mono_mempool_alloc (table->mp, total_size);
481         }
482
483         address->code_start = jit->code_start;
484         address->code_size = jit->code_size;
485
486         memcpy (&address->data, oldptr, size);
487         if (max_size > BUFSIZ)
488                 g_free (oldptr);
489
490         g_hash_table_insert (table->method_address_hash, method, address);
491
492         mono_debugger_unlock ();
493         return address;
494 }
495
496 void
497 mono_debug_remove_method (MonoMethod *method, MonoDomain *domain)
498 {
499         MonoDebugDataTable *table;
500         MonoDebugMethodAddress *address;
501
502         if (!mono_debug_initialized)
503                 return;
504
505         g_assert (method_is_dynamic (method));
506
507         mono_debugger_lock ();
508
509         table = lookup_data_table (domain);
510
511         address = g_hash_table_lookup (table->method_address_hash, method);
512         if (address)
513                 g_free (address);
514
515         g_hash_table_remove (table->method_address_hash, method);
516
517         mono_debugger_unlock ();
518 }
519
520 void
521 mono_debug_add_delegate_trampoline (gpointer code, int size)
522 {
523 }
524
525 static inline guint32
526 read_leb128 (guint8 *ptr, guint8 **rptr)
527 {
528         guint32 result = 0, shift = 0;
529
530         while (TRUE) {
531                 guint8 byte = *ptr++;
532
533                 result |= (byte & 0x7f) << shift;
534                 if ((byte & 0x80) == 0)
535                         break;
536                 shift += 7;
537         }
538
539         *rptr = ptr;
540         return result;
541 }
542
543 static inline gint32
544 read_sleb128 (guint8 *ptr, guint8 **rptr)
545 {
546         gint32 result = 0;
547         guint32 shift = 0;
548
549         while (TRUE) {
550                 guint8 byte = *ptr++;
551
552                 result |= (byte & 0x7f) << shift;
553                 shift += 7;
554
555                 if (byte & 0x80)
556                         continue;
557
558                 if ((shift < 32) && (byte & 0x40))
559                         result |= - (1 << shift);
560                 break;
561         }
562
563         *rptr = ptr;
564         return result;
565 }
566
567 static void
568 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
569 {
570         var->index = read_leb128 (ptr, &ptr);
571         var->offset = read_sleb128 (ptr, &ptr);
572         var->size = read_leb128 (ptr, &ptr);
573         var->begin_scope = read_leb128 (ptr, &ptr);
574         var->end_scope = read_leb128 (ptr, &ptr);
575         READ_UNALIGNED (gpointer, ptr, var->type);
576         ptr += sizeof (gpointer);
577         *rptr = ptr;
578 }
579
580 void
581 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
582 {
583         if (!jit)
584                 return;
585         g_free (jit->line_numbers);
586         g_free (jit->this_var);
587         g_free (jit->params);
588         g_free (jit->locals);
589         g_free (jit->gsharedvt_info_var);
590         g_free (jit->gsharedvt_locals_var);
591         g_free (jit);
592 }
593
594 static MonoDebugMethodJitInfo *
595 mono_debug_read_method (MonoDebugMethodAddress *address)
596 {
597         MonoDebugMethodJitInfo *jit;
598         guint32 i;
599         guint8 *ptr;
600
601         jit = g_new0 (MonoDebugMethodJitInfo, 1);
602         jit->code_start = address->code_start;
603         jit->code_size = address->code_size;
604
605         ptr = (guint8 *) &address->data;
606
607         jit->prologue_end = read_leb128 (ptr, &ptr);
608         jit->epilogue_begin = read_leb128 (ptr, &ptr);
609
610         jit->num_line_numbers = read_leb128 (ptr, &ptr);
611         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
612         for (i = 0; i < jit->num_line_numbers; i++) {
613                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
614
615                 lne->il_offset = read_sleb128 (ptr, &ptr);
616                 lne->native_offset = read_sleb128 (ptr, &ptr);
617         }
618
619         if (*ptr++) {
620                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
621                 read_variable (jit->this_var, ptr, &ptr);
622         }
623
624         jit->num_params = read_leb128 (ptr, &ptr);
625         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
626         for (i = 0; i < jit->num_params; i++)
627                 read_variable (&jit->params [i], ptr, &ptr);
628
629         jit->num_locals = read_leb128 (ptr, &ptr);
630         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
631         for (i = 0; i < jit->num_locals; i++)
632                 read_variable (&jit->locals [i], ptr, &ptr);
633
634         if (*ptr++) {
635                 jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
636                 jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
637                 read_variable (jit->gsharedvt_info_var, ptr, &ptr);
638                 read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
639         }
640
641         return jit;
642 }
643
644 static MonoDebugMethodJitInfo *
645 find_method (MonoMethod *method, MonoDomain *domain)
646 {
647         MonoDebugDataTable *table;
648         MonoDebugMethodAddress *address;
649
650         table = lookup_data_table (domain);
651         address = g_hash_table_lookup (table->method_address_hash, method);
652
653         if (!address)
654                 return NULL;
655
656         return mono_debug_read_method (address);
657 }
658
659 MonoDebugMethodJitInfo *
660 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
661 {
662         MonoDebugMethodJitInfo *res;
663
664         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
665                 return NULL;
666
667         mono_debugger_lock ();
668         res = find_method (method, domain);
669         mono_debugger_unlock ();
670         return res;
671 }
672
673 MonoDebugMethodAddressList *
674 mono_debug_lookup_method_addresses (MonoMethod *method)
675 {
676         g_assert_not_reached ();
677         return NULL;
678 }
679
680 static gint32
681 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
682 {
683         MonoDebugMethodJitInfo *jit;
684         int i;
685
686         jit = find_method (method, domain);
687         if (!jit || !jit->line_numbers)
688                 goto cleanup_and_fail;
689
690         for (i = jit->num_line_numbers - 1; i >= 0; i--) {
691                 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
692
693                 if (lne.native_offset <= native_offset) {
694                         mono_debug_free_method_jit_info (jit);
695                         return lne.il_offset;
696                 }
697         }
698
699 cleanup_and_fail:
700         mono_debug_free_method_jit_info (jit);
701         return -1;
702 }
703
704 /**
705  * mono_debug_il_offset_from_address:
706  *
707  *   Compute the IL offset corresponding to NATIVE_OFFSET inside the native
708  * code of METHOD in DOMAIN.
709  */
710 gint32
711 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
712 {
713         gint32 res;
714
715         mono_debugger_lock ();
716
717         res = il_offset_from_address (method, domain, native_offset);
718
719         mono_debugger_unlock ();
720
721         return res;
722 }
723
724 /**
725  * mono_debug_lookup_source_location:
726  * @address: Native offset within the @method's machine code.
727  *
728  * Lookup the source code corresponding to the machine instruction located at
729  * native offset @address within @method.
730  *
731  * The returned `MonoDebugSourceLocation' contains both file / line number
732  * information and the corresponding IL offset.  It must be freed by
733  * mono_debug_free_source_location().
734  */
735 MonoDebugSourceLocation *
736 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
737 {
738         MonoDebugMethodInfo *minfo;
739         MonoDebugSourceLocation *location;
740         gint32 offset;
741
742         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
743                 return NULL;
744
745         mono_debugger_lock ();
746         minfo = mono_debug_lookup_method_internal (method);
747         if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
748                 mono_debugger_unlock ();
749                 return NULL;
750         }
751
752         offset = il_offset_from_address (method, domain, address);
753         if (offset < 0) {
754                 mono_debugger_unlock ();
755                 return NULL;
756         }
757
758         location = mono_debug_symfile_lookup_location (minfo, offset);
759         mono_debugger_unlock ();
760         return location;
761 }
762
763 /*
764  * mono_debug_lookup_locals:
765  *
766  *   Return information about the local variables of MINFO.
767  * The result should be freed using mono_debug_symfile_free_locals ().
768  */
769 MonoDebugLocalsInfo*
770 mono_debug_lookup_locals (MonoMethod *method)
771 {
772         MonoDebugMethodInfo *minfo;
773         MonoDebugLocalsInfo *res;
774
775         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
776                 return NULL;
777
778         mono_debugger_lock ();
779         minfo = mono_debug_lookup_method_internal (method);
780         if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
781                 mono_debugger_unlock ();
782                 return NULL;
783         }
784
785         res = mono_debug_symfile_lookup_locals (minfo);
786         mono_debugger_unlock ();
787
788         return res;
789 }
790
791 /**
792  * mono_debug_free_source_location:
793  * @location: A `MonoDebugSourceLocation'.
794  *
795  * Frees the @location.
796  */
797 void
798 mono_debug_free_source_location (MonoDebugSourceLocation *location)
799 {
800         if (location) {
801                 g_free (location->source_file);
802                 g_free (location);
803         }
804 }
805
806 /**
807  * mono_debug_print_stack_frame:
808  * @native_offset: Native offset within the @method's machine code.
809  *
810  * Conventient wrapper around mono_debug_lookup_source_location() which can be
811  * used if you only want to use the location to print a stack frame.
812  */
813 gchar *
814 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
815 {
816         MonoDebugSourceLocation *location;
817         gchar *fname, *ptr, *res;
818         int offset;
819
820         fname = mono_method_full_name (method, TRUE);
821         for (ptr = fname; *ptr; ptr++) {
822                 if (*ptr == ':') *ptr = '.';
823         }
824
825         location = mono_debug_lookup_source_location (method, native_offset, domain);
826
827         if (!location) {
828                 if (mono_debug_initialized) {
829                         mono_debugger_lock ();
830                         offset = il_offset_from_address (method, domain, native_offset);
831                         mono_debugger_unlock ();
832                 } else {
833                         offset = -1;
834                 }
835
836                 if (offset < 0)
837                         res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
838                 else
839                         res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
840                 g_free (fname);
841                 return res;
842         }
843
844         res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
845                                location->source_file, location->row);
846
847         g_free (fname);
848         mono_debug_free_source_location (location);
849         return res;
850 }
851
852 void
853 mono_set_is_debugger_attached (gboolean attached)
854 {
855         is_attached = attached;
856 }
857
858 gboolean
859 mono_is_debugger_attached (void)
860 {
861         return is_attached;
862 }
863
864 /*
865  * Bundles
866  */
867
868 typedef struct _BundledSymfile BundledSymfile;
869
870 struct _BundledSymfile {
871         BundledSymfile *next;
872         const char *aname;
873         const mono_byte *raw_contents;
874         int size;
875 };
876
877 static BundledSymfile *bundled_symfiles = NULL;
878
879 void
880 mono_register_symfile_for_assembly (const char *assembly_name, const mono_byte *raw_contents, int size)
881 {
882         BundledSymfile *bsymfile;
883
884         bsymfile = g_new0 (BundledSymfile, 1);
885         bsymfile->aname = assembly_name;
886         bsymfile->raw_contents = raw_contents;
887         bsymfile->size = size;
888         bsymfile->next = bundled_symfiles;
889         bundled_symfiles = bsymfile;
890 }
891
892 static MonoDebugHandle *
893 open_symfile_from_bundle (MonoImage *image)
894 {
895         BundledSymfile *bsymfile;
896
897         for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) {
898                 if (strcmp (bsymfile->aname, image->module_name))
899                         continue;
900
901                 return mono_debug_open_image (image, bsymfile->raw_contents, bsymfile->size);
902         }
903
904         return NULL;
905 }
906
907 void
908 mono_debugger_lock (void)
909 {
910         g_assert (initialized);
911         mono_mutex_lock (&debugger_lock_mutex);
912 }
913
914 void
915 mono_debugger_unlock (void)
916 {
917         g_assert (initialized);
918         mono_mutex_unlock (&debugger_lock_mutex);
919 }
920
921 void
922 mono_debugger_initialize ()
923 {
924         mono_mutex_init_recursive (&debugger_lock_mutex);
925         initialized = 1;
926 }
927
928 /**
929  * mono_debug_enabled:
930  *
931  * Returns true is debug information is enabled. This doesn't relate if a debugger is present or not.
932  */
933 mono_bool
934 mono_debug_enabled (void)
935 {
936         return mono_debug_format != MONO_DEBUG_FORMAT_NONE;
937 }