[interp] Make newarr lockfree
[mono-project.git] / mono / mini / lldb.c
blob4b10681889c7208ddd5064f9e1c4f2ec11ebefde
1 /**
2 * \file
3 * Mono support for LLDB.
5 * Author:
6 * Zoltan Varga (vargaz@gmail.com)
8 * Copyright 2016 Xamarin, Inc (http://www.xamarin.com)
9 */
11 #include "config.h"
12 #include "mini.h"
13 #include "lldb.h"
14 #include "seq-points.h"
16 #include <mono/metadata/debug-internals.h>
17 #include <mono/utils/mono-counters.h>
19 #if !defined(DISABLE_JIT) && !defined(DISABLE_LLDB)
21 typedef enum {
22 ENTRY_CODE_REGION = 1,
23 ENTRY_METHOD = 2,
24 ENTRY_TRAMPOLINE = 3,
25 ENTRY_UNLOAD_CODE_REGION = 4
26 } EntryType;
29 * Need to make sure these structures have the same size and alignment on
30 * all platforms.
33 /* One data packet sent from the runtime to the debugger */
34 typedef struct {
35 /* Pointer to the next entry */
36 guint64 next_addr;
37 /* The type of data pointed to by ADDR */
38 /* One of the ENTRY_ constants */
39 guint32 type;
40 /* Align */
41 guint32 dummy;
42 guint64 size;
43 guint64 addr;
44 } DebugEntry;
46 typedef struct
48 /* (MAJOR << 16) | MINOR */
49 guint32 version;
50 /* Align */
51 guint32 dummy;
52 DebugEntry *entry;
53 /* List of all entries */
54 /* Keep this as a pointer so accessing it is atomic */
55 DebugEntry *all_entries;
56 /* The current entry embedded here to reduce the amount of roundtrips */
57 guint32 type;
58 guint32 dummy2;
59 guint64 size;
60 guint64 addr;
61 } JitDescriptor;
64 * Represents a memory region used for code.
66 typedef struct {
68 * OBJFILE_MAGIC. This is needed to make it easier for lldb to
69 * create object files from this packet.
71 char magic [32];
72 guint64 start;
73 guint32 size;
74 int id;
75 } CodeRegionEntry;
77 typedef struct {
78 int id;
79 } UnloadCodeRegionEntry;
82 * Represents a managed method
84 typedef struct {
85 guint64 code;
86 int id;
87 /* The id of the codegen region which contains CODE */
88 int region_id;
89 int code_size;
90 /* Align */
91 guint32 dummy;
92 /* Followed by variable size data */
93 } MethodEntry;
96 * Represents a trampoline
98 typedef struct {
99 guint64 code;
100 int id;
101 /* The id of the codegen region which contains CODE */
102 int region_id;
103 int code_size;
104 /* Align */
105 guint32 dummy;
106 /* Followed by variable size data */
107 } TrampolineEntry;
109 #define MAJOR_VERSION 1
110 #define MINOR_VERSION 0
112 static const char* OBJFILE_MAGIC = { "MONO_JIT_OBJECT_FILE" };
114 JitDescriptor __mono_jit_debug_descriptor = { (MAJOR_VERSION << 16) | MINOR_VERSION };
116 static gboolean enabled;
117 static int id_generator;
118 static GHashTable *codegen_regions;
119 static DebugEntry *last_entry;
120 static mono_mutex_t mutex;
121 static GHashTable *dyn_codegen_regions;
122 static gint64 register_time;
123 static int num_entries;
125 #define lldb_lock() mono_os_mutex_lock (&mutex)
126 #define lldb_unlock() mono_os_mutex_unlock (&mutex)
128 G_BEGIN_DECLS
130 void MONO_NEVER_INLINE __mono_jit_debug_register_code (void);
132 /* The native debugger puts a breakpoint in this function. */
133 void MONO_NEVER_INLINE
134 __mono_jit_debug_register_code (void)
136 /* Make sure that even compilers that ignore __noinline__ don't inline this */
137 #if defined(__GNUC__)
138 asm ("");
139 #endif
142 G_END_DECLS
145 * Functions to encode protocol data
148 typedef struct {
149 guint8 *buf, *p, *end;
150 } Buffer;
152 static inline void
153 buffer_init (Buffer *buf, int size)
155 buf->buf = (guint8 *)g_malloc (size);
156 buf->p = buf->buf;
157 buf->end = buf->buf + size;
160 static inline int
161 buffer_len (Buffer *buf)
163 return buf->p - buf->buf;
166 static inline void
167 buffer_make_room (Buffer *buf, int size)
169 if (buf->end - buf->p < size) {
170 int new_size = buf->end - buf->buf + size + 32;
171 guint8 *p = (guint8 *)g_realloc (buf->buf, new_size);
172 size = buf->p - buf->buf;
173 buf->buf = p;
174 buf->p = p + size;
175 buf->end = buf->buf + new_size;
179 static inline void
180 buffer_add_byte (Buffer *buf, guint8 val)
182 buffer_make_room (buf, 1);
183 buf->p [0] = val;
184 buf->p++;
187 static inline void
188 buffer_add_short (Buffer *buf, guint32 val)
190 buffer_make_room (buf, 2);
191 buf->p [0] = (val >> 8) & 0xff;
192 buf->p [1] = (val >> 0) & 0xff;
193 buf->p += 2;
196 static inline void
197 buffer_add_int (Buffer *buf, guint32 val)
199 buffer_make_room (buf, 4);
200 buf->p [0] = (val >> 24) & 0xff;
201 buf->p [1] = (val >> 16) & 0xff;
202 buf->p [2] = (val >> 8) & 0xff;
203 buf->p [3] = (val >> 0) & 0xff;
204 buf->p += 4;
207 static inline void
208 buffer_add_long (Buffer *buf, guint64 l)
210 buffer_add_int (buf, (l >> 32) & 0xffffffff);
211 buffer_add_int (buf, (l >> 0) & 0xffffffff);
214 static inline void
215 buffer_add_id (Buffer *buf, int id)
217 buffer_add_int (buf, (guint64)id);
220 static inline void
221 buffer_add_data (Buffer *buf, guint8 *data, int len)
223 buffer_make_room (buf, len);
224 memcpy (buf->p, data, len);
225 buf->p += len;
228 static inline void
229 buffer_add_string (Buffer *buf, const char *str)
231 int len;
233 if (str == NULL) {
234 buffer_add_int (buf, 0);
235 } else {
236 len = strlen (str);
237 buffer_add_int (buf, len);
238 buffer_add_data (buf, (guint8*)str, len);
242 static inline void
243 buffer_add_buffer (Buffer *buf, Buffer *data)
245 buffer_add_data (buf, data->buf, buffer_len (data));
248 static inline void
249 buffer_free (Buffer *buf)
251 g_free (buf->buf);
254 typedef struct {
255 gpointer code;
256 gpointer region_start;
257 guint32 region_size;
258 gboolean found;
259 } UserData;
261 static int
262 find_code_region (void *data, int csize, int size, void *user_data)
264 UserData *ud = (UserData*)user_data;
266 if ((char*)ud->code >= (char*)data && (char*)ud->code < (char*)data + csize) {
267 ud->region_start = data;
268 ud->region_size = csize;
269 ud->found = TRUE;
270 return 1;
272 return 0;
275 static void
276 add_entry (EntryType type, Buffer *buf)
278 DebugEntry *entry;
279 guint8 *data;
280 int size = buffer_len (buf);
282 data = g_malloc (size);
283 memcpy (data, buf->buf, size);
285 entry = g_malloc0 (sizeof (DebugEntry));
286 entry->type = type;
287 entry->addr = (guint64)(gsize)data;
288 entry->size = size;
290 mono_memory_barrier ();
292 lldb_lock ();
294 /* The debugger can read the list of entries asynchronously, so this has to be async safe */
295 // FIXME: Make sure this is async safe
296 if (last_entry) {
297 last_entry->next_addr = (guint64)(gsize) (entry);
298 last_entry = entry;
299 } else {
300 last_entry = entry;
301 __mono_jit_debug_descriptor.all_entries = entry;
304 __mono_jit_debug_descriptor.entry = entry;
306 __mono_jit_debug_descriptor.type = entry->type;
307 __mono_jit_debug_descriptor.size = entry->size;
308 __mono_jit_debug_descriptor.addr = entry->addr;
309 mono_memory_barrier ();
311 gint64 start = mono_time_track_start ();
312 __mono_jit_debug_register_code ();
313 mono_time_track_end (&register_time, start);
314 num_entries ++;
315 //printf ("%lf %d %d\n", register_time, num_entries, entry->type);
317 lldb_unlock ();
321 * register_codegen_region:
323 * Register a codegen region with the debugger if needed.
324 * Return a region id.
326 static int
327 register_codegen_region (gpointer region_start, int region_size, gboolean dynamic)
329 CodeRegionEntry *region_entry;
330 int id;
331 Buffer tmp_buf;
332 Buffer *buf = &tmp_buf;
334 if (dynamic) {
335 lldb_lock ();
336 id = ++id_generator;
337 lldb_unlock ();
338 } else {
339 lldb_lock ();
340 if (!codegen_regions)
341 codegen_regions = g_hash_table_new (NULL, NULL);
342 id = GPOINTER_TO_INT (g_hash_table_lookup (codegen_regions, region_start));
343 if (id) {
344 lldb_unlock ();
345 return id;
347 id = ++id_generator;
348 g_hash_table_insert (codegen_regions, region_start, GINT_TO_POINTER (id));
349 lldb_unlock ();
352 buffer_init (buf, 128);
354 region_entry = (CodeRegionEntry*)buf->p;
355 buf->p += sizeof (CodeRegionEntry);
356 memset (region_entry, 0, sizeof (CodeRegionEntry));
357 strcpy (region_entry->magic, OBJFILE_MAGIC);
358 region_entry->id = id;
359 region_entry->start = (gsize)region_start;
360 region_entry->size = (gsize)region_size;
362 add_entry (ENTRY_CODE_REGION, buf);
363 buffer_free (buf);
364 return id;
367 static void
368 emit_unwind_info (GSList *unwind_ops, Buffer *buf)
370 int ret_reg;
371 int nunwind_ops;
372 GSList *l;
374 ret_reg = mono_unwind_get_dwarf_pc_reg ();
375 g_assert (ret_reg < 256);
377 /* We use the unencoded version of the unwind info to make it easier to decode */
378 nunwind_ops = 0;
379 for (l = unwind_ops; l; l = l->next) {
380 MonoUnwindOp *op = (MonoUnwindOp*)l->data;
382 /* lldb can't handle these */
383 if (op->op == DW_CFA_mono_advance_loc)
384 break;
385 nunwind_ops ++;
388 buffer_add_byte (buf, ret_reg);
389 buffer_add_int (buf, nunwind_ops);
390 for (l = unwind_ops; l; l = l->next) {
391 MonoUnwindOp *op = (MonoUnwindOp*)l->data;
393 if (op->op == DW_CFA_mono_advance_loc)
394 break;
395 buffer_add_int (buf, op->op);
396 buffer_add_int (buf, op->when);
397 int dreg;
398 #if TARGET_X86
399 // LLDB doesn't see to use the switched esp/ebp
400 if (op->reg == X86_ESP)
401 dreg = X86_ESP;
402 else if (op->reg == X86_EBP)
403 dreg = X86_EBP;
404 else
405 dreg = mono_hw_reg_to_dwarf_reg (op->reg);
406 #else
407 dreg = mono_hw_reg_to_dwarf_reg (op->reg);
408 #endif
409 buffer_add_int (buf, dreg);
410 buffer_add_int (buf, op->val);
414 void
415 mono_lldb_init (const char *options)
417 enabled = TRUE;
418 mono_os_mutex_init_recursive (&mutex);
420 mono_counters_register ("Time spent in LLDB", MONO_COUNTER_JIT | MONO_COUNTER_LONG | MONO_COUNTER_TIME, &register_time);
423 typedef struct
425 MonoSymSeqPoint sp;
426 int native_offset;
427 } FullSeqPoint;
429 static int
430 compare_by_addr (const void *arg1, const void *arg2)
432 const FullSeqPoint *sp1 = (const FullSeqPoint *)arg1;
433 const FullSeqPoint *sp2 = (const FullSeqPoint *)arg2;
435 return sp1->native_offset - sp2->native_offset;
438 void
439 mono_lldb_save_method_info (MonoCompile *cfg)
441 MethodEntry *entry;
442 UserData udata;
443 int region_id;
444 Buffer tmpbuf;
445 Buffer *buf = &tmpbuf;
446 MonoDebugMethodInfo *minfo;
447 int i, j, n_il_offsets;
448 int *source_files;
449 GPtrArray *source_file_list;
450 MonoSymSeqPoint *sym_seq_points;
451 FullSeqPoint *locs;
453 if (!enabled)
454 return;
456 /* Find the codegen region which contains the code */
457 memset (&udata, 0, sizeof (udata));
458 udata.code = cfg->native_code;
459 if (cfg->method->dynamic) {
460 mono_code_manager_foreach (cfg->dynamic_info->code_mp, find_code_region, &udata);
461 g_assert (udata.found);
463 region_id = register_codegen_region (udata.region_start, udata.region_size, TRUE);
465 lldb_lock ();
466 if (!dyn_codegen_regions)
467 dyn_codegen_regions = g_hash_table_new (NULL, NULL);
468 g_hash_table_insert (dyn_codegen_regions, cfg->method, GINT_TO_POINTER (region_id));
469 lldb_unlock ();
470 } else {
471 mono_domain_code_foreach (cfg->domain, find_code_region, &udata);
472 g_assert (udata.found);
474 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
477 buffer_init (buf, 256);
479 entry = (MethodEntry*)buf->p;
480 buf->p += sizeof (MethodEntry);
481 entry->id = ++id_generator;
482 entry->region_id = region_id;
483 entry->code = (gsize)cfg->native_code;
484 entry->code_size = cfg->code_size;
486 emit_unwind_info (cfg->unwind_ops, buf);
488 char *s = mono_method_full_name (cfg->method, TRUE);
489 buffer_add_string (buf, s);
490 g_free (s);
492 minfo = mono_debug_lookup_method (cfg->method);
493 MonoSeqPointInfo *seq_points = cfg->seq_point_info;
494 if (minfo && seq_points) {
495 mono_debug_get_seq_points (minfo, NULL, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
496 buffer_add_int (buf, source_file_list->len);
497 for (i = 0; i < source_file_list->len; ++i) {
498 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
499 buffer_add_string (buf, sinfo->source_file);
500 for (j = 0; j < 16; ++j)
501 buffer_add_byte (buf, sinfo->hash [j]);
504 // The sym seq points are ordered by il offset, need to order them by address
505 int skipped = 0;
506 locs = g_new0 (FullSeqPoint, n_il_offsets);
507 for (i = 0; i < n_il_offsets; ++i) {
508 locs [i].sp = sym_seq_points [i];
510 // FIXME: O(n^2)
511 SeqPoint seq_point;
512 if (mono_seq_point_find_by_il_offset (seq_points, sym_seq_points [i].il_offset, &seq_point)) {
513 locs [i].native_offset = seq_point.native_offset;
514 } else {
515 locs [i].native_offset = 0xffffff;
516 skipped ++;
519 qsort (locs, n_il_offsets, sizeof (FullSeqPoint), compare_by_addr);
521 n_il_offsets -= skipped;
522 buffer_add_int (buf, n_il_offsets);
523 for (i = 0; i < n_il_offsets; ++i) {
524 MonoSymSeqPoint *sp = &locs [i].sp;
526 //printf ("%s %x %d %d\n", cfg->method->name, locs [i].native_offset, sp->il_offset, sp->line);
527 buffer_add_int (buf, locs [i].native_offset);
528 buffer_add_int (buf, sp->il_offset);
529 buffer_add_int (buf, sp->line);
530 buffer_add_int (buf, source_files [i]);
531 buffer_add_int (buf, sp->column);
532 buffer_add_int (buf, sp->end_line);
533 buffer_add_int (buf, sp->end_column);
535 g_free (locs);
536 g_free (source_files);
537 g_free (sym_seq_points);
538 g_ptr_array_free (source_file_list, TRUE);
539 } else {
540 buffer_add_int (buf, 0);
541 buffer_add_int (buf, 0);
544 add_entry (ENTRY_METHOD, buf);
545 buffer_free (buf);
548 void
549 mono_lldb_remove_method (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *info)
551 int region_id;
552 UnloadCodeRegionEntry *entry;
553 Buffer tmpbuf;
554 Buffer *buf = &tmpbuf;
556 if (!enabled)
557 return;
559 g_assert (method->dynamic);
561 lldb_lock ();
562 region_id = GPOINTER_TO_INT (g_hash_table_lookup (dyn_codegen_regions, method));
563 g_hash_table_remove (dyn_codegen_regions, method);
564 lldb_unlock ();
566 buffer_init (buf, 256);
568 entry = (UnloadCodeRegionEntry*)buf->p;
569 buf->p += sizeof (UnloadCodeRegionEntry);
570 entry->id = region_id;
572 add_entry (ENTRY_UNLOAD_CODE_REGION, buf);
573 buffer_free (buf);
575 /* The method is associated with the code region, so it doesn't have to be unloaded */
578 void
579 mono_lldb_save_trampoline_info (MonoTrampInfo *info)
581 TrampolineEntry *entry;
582 UserData udata;
583 int region_id;
584 Buffer tmpbuf;
585 Buffer *buf = &tmpbuf;
587 if (!enabled)
588 return;
590 /* Find the codegen region which contains the code */
591 memset (&udata, 0, sizeof (udata));
592 udata.code = info->code;
593 mono_global_codeman_foreach (find_code_region, &udata);
594 if (!udata.found)
595 mono_domain_code_foreach (mono_get_root_domain (), find_code_region, &udata);
596 if (!udata.found)
597 /* Can happen with AOT */
598 return;
600 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
602 buffer_init (buf, 1024);
604 entry = (TrampolineEntry*)buf->p;
605 buf->p += sizeof (TrampolineEntry);
606 entry->id = ++id_generator;
607 entry->region_id = region_id;
608 entry->code = (gsize)info->code;
609 entry->code_size = info->code_size;
611 emit_unwind_info (info->unwind_ops, buf);
613 buffer_add_string (buf, info->name);
615 add_entry (ENTRY_TRAMPOLINE, buf);
616 buffer_free (buf);
619 void
620 mono_lldb_save_specific_trampoline_info (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, gpointer code, guint32 code_len)
623 * Avoid emitting these for now,
624 * they slow down execution too much, and they are
625 * only needed during single stepping which doesn't
626 * work anyway.
628 #if 0
629 TrampolineEntry *entry;
630 UserData udata;
631 int region_id;
632 Buffer tmpbuf;
633 Buffer *buf = &tmpbuf;
635 if (!enabled)
636 return;
638 /* Find the codegen region which contains the code */
639 memset (&udata, 0, sizeof (udata));
640 udata.code = code;
641 mono_global_codeman_foreach (find_code_region, &udata);
642 if (!udata.found)
643 mono_domain_code_foreach (mono_get_root_domain (), find_code_region, &udata);
644 g_assert (udata.found);
646 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
648 buffer_init (buf, 1024);
650 entry = (TrampolineEntry*)buf->p;
651 buf->p += sizeof (TrampolineEntry);
652 entry->id = ++id_generator;
653 entry->region_id = region_id;
654 entry->code = (gsize)code;
655 entry->code_size = code_len;
657 GSList *unwind_ops = mono_unwind_get_cie_program ();
658 emit_unwind_info (unwind_ops, buf);
660 buffer_add_string (buf, "");
662 add_entry (ENTRY_TRAMPOLINE, buf);
663 buffer_free (buf);
664 #endif
668 DESIGN:
670 Communication:
671 Similar to the gdb jit interface. The runtime communicates with a plugin running inside lldb.
672 - The runtime allocates a data packet, points a symbol with a well known name at it.
673 - It calls a dummy function with a well known name.
674 - The plugin sets a breakpoint at this function, causing the runtime to be suspended.
675 - The plugin reads the data pointed to by the other symbol and processes it.
677 The data packets are kept in a list, so lldb can read all of them after attaching.
678 Lldb will associate an object file with each mono codegen region.
680 Packet design:
681 - use a flat byte array so the whole data can be read in one operation.
682 - use 64 bit ints for pointers.
685 #else
687 void
688 mono_lldb_init (const char *options)
690 g_error ("lldb support has been disabled at configure time.");
693 void
694 mono_lldb_save_method_info (MonoCompile *cfg)
698 void
699 mono_lldb_save_trampoline_info (MonoTrampInfo *info)
703 void
704 mono_lldb_remove_method (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *info)
708 void
709 mono_lldb_save_specific_trampoline_info (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, gpointer code, guint32 code_len)
713 #endif