[sdb] Fix the detection of whenever an image has debug info or not.
[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         MonoDebugDataTable *table;
179
180         if (!mono_debug_initialized)
181                 return;
182
183         mono_debugger_lock ();
184
185         table = create_data_table (domain);
186
187         mono_debugger_unlock ();
188 }
189
190 void
191 mono_debug_domain_unload (MonoDomain *domain)
192 {
193         MonoDebugDataTable *table;
194
195         if (!mono_debug_initialized)
196                 return;
197
198         mono_debugger_lock ();
199
200         table = g_hash_table_lookup (data_table_hash, domain);
201         if (!table) {
202                 g_warning (G_STRLOC ": unloading unknown domain %p / %d",
203                            domain, mono_domain_get_id (domain));
204                 mono_debugger_unlock ();
205                 return;
206         }
207
208         g_hash_table_remove (data_table_hash, domain);
209
210         mono_debugger_unlock ();
211 }
212
213 /*
214  * LOCKING: Assumes the debug lock is held.
215  */
216 static MonoDebugHandle *
217 mono_debug_get_image (MonoImage *image)
218 {
219         return g_hash_table_lookup (mono_debug_handles, image);
220 }
221
222 void
223 mono_debug_close_image (MonoImage *image)
224 {
225         MonoDebugHandle *handle;
226
227         if (!mono_debug_initialized)
228                 return;
229
230         mono_debugger_lock ();
231
232         handle = mono_debug_get_image (image);
233         if (!handle) {
234                 mono_debugger_unlock ();
235                 return;
236         }
237
238         g_hash_table_remove (mono_debug_handles, image);
239
240         mono_debugger_unlock ();
241 }
242
243 static MonoDebugHandle *
244 mono_debug_open_image (MonoImage *image, const guint8 *raw_contents, int size)
245 {
246         MonoDebugHandle *handle;
247
248         if (mono_image_is_dynamic (image))
249                 return NULL;
250
251         mono_debugger_lock ();
252
253         handle = mono_debug_get_image (image);
254         if (handle != NULL) {
255                 mono_debugger_unlock ();
256                 return handle;
257         }
258
259         handle = g_new0 (MonoDebugHandle, 1);
260
261         handle->image = image;
262         mono_image_addref (image);
263
264         handle->symfile = mono_debug_open_mono_symbols (
265                 handle, raw_contents, size, FALSE);
266
267         g_hash_table_insert (mono_debug_handles, image, handle);
268
269         mono_debugger_unlock ();
270
271         return handle;
272 }
273
274 static void
275 mono_debug_add_assembly (MonoAssembly *assembly, gpointer user_data)
276 {
277         MonoDebugHandle *handle;
278         MonoImage *image;
279
280         mono_debugger_lock ();
281         image = mono_assembly_get_image (assembly);
282         handle = open_symfile_from_bundle (image);
283         if (!handle)
284                 mono_debug_open_image (image, NULL, 0);
285         mono_debugger_unlock ();
286 }
287
288 struct LookupMethodData
289 {
290         MonoDebugMethodInfo *minfo;
291         MonoMethod *method;
292 };
293
294 static void
295 lookup_method_func (gpointer key, gpointer value, gpointer user_data)
296 {
297         MonoDebugHandle *handle = (MonoDebugHandle *) value;
298         struct LookupMethodData *data = (struct LookupMethodData *) user_data;
299
300         if (data->minfo)
301                 return;
302
303         if (handle->symfile)
304                 data->minfo = mono_debug_symfile_lookup_method (handle, data->method);
305 }
306
307 static MonoDebugMethodInfo *
308 mono_debug_lookup_method_internal (MonoMethod *method)
309 {
310         struct LookupMethodData data;
311
312         data.minfo = NULL;
313         data.method = method;
314
315         if (!mono_debug_handles)
316                 return NULL;
317
318         g_hash_table_foreach (mono_debug_handles, lookup_method_func, &data);
319         return data.minfo;
320 }
321
322 /**
323  * mono_debug_lookup_method:
324  *
325  * Lookup symbol file information for the method @method.  The returned
326  * `MonoDebugMethodInfo' is a private structure, but it can be passed to
327  * mono_debug_symfile_lookup_location().
328  */
329 MonoDebugMethodInfo *
330 mono_debug_lookup_method (MonoMethod *method)
331 {
332         MonoDebugMethodInfo *minfo;
333
334         mono_debugger_lock ();
335         minfo = mono_debug_lookup_method_internal (method);
336         mono_debugger_unlock ();
337         return minfo;
338 }
339
340 typedef struct
341 {
342         gboolean found;
343         MonoImage *image;
344 } LookupImageData;
345
346 static void
347 lookup_image_func (gpointer key, gpointer value, gpointer user_data)
348 {
349         MonoDebugHandle *handle = (MonoDebugHandle *) value;
350         LookupImageData *data = (LookupImageData *) user_data;
351
352         if (data->found)
353                 return;
354
355         if (handle->image == data->image && handle->symfile)
356                 data->found = TRUE;
357 }
358
359 gboolean
360 mono_debug_image_has_debug_info (MonoImage *image)
361 {
362         LookupImageData data;
363
364         if (!mono_debug_handles)
365                 return FALSE;
366
367         memset (&data, 0, sizeof (data));
368         data.image = image;
369
370         mono_debugger_lock ();
371         g_hash_table_foreach (mono_debug_handles, lookup_image_func, &data);
372         mono_debugger_unlock ();
373         return data.found;
374 }
375
376 static inline void
377 write_leb128 (guint32 value, guint8 *ptr, guint8 **rptr)
378 {
379         do {
380                 guint8 byte = value & 0x7f;
381                 value >>= 7;
382                 if (value)
383                         byte |= 0x80;
384                 *ptr++ = byte;
385         } while (value);
386
387         *rptr = ptr;
388 }
389
390 static inline void
391 write_sleb128 (gint32 value, guint8 *ptr, guint8 **rptr)
392 {
393         gboolean more = 1;
394
395         while (more) {
396                 guint8 byte = value & 0x7f;
397                 value >>= 7;
398
399                 if (((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && (byte & 0x40)))
400                         more = 0;
401                 else
402                         byte |= 0x80;
403                 *ptr++ = byte;
404         }
405
406         *rptr = ptr;
407 }
408
409 static void
410 write_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
411 {
412         write_leb128 (var->index, ptr, &ptr);
413         write_sleb128 (var->offset, ptr, &ptr);
414         write_leb128 (var->size, ptr, &ptr);
415         write_leb128 (var->begin_scope, ptr, &ptr);
416         write_leb128 (var->end_scope, ptr, &ptr);
417         WRITE_UNALIGNED (gpointer, ptr, var->type);
418         ptr += sizeof (gpointer);
419         *rptr = ptr;
420 }
421
422 MonoDebugMethodAddress *
423 mono_debug_add_method (MonoMethod *method, MonoDebugMethodJitInfo *jit, MonoDomain *domain)
424 {
425         MonoDebugDataTable *table;
426         MonoDebugMethodAddress *address;
427         MonoDebugMethodInfo *minfo;
428         MonoDebugHandle *handle;
429         guint8 buffer [BUFSIZ];
430         guint8 *ptr, *oldptr;
431         guint32 i, size, total_size, max_size;
432
433         mono_debugger_lock ();
434
435         table = lookup_data_table (domain);
436
437         handle = mono_debug_get_image (method->klass->image);
438         minfo = mono_debug_lookup_method_internal (method);
439
440         max_size = (5 * 5) + 1 + (10 * jit->num_line_numbers) +
441                 (25 + sizeof (gpointer)) * (1 + jit->num_params + jit->num_locals);
442
443         if (max_size > BUFSIZ)
444                 ptr = oldptr = g_malloc (max_size);
445         else
446                 ptr = oldptr = buffer;
447
448         write_leb128 (jit->prologue_end, ptr, &ptr);
449         write_leb128 (jit->epilogue_begin, ptr, &ptr);
450
451         write_leb128 (jit->num_line_numbers, ptr, &ptr);
452         for (i = 0; i < jit->num_line_numbers; i++) {
453                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
454
455                 write_sleb128 (lne->il_offset, ptr, &ptr);
456                 write_sleb128 (lne->native_offset, ptr, &ptr);
457         }
458
459         *ptr++ = jit->this_var ? 1 : 0;
460         if (jit->this_var)
461                 write_variable (jit->this_var, ptr, &ptr);
462
463         write_leb128 (jit->num_params, ptr, &ptr);
464         for (i = 0; i < jit->num_params; i++)
465                 write_variable (&jit->params [i], ptr, &ptr);
466
467         write_leb128 (jit->num_locals, ptr, &ptr);
468         for (i = 0; i < jit->num_locals; i++)
469                 write_variable (&jit->locals [i], ptr, &ptr);
470
471         *ptr++ = jit->gsharedvt_info_var ? 1 : 0;
472         if (jit->gsharedvt_info_var) {
473                 write_variable (jit->gsharedvt_info_var, ptr, &ptr);
474                 write_variable (jit->gsharedvt_locals_var, ptr, &ptr);
475         }
476
477         size = ptr - oldptr;
478         g_assert (size < max_size);
479         total_size = size + sizeof (MonoDebugMethodAddress);
480
481         if (method_is_dynamic (method)) {
482                 address = g_malloc0 (total_size);
483         } else {
484                 address = mono_mempool_alloc (table->mp, total_size);
485         }
486
487         address->code_start = jit->code_start;
488         address->code_size = jit->code_size;
489
490         memcpy (&address->data, oldptr, size);
491         if (max_size > BUFSIZ)
492                 g_free (oldptr);
493
494         g_hash_table_insert (table->method_address_hash, method, address);
495
496         mono_debugger_unlock ();
497         return address;
498 }
499
500 void
501 mono_debug_remove_method (MonoMethod *method, MonoDomain *domain)
502 {
503         MonoDebugDataTable *table;
504         MonoDebugMethodAddress *address;
505
506         if (!mono_debug_initialized)
507                 return;
508
509         g_assert (method_is_dynamic (method));
510
511         mono_debugger_lock ();
512
513         table = lookup_data_table (domain);
514
515         address = g_hash_table_lookup (table->method_address_hash, method);
516         if (address)
517                 g_free (address);
518
519         g_hash_table_remove (table->method_address_hash, method);
520
521         mono_debugger_unlock ();
522 }
523
524 void
525 mono_debug_add_delegate_trampoline (gpointer code, int size)
526 {
527 }
528
529 static inline guint32
530 read_leb128 (guint8 *ptr, guint8 **rptr)
531 {
532         guint32 result = 0, shift = 0;
533
534         while (TRUE) {
535                 guint8 byte = *ptr++;
536
537                 result |= (byte & 0x7f) << shift;
538                 if ((byte & 0x80) == 0)
539                         break;
540                 shift += 7;
541         }
542
543         *rptr = ptr;
544         return result;
545 }
546
547 static inline gint32
548 read_sleb128 (guint8 *ptr, guint8 **rptr)
549 {
550         gint32 result = 0;
551         guint32 shift = 0;
552
553         while (TRUE) {
554                 guint8 byte = *ptr++;
555
556                 result |= (byte & 0x7f) << shift;
557                 shift += 7;
558
559                 if (byte & 0x80)
560                         continue;
561
562                 if ((shift < 32) && (byte & 0x40))
563                         result |= - (1 << shift);
564                 break;
565         }
566
567         *rptr = ptr;
568         return result;
569 }
570
571 static void
572 read_variable (MonoDebugVarInfo *var, guint8 *ptr, guint8 **rptr)
573 {
574         var->index = read_leb128 (ptr, &ptr);
575         var->offset = read_sleb128 (ptr, &ptr);
576         var->size = read_leb128 (ptr, &ptr);
577         var->begin_scope = read_leb128 (ptr, &ptr);
578         var->end_scope = read_leb128 (ptr, &ptr);
579         READ_UNALIGNED (gpointer, ptr, var->type);
580         ptr += sizeof (gpointer);
581         *rptr = ptr;
582 }
583
584 void
585 mono_debug_free_method_jit_info (MonoDebugMethodJitInfo *jit)
586 {
587         if (!jit)
588                 return;
589         g_free (jit->line_numbers);
590         g_free (jit->this_var);
591         g_free (jit->params);
592         g_free (jit->locals);
593         g_free (jit->gsharedvt_info_var);
594         g_free (jit->gsharedvt_locals_var);
595         g_free (jit);
596 }
597
598 static MonoDebugMethodJitInfo *
599 mono_debug_read_method (MonoDebugMethodAddress *address)
600 {
601         MonoDebugMethodJitInfo *jit;
602         guint32 i;
603         guint8 *ptr;
604
605         jit = g_new0 (MonoDebugMethodJitInfo, 1);
606         jit->code_start = address->code_start;
607         jit->code_size = address->code_size;
608
609         ptr = (guint8 *) &address->data;
610
611         jit->prologue_end = read_leb128 (ptr, &ptr);
612         jit->epilogue_begin = read_leb128 (ptr, &ptr);
613
614         jit->num_line_numbers = read_leb128 (ptr, &ptr);
615         jit->line_numbers = g_new0 (MonoDebugLineNumberEntry, jit->num_line_numbers);
616         for (i = 0; i < jit->num_line_numbers; i++) {
617                 MonoDebugLineNumberEntry *lne = &jit->line_numbers [i];
618
619                 lne->il_offset = read_sleb128 (ptr, &ptr);
620                 lne->native_offset = read_sleb128 (ptr, &ptr);
621         }
622
623         if (*ptr++) {
624                 jit->this_var = g_new0 (MonoDebugVarInfo, 1);
625                 read_variable (jit->this_var, ptr, &ptr);
626         }
627
628         jit->num_params = read_leb128 (ptr, &ptr);
629         jit->params = g_new0 (MonoDebugVarInfo, jit->num_params);
630         for (i = 0; i < jit->num_params; i++)
631                 read_variable (&jit->params [i], ptr, &ptr);
632
633         jit->num_locals = read_leb128 (ptr, &ptr);
634         jit->locals = g_new0 (MonoDebugVarInfo, jit->num_locals);
635         for (i = 0; i < jit->num_locals; i++)
636                 read_variable (&jit->locals [i], ptr, &ptr);
637
638         if (*ptr++) {
639                 jit->gsharedvt_info_var = g_new0 (MonoDebugVarInfo, 1);
640                 jit->gsharedvt_locals_var = g_new0 (MonoDebugVarInfo, 1);
641                 read_variable (jit->gsharedvt_info_var, ptr, &ptr);
642                 read_variable (jit->gsharedvt_locals_var, ptr, &ptr);
643         }
644
645         return jit;
646 }
647
648 static MonoDebugMethodJitInfo *
649 find_method (MonoMethod *method, MonoDomain *domain)
650 {
651         MonoDebugDataTable *table;
652         MonoDebugMethodAddress *address;
653
654         table = lookup_data_table (domain);
655         address = g_hash_table_lookup (table->method_address_hash, method);
656
657         if (!address)
658                 return NULL;
659
660         return mono_debug_read_method (address);
661 }
662
663 MonoDebugMethodJitInfo *
664 mono_debug_find_method (MonoMethod *method, MonoDomain *domain)
665 {
666         MonoDebugMethodJitInfo *res;
667
668         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
669                 return NULL;
670
671         mono_debugger_lock ();
672         res = find_method (method, domain);
673         mono_debugger_unlock ();
674         return res;
675 }
676
677 MonoDebugMethodAddressList *
678 mono_debug_lookup_method_addresses (MonoMethod *method)
679 {
680         g_assert_not_reached ();
681         return NULL;
682 }
683
684 static gint32
685 il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
686 {
687         MonoDebugMethodJitInfo *jit;
688         int i;
689
690         jit = find_method (method, domain);
691         if (!jit || !jit->line_numbers)
692                 goto cleanup_and_fail;
693
694         for (i = jit->num_line_numbers - 1; i >= 0; i--) {
695                 MonoDebugLineNumberEntry lne = jit->line_numbers [i];
696
697                 if (lne.native_offset <= native_offset) {
698                         mono_debug_free_method_jit_info (jit);
699                         return lne.il_offset;
700                 }
701         }
702
703 cleanup_and_fail:
704         mono_debug_free_method_jit_info (jit);
705         return -1;
706 }
707
708 /**
709  * mono_debug_il_offset_from_address:
710  *
711  *   Compute the IL offset corresponding to NATIVE_OFFSET inside the native
712  * code of METHOD in DOMAIN.
713  */
714 gint32
715 mono_debug_il_offset_from_address (MonoMethod *method, MonoDomain *domain, guint32 native_offset)
716 {
717         gint32 res;
718
719         mono_debugger_lock ();
720
721         res = il_offset_from_address (method, domain, native_offset);
722
723         mono_debugger_unlock ();
724
725         return res;
726 }
727
728 /**
729  * mono_debug_lookup_source_location:
730  * @address: Native offset within the @method's machine code.
731  *
732  * Lookup the source code corresponding to the machine instruction located at
733  * native offset @address within @method.
734  *
735  * The returned `MonoDebugSourceLocation' contains both file / line number
736  * information and the corresponding IL offset.  It must be freed by
737  * mono_debug_free_source_location().
738  */
739 MonoDebugSourceLocation *
740 mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDomain *domain)
741 {
742         MonoDebugMethodInfo *minfo;
743         MonoDebugSourceLocation *location;
744         gint32 offset;
745
746         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
747                 return NULL;
748
749         mono_debugger_lock ();
750         minfo = mono_debug_lookup_method_internal (method);
751         if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
752                 mono_debugger_unlock ();
753                 return NULL;
754         }
755
756         offset = il_offset_from_address (method, domain, address);
757         if (offset < 0) {
758                 mono_debugger_unlock ();
759                 return NULL;
760         }
761
762         location = mono_debug_symfile_lookup_location (minfo, offset);
763         mono_debugger_unlock ();
764         return location;
765 }
766
767 /*
768  * mono_debug_lookup_locals:
769  *
770  *   Return information about the local variables of MINFO.
771  * The result should be freed using mono_debug_symfile_free_locals ().
772  */
773 MonoDebugLocalsInfo*
774 mono_debug_lookup_locals (MonoMethod *method)
775 {
776         MonoDebugMethodInfo *minfo;
777         MonoDebugLocalsInfo *res;
778
779         if (mono_debug_format == MONO_DEBUG_FORMAT_NONE)
780                 return NULL;
781
782         mono_debugger_lock ();
783         minfo = mono_debug_lookup_method_internal (method);
784         if (!minfo || !minfo->handle || !minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile)) {
785                 mono_debugger_unlock ();
786                 return NULL;
787         }
788
789         res = mono_debug_symfile_lookup_locals (minfo);
790         mono_debugger_unlock ();
791
792         return res;
793 }
794
795 /**
796  * mono_debug_free_source_location:
797  * @location: A `MonoDebugSourceLocation'.
798  *
799  * Frees the @location.
800  */
801 void
802 mono_debug_free_source_location (MonoDebugSourceLocation *location)
803 {
804         if (location) {
805                 g_free (location->source_file);
806                 g_free (location);
807         }
808 }
809
810 /**
811  * mono_debug_print_stack_frame:
812  * @native_offset: Native offset within the @method's machine code.
813  *
814  * Conventient wrapper around mono_debug_lookup_source_location() which can be
815  * used if you only want to use the location to print a stack frame.
816  */
817 gchar *
818 mono_debug_print_stack_frame (MonoMethod *method, guint32 native_offset, MonoDomain *domain)
819 {
820         MonoDebugSourceLocation *location;
821         gchar *fname, *ptr, *res;
822         int offset;
823
824         fname = mono_method_full_name (method, TRUE);
825         for (ptr = fname; *ptr; ptr++) {
826                 if (*ptr == ':') *ptr = '.';
827         }
828
829         location = mono_debug_lookup_source_location (method, native_offset, domain);
830
831         if (!location) {
832                 if (mono_debug_initialized) {
833                         mono_debugger_lock ();
834                         offset = il_offset_from_address (method, domain, native_offset);
835                         mono_debugger_unlock ();
836                 } else {
837                         offset = -1;
838                 }
839
840                 if (offset < 0)
841                         res = g_strdup_printf ("at %s <0x%05x>", fname, native_offset);
842                 else
843                         res = g_strdup_printf ("at %s <IL 0x%05x, 0x%05x>", fname, offset, native_offset);
844                 g_free (fname);
845                 return res;
846         }
847
848         res = g_strdup_printf ("at %s [0x%05x] in %s:%d", fname, location->il_offset,
849                                location->source_file, location->row);
850
851         g_free (fname);
852         mono_debug_free_source_location (location);
853         return res;
854 }
855
856 void
857 mono_set_is_debugger_attached (gboolean attached)
858 {
859         is_attached = attached;
860 }
861
862 gboolean
863 mono_is_debugger_attached (void)
864 {
865         return is_attached;
866 }
867
868 /*
869  * Bundles
870  */
871
872 typedef struct _BundledSymfile BundledSymfile;
873
874 struct _BundledSymfile {
875         BundledSymfile *next;
876         const char *aname;
877         const mono_byte *raw_contents;
878         int size;
879 };
880
881 static BundledSymfile *bundled_symfiles = NULL;
882
883 void
884 mono_register_symfile_for_assembly (const char *assembly_name, const mono_byte *raw_contents, int size)
885 {
886         BundledSymfile *bsymfile;
887
888         bsymfile = g_new0 (BundledSymfile, 1);
889         bsymfile->aname = assembly_name;
890         bsymfile->raw_contents = raw_contents;
891         bsymfile->size = size;
892         bsymfile->next = bundled_symfiles;
893         bundled_symfiles = bsymfile;
894 }
895
896 static MonoDebugHandle *
897 open_symfile_from_bundle (MonoImage *image)
898 {
899         BundledSymfile *bsymfile;
900
901         for (bsymfile = bundled_symfiles; bsymfile; bsymfile = bsymfile->next) {
902                 if (strcmp (bsymfile->aname, image->module_name))
903                         continue;
904
905                 return mono_debug_open_image (image, bsymfile->raw_contents, bsymfile->size);
906         }
907
908         return NULL;
909 }
910
911 void
912 mono_debugger_lock (void)
913 {
914         g_assert (initialized);
915         mono_mutex_lock (&debugger_lock_mutex);
916 }
917
918 void
919 mono_debugger_unlock (void)
920 {
921         g_assert (initialized);
922         mono_mutex_unlock (&debugger_lock_mutex);
923 }
924
925 void
926 mono_debugger_initialize ()
927 {
928         mono_mutex_init_recursive (&debugger_lock_mutex);
929         initialized = 1;
930 }
931
932 /**
933  * mono_debug_enabled:
934  *
935  * Returns true is debug information is enabled. This doesn't relate if a debugger is present or not.
936  */
937 mono_bool
938 mono_debug_enabled (void)
939 {
940         return mono_debug_format != MONO_DEBUG_FORMAT_NONE;
941 }