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