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