2 * lldb.c: Mono support for LLDB.
5 * Zoltan Varga (vargaz@gmail.com)
7 * Copyright 2016 Xamarin, Inc (http://www.xamarin.com)
13 #include "seq-points.h"
15 #include <mono/metadata/mono-debug.h>
16 #include <mono/metadata/mono-debug-debugger.h>
17 #include <mono/metadata/debug-mono-symfile.h>
18 #include <mono/utils/mono-counters.h>
20 #if !defined(DISABLE_JIT) && !defined(DISABLE_LLDB)
23 ENTRY_CODE_REGION = 1,
26 ENTRY_UNLOAD_CODE_REGION = 4
30 * Need to make sure these structures have the same size and alignment on
34 /* One data packet sent from the runtime to the debugger */
36 /* Pointer to the next entry */
38 /* The type of data pointed to by ADDR */
39 /* One of the ENTRY_ constants */
49 /* (MAJOR << 16) | MINOR */
54 /* List of all entries */
55 /* Keep this as a pointer so accessing it is atomic */
56 DebugEntry *all_entries;
57 /* The current entry embedded here to reduce the amount of roundtrips */
65 * Represents a memory region used for code.
69 * OBJFILE_MAGIC. This is needed to make it easier for lldb to
70 * create object files from this packet.
80 } UnloadCodeRegionEntry;
83 * Represents a managed method
88 /* The id of the codegen region which contains CODE */
93 /* Followed by variable size data */
97 * Represents a trampoline
102 /* The id of the codegen region which contains CODE */
107 /* Followed by variable size data */
110 #define MAJOR_VERSION 1
111 #define MINOR_VERSION 0
113 static const char* OBJFILE_MAGIC = { "MONO_JIT_OBJECT_FILE" };
115 JitDescriptor __mono_jit_debug_descriptor = { (MAJOR_VERSION << 16) | MINOR_VERSION };
117 static gboolean enabled;
118 static int id_generator;
119 static GHashTable *codegen_regions;
120 static DebugEntry *last_entry;
121 static mono_mutex_t mutex;
122 static GHashTable *dyn_codegen_regions;
123 static double register_time;
124 static int num_entries;
126 #define lldb_lock() mono_os_mutex_lock (&mutex)
127 #define lldb_unlock() mono_os_mutex_unlock (&mutex)
129 void MONO_NEVER_INLINE __mono_jit_debug_register_code (void);
131 /* The native debugger puts a breakpoint in this function. */
132 void MONO_NEVER_INLINE
133 __mono_jit_debug_register_code (void)
135 /* Make sure that even compilers that ignore __noinline__ don't inline this */
136 #if defined(__GNUC__)
142 * Functions to encode protocol data
146 guint8 *buf, *p, *end;
150 buffer_init (Buffer *buf, int size)
152 buf->buf = (guint8 *)g_malloc (size);
154 buf->end = buf->buf + size;
158 buffer_len (Buffer *buf)
160 return buf->p - buf->buf;
164 buffer_make_room (Buffer *buf, int size)
166 if (buf->end - buf->p < size) {
167 int new_size = buf->end - buf->buf + size + 32;
168 guint8 *p = (guint8 *)g_realloc (buf->buf, new_size);
169 size = buf->p - buf->buf;
172 buf->end = buf->buf + new_size;
177 buffer_add_byte (Buffer *buf, guint8 val)
179 buffer_make_room (buf, 1);
185 buffer_add_short (Buffer *buf, guint32 val)
187 buffer_make_room (buf, 2);
188 buf->p [0] = (val >> 8) & 0xff;
189 buf->p [1] = (val >> 0) & 0xff;
194 buffer_add_int (Buffer *buf, guint32 val)
196 buffer_make_room (buf, 4);
197 buf->p [0] = (val >> 24) & 0xff;
198 buf->p [1] = (val >> 16) & 0xff;
199 buf->p [2] = (val >> 8) & 0xff;
200 buf->p [3] = (val >> 0) & 0xff;
205 buffer_add_long (Buffer *buf, guint64 l)
207 buffer_add_int (buf, (l >> 32) & 0xffffffff);
208 buffer_add_int (buf, (l >> 0) & 0xffffffff);
212 buffer_add_id (Buffer *buf, int id)
214 buffer_add_int (buf, (guint64)id);
218 buffer_add_data (Buffer *buf, guint8 *data, int len)
220 buffer_make_room (buf, len);
221 memcpy (buf->p, data, len);
226 buffer_add_string (Buffer *buf, const char *str)
231 buffer_add_int (buf, 0);
234 buffer_add_int (buf, len);
235 buffer_add_data (buf, (guint8*)str, len);
240 buffer_add_buffer (Buffer *buf, Buffer *data)
242 buffer_add_data (buf, data->buf, buffer_len (data));
246 buffer_free (Buffer *buf)
253 gpointer region_start;
259 find_code_region (void *data, int csize, int size, void *user_data)
261 UserData *ud = user_data;
263 if ((char*)ud->code >= (char*)data && (char*)ud->code < (char*)data + csize) {
264 ud->region_start = data;
265 ud->region_size = csize;
273 add_entry (EntryType type, Buffer *buf)
277 int size = buffer_len (buf);
279 data = g_malloc (size);
280 memcpy (data, buf->buf, size);
282 entry = g_malloc0 (sizeof (DebugEntry));
284 entry->addr = (guint64)(gsize)data;
287 mono_memory_barrier ();
291 /* The debugger can read the list of entries asynchronously, so this has to be async safe */
292 // FIXME: Make sure this is async safe
294 last_entry->next_addr = (guint64)(gsize) (entry);
298 __mono_jit_debug_descriptor.all_entries = entry;
301 __mono_jit_debug_descriptor.entry = entry;
303 __mono_jit_debug_descriptor.type = entry->type;
304 __mono_jit_debug_descriptor.size = entry->size;
305 __mono_jit_debug_descriptor.addr = entry->addr;
306 mono_memory_barrier ();
308 GTimer *timer = mono_time_track_start ();
309 __mono_jit_debug_register_code ();
310 mono_time_track_end (®ister_time, timer);
312 //printf ("%lf %d %d\n", register_time, num_entries, entry->type);
318 * register_codegen_region:
320 * Register a codegen region with the debugger if needed.
321 * Return a region id.
324 register_codegen_region (gpointer region_start, int region_size, gboolean dynamic)
326 CodeRegionEntry *region_entry;
329 Buffer *buf = &tmp_buf;
337 if (!codegen_regions)
338 codegen_regions = g_hash_table_new (NULL, NULL);
339 id = GPOINTER_TO_INT (g_hash_table_lookup (codegen_regions, region_start));
345 g_hash_table_insert (codegen_regions, region_start, GINT_TO_POINTER (id));
349 buffer_init (buf, 128);
351 region_entry = (CodeRegionEntry*)buf->p;
352 buf->p += sizeof (CodeRegionEntry);
353 memset (region_entry, 0, sizeof (CodeRegionEntry));
354 strcpy (region_entry->magic, OBJFILE_MAGIC);
355 region_entry->id = id;
356 region_entry->start = (gsize)region_start;
357 region_entry->size = (gsize)region_size;
359 add_entry (ENTRY_CODE_REGION, buf);
365 emit_unwind_info (GSList *unwind_ops, Buffer *buf)
371 ret_reg = mono_unwind_get_dwarf_pc_reg ();
372 g_assert (ret_reg < 256);
374 /* We use the unencoded version of the unwind info to make it easier to decode */
376 for (l = unwind_ops; l; l = l->next) {
377 MonoUnwindOp *op = l->data;
379 /* lldb can't handle these */
380 if (op->op == DW_CFA_mono_advance_loc)
385 buffer_add_byte (buf, ret_reg);
386 buffer_add_int (buf, nunwind_ops);
387 for (l = unwind_ops; l; l = l->next) {
388 MonoUnwindOp *op = l->data;
390 if (op->op == DW_CFA_mono_advance_loc)
392 buffer_add_int (buf, op->op);
393 buffer_add_int (buf, op->when);
396 // LLDB doesn't see to use the switched esp/ebp
397 if (op->reg == X86_ESP)
399 else if (op->reg == X86_EBP)
402 dreg = mono_hw_reg_to_dwarf_reg (op->reg);
404 dreg = mono_hw_reg_to_dwarf_reg (op->reg);
406 buffer_add_int (buf, dreg);
407 buffer_add_int (buf, op->val);
412 mono_lldb_init (const char *options)
415 mono_os_mutex_init_recursive (&mutex);
417 mono_counters_register ("Time spent in LLDB", MONO_COUNTER_JIT | MONO_COUNTER_DOUBLE, ®ister_time);
427 compare_by_addr (const void *arg1, const void *arg2)
429 const FullSeqPoint *sp1 = arg1;
430 const FullSeqPoint *sp2 = arg2;
432 return sp1->native_offset - sp2->native_offset;
436 mono_lldb_save_method_info (MonoCompile *cfg)
442 Buffer *buf = &tmpbuf;
443 MonoDebugMethodInfo *minfo;
444 int i, j, n_il_offsets;
446 GPtrArray *source_file_list;
447 MonoSymSeqPoint *sym_seq_points;
453 /* Find the codegen region which contains the code */
454 memset (&udata, 0, sizeof (udata));
455 udata.code = cfg->native_code;
456 if (cfg->method->dynamic) {
457 mono_code_manager_foreach (cfg->dynamic_info->code_mp, find_code_region, &udata);
458 g_assert (udata.found);
460 region_id = register_codegen_region (udata.region_start, udata.region_size, TRUE);
463 if (!dyn_codegen_regions)
464 dyn_codegen_regions = g_hash_table_new (NULL, NULL);
465 g_hash_table_insert (dyn_codegen_regions, cfg->method, GINT_TO_POINTER (region_id));
468 mono_domain_code_foreach (cfg->domain, find_code_region, &udata);
469 g_assert (udata.found);
471 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
474 buffer_init (buf, 256);
476 entry = (MethodEntry*)buf->p;
477 buf->p += sizeof (MethodEntry);
478 entry->id = ++id_generator;
479 entry->region_id = region_id;
480 entry->code = (gsize)cfg->native_code;
481 entry->code_size = cfg->code_size;
483 emit_unwind_info (cfg->unwind_ops, buf);
485 char *s = mono_method_full_name (cfg->method, TRUE);
486 buffer_add_string (buf, s);
489 minfo = mono_debug_lookup_method (cfg->method);
490 MonoSeqPointInfo *seq_points = cfg->seq_point_info;
491 if (minfo && seq_points) {
492 mono_debug_get_seq_points (minfo, NULL, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
493 buffer_add_int (buf, source_file_list->len);
494 for (i = 0; i < source_file_list->len; ++i) {
495 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
496 buffer_add_string (buf, sinfo->source_file);
497 for (j = 0; j < 16; ++j)
498 buffer_add_byte (buf, sinfo->hash [j]);
501 // The sym seq points are ordered by il offset, need to order them by address
503 locs = g_new0 (FullSeqPoint, n_il_offsets);
504 for (i = 0; i < n_il_offsets; ++i) {
505 locs [i].sp = sym_seq_points [i];
509 if (mono_seq_point_find_by_il_offset (seq_points, sym_seq_points [i].il_offset, &seq_point)) {
510 locs [i].native_offset = seq_point.native_offset;
512 locs [i].native_offset = 0xffffff;
516 qsort (locs, n_il_offsets, sizeof (FullSeqPoint), compare_by_addr);
518 n_il_offsets -= skipped;
519 buffer_add_int (buf, n_il_offsets);
520 for (i = 0; i < n_il_offsets; ++i) {
521 MonoSymSeqPoint *sp = &locs [i].sp;
522 const char *srcfile = "";
524 if (source_files [i] != -1) {
525 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
526 srcfile = sinfo->source_file;
529 //printf ("%s %x %d %d\n", cfg->method->name, locs [i].native_offset, sp->il_offset, sp->line);
530 buffer_add_int (buf, locs [i].native_offset);
531 buffer_add_int (buf, sp->il_offset);
532 buffer_add_int (buf, sp->line);
533 buffer_add_int (buf, source_files [i]);
534 buffer_add_int (buf, sp->column);
535 buffer_add_int (buf, sp->end_line);
536 buffer_add_int (buf, sp->end_column);
539 g_free (source_files);
540 g_free (sym_seq_points);
541 g_ptr_array_free (source_file_list, TRUE);
543 buffer_add_int (buf, 0);
544 buffer_add_int (buf, 0);
547 add_entry (ENTRY_METHOD, buf);
552 mono_lldb_remove_method (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *info)
555 UnloadCodeRegionEntry *entry;
557 Buffer *buf = &tmpbuf;
562 g_assert (method->dynamic);
565 region_id = GPOINTER_TO_INT (g_hash_table_lookup (dyn_codegen_regions, method));
566 g_hash_table_remove (dyn_codegen_regions, method);
569 buffer_init (buf, 256);
571 entry = (UnloadCodeRegionEntry*)buf->p;
572 buf->p += sizeof (UnloadCodeRegionEntry);
573 entry->id = region_id;
575 add_entry (ENTRY_UNLOAD_CODE_REGION, buf);
578 /* The method is associated with the code region, so it doesn't have to be unloaded */
582 mono_lldb_save_trampoline_info (MonoTrampInfo *info)
584 TrampolineEntry *entry;
588 Buffer *buf = &tmpbuf;
593 /* Find the codegen region which contains the code */
594 memset (&udata, 0, sizeof (udata));
595 udata.code = info->code;
596 mono_global_codeman_foreach (find_code_region, &udata);
598 mono_domain_code_foreach (mono_get_root_domain (), find_code_region, &udata);
599 g_assert (udata.found);
601 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
603 buffer_init (buf, 1024);
605 entry = (TrampolineEntry*)buf->p;
606 buf->p += sizeof (TrampolineEntry);
607 entry->id = ++id_generator;
608 entry->region_id = region_id;
609 entry->code = (gsize)info->code;
610 entry->code_size = info->code_size;
612 emit_unwind_info (info->unwind_ops, buf);
614 buffer_add_string (buf, info->name);
616 add_entry (ENTRY_TRAMPOLINE, buf);
621 mono_lldb_save_specific_trampoline_info (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, gpointer code, guint32 code_len)
624 * Avoid emitting these for now,
625 * they slow down execution too much, and they are
626 * only needed during single stepping which doesn't
630 TrampolineEntry *entry;
634 Buffer *buf = &tmpbuf;
639 /* Find the codegen region which contains the code */
640 memset (&udata, 0, sizeof (udata));
642 mono_global_codeman_foreach (find_code_region, &udata);
644 mono_domain_code_foreach (mono_get_root_domain (), find_code_region, &udata);
645 g_assert (udata.found);
647 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
649 buffer_init (buf, 1024);
651 entry = (TrampolineEntry*)buf->p;
652 buf->p += sizeof (TrampolineEntry);
653 entry->id = ++id_generator;
654 entry->region_id = region_id;
655 entry->code = (gsize)code;
656 entry->code_size = code_len;
658 GSList *unwind_ops = mono_unwind_get_cie_program ();
659 emit_unwind_info (unwind_ops, buf);
661 buffer_add_string (buf, "");
663 add_entry (ENTRY_TRAMPOLINE, buf);
672 Similar to the gdb jit interface. The runtime communicates with a plugin running inside lldb.
673 - The runtime allocates a data packet, points a symbol with a well known name at it.
674 - It calls a dummy function with a well known name.
675 - The plugin sets a breakpoint at this function, causing the runtime to be suspended.
676 - The plugin reads the data pointed to by the other symbol and processes it.
678 The data packets are kept in a list, so lldb can read all of them after attaching.
679 Lldb will associate an object file with each mono codegen region.
682 - use a flat byte array so the whole data can be read in one operation.
683 - use 64 bit ints for pointers.
689 mono_lldb_init (const char *options)
691 g_error ("lldb support has been disabled at configure time.");
695 mono_lldb_save_method_info (MonoCompile *cfg)
700 mono_lldb_save_trampoline_info (MonoTrampInfo *info)
705 mono_lldb_remove_method (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *info)
710 mono_lldb_save_specific_trampoline_info (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, gpointer code, guint32 code_len)