Merge pull request #4224 from akoeplinger/fix-46602
[mono.git] / mono / mini / lldb.c
1 /*
2  * lldb.c: Mono support for LLDB.
3  *
4  * Author:
5  *   Zoltan Varga (vargaz@gmail.com)
6  *
7  * Copyright 2016 Xamarin, Inc (http://www.xamarin.com)
8  */
9
10 #include "config.h"
11 #include "mini.h"
12 #include "lldb.h"
13 #include "seq-points.h"
14
15 #include <mono/metadata/mono-debug.h>
16 #include <mono/metadata/mono-debug-debugger.h>
17 #include <mono/metadata/debug-mono-symfile.h>
18
19 #if !defined(DISABLE_JIT) && !defined(DISABLE_LLDB)
20
21 typedef enum {
22         ENTRY_CODE_REGION = 1,
23         ENTRY_METHOD = 2,
24         ENTRY_TRAMPOLINE = 3,
25         ENTRY_UNLOAD_CODE_REGION = 4
26 } EntryType;
27
28 /*
29  * Need to make sure these structures have the same size and alignment on
30  * all platforms.
31  */
32
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;
45
46 typedef struct
47 {
48         /* (MAJOR << 16) | MINOR */
49         guint32 version;
50         /* Align */
51         guint32 dummy;
52         /* Keep these as pointers so accessing them is atomic */
53         DebugEntry *entry;
54         /* List of all entries */
55         DebugEntry *all_entries;
56 } JitDescriptor;
57
58 /*
59  * Represents a memory region used for code.
60  */
61 typedef struct {
62         /*
63          * OBJFILE_MAGIC. This is needed to make it easier for lldb to
64          * create object files from this packet.
65          */
66         char magic [32];
67         guint64 start;
68         guint32 size;
69         int id;
70 } CodeRegionEntry;
71
72 typedef struct {
73         int id;
74 } UnloadCodeRegionEntry;
75
76 /*
77  * Represents a managed method
78  */
79 typedef struct {
80         guint64 code;
81         int id;
82         /* The id of the codegen region which contains CODE */
83         int region_id;
84         int code_size;
85         /* Align */
86         guint32 dummy;
87         /* Followed by variable size data */
88 } MethodEntry;
89
90 /*
91  * Represents a trampoline
92  */
93 typedef struct {
94         guint64 code;
95         int id;
96         /* The id of the codegen region which contains CODE */
97         int region_id;
98         int code_size;
99         /* Align */
100         guint32 dummy;
101         /* Followed by variable size data */
102 } TrampolineEntry;
103
104 #define MAJOR_VERSION 1
105 #define MINOR_VERSION 0
106
107 static const char* OBJFILE_MAGIC = { "MONO_JIT_OBJECT_FILE" };
108
109 JitDescriptor __mono_jit_debug_descriptor = { (MAJOR_VERSION << 16) | MINOR_VERSION };
110
111 static gboolean enabled;
112 static int id_generator;
113 static GHashTable *codegen_regions;
114 static DebugEntry *last_entry;
115 static mono_mutex_t mutex;
116 static GHashTable *dyn_codegen_regions;
117
118 #define lldb_lock() mono_os_mutex_lock (&mutex)
119 #define lldb_unlock() mono_os_mutex_unlock (&mutex)
120
121 void MONO_NEVER_INLINE __mono_jit_debug_register_code (void);
122
123 /* The native debugger puts a breakpoint in this function. */
124 void MONO_NEVER_INLINE
125 __mono_jit_debug_register_code (void)
126 {
127         /* Make sure that even compilers that ignore __noinline__ don't inline this */
128 #if defined(__GNUC__)
129         asm ("");
130 #endif
131 }
132
133 /*
134  * Functions to encode protocol data
135  */
136
137 typedef struct {
138         guint8 *buf, *p, *end;
139 } Buffer;
140
141 static inline void
142 buffer_init (Buffer *buf, int size)
143 {
144         buf->buf = (guint8 *)g_malloc (size);
145         buf->p = buf->buf;
146         buf->end = buf->buf + size;
147 }
148
149 static inline int
150 buffer_len (Buffer *buf)
151 {
152         return buf->p - buf->buf;
153 }
154
155 static inline void
156 buffer_make_room (Buffer *buf, int size)
157 {
158         if (buf->end - buf->p < size) {
159                 int new_size = buf->end - buf->buf + size + 32;
160                 guint8 *p = (guint8 *)g_realloc (buf->buf, new_size);
161                 size = buf->p - buf->buf;
162                 buf->buf = p;
163                 buf->p = p + size;
164                 buf->end = buf->buf + new_size;
165         }
166 }
167
168 static inline void
169 buffer_add_byte (Buffer *buf, guint8 val)
170 {
171         buffer_make_room (buf, 1);
172         buf->p [0] = val;
173         buf->p++;
174 }
175
176 static inline void
177 buffer_add_short (Buffer *buf, guint32 val)
178 {
179         buffer_make_room (buf, 2);
180         buf->p [0] = (val >> 8) & 0xff;
181         buf->p [1] = (val >> 0) & 0xff;
182         buf->p += 2;
183 }
184
185 static inline void
186 buffer_add_int (Buffer *buf, guint32 val)
187 {
188         buffer_make_room (buf, 4);
189         buf->p [0] = (val >> 24) & 0xff;
190         buf->p [1] = (val >> 16) & 0xff;
191         buf->p [2] = (val >> 8) & 0xff;
192         buf->p [3] = (val >> 0) & 0xff;
193         buf->p += 4;
194 }
195
196 static inline void
197 buffer_add_long (Buffer *buf, guint64 l)
198 {
199         buffer_add_int (buf, (l >> 32) & 0xffffffff);
200         buffer_add_int (buf, (l >> 0) & 0xffffffff);
201 }
202
203 static inline void
204 buffer_add_id (Buffer *buf, int id)
205 {
206         buffer_add_int (buf, (guint64)id);
207 }
208
209 static inline void
210 buffer_add_data (Buffer *buf, guint8 *data, int len)
211 {
212         buffer_make_room (buf, len);
213         memcpy (buf->p, data, len);
214         buf->p += len;
215 }
216
217 static inline void
218 buffer_add_string (Buffer *buf, const char *str)
219 {
220         int len;
221
222         if (str == NULL) {
223                 buffer_add_int (buf, 0);
224         } else {
225                 len = strlen (str);
226                 buffer_add_int (buf, len);
227                 buffer_add_data (buf, (guint8*)str, len);
228         }
229 }
230
231 static inline void
232 buffer_add_buffer (Buffer *buf, Buffer *data)
233 {
234         buffer_add_data (buf, data->buf, buffer_len (data));
235 }
236
237 static inline void
238 buffer_free (Buffer *buf)
239 {
240         g_free (buf->buf);
241 }
242
243 typedef struct {
244         gpointer code;
245         gpointer region_start;
246         guint32 region_size;
247         gboolean found;
248 } UserData;
249
250 static int
251 find_code_region (void *data, int csize, int size, void *user_data)
252 {
253         UserData *ud = user_data;
254
255         if ((char*)ud->code >= (char*)data && (char*)ud->code < (char*)data + csize) {
256                 ud->region_start = data;
257                 ud->region_size = csize;
258                 ud->found = TRUE;
259                 return 1;
260         }
261         return 0;
262 }
263
264 static void
265 add_entry (EntryType type, Buffer *buf)
266 {
267         DebugEntry *entry;
268         guint8 *data;
269         int size = buffer_len (buf);
270
271         data = g_malloc (size);
272         memcpy (data, buf->buf, size);
273
274         entry = g_malloc0 (sizeof (DebugEntry));
275         entry->type = type;
276         entry->addr = (guint64)(gsize)data;
277         entry->size = size;
278
279         mono_memory_barrier ();
280
281         lldb_lock ();
282
283         /* The debugger can read the list of entries asynchronously, so this has to be async safe */
284         // FIXME: Make sure this is async safe
285         if (last_entry) {
286                 last_entry->next_addr = (guint64)(gsize) (entry);
287                 last_entry = entry;
288         } else {
289                 last_entry = entry;
290                 __mono_jit_debug_descriptor.all_entries = entry;
291         }
292
293         __mono_jit_debug_descriptor.entry = entry;
294         __mono_jit_debug_register_code ();
295
296         lldb_unlock ();
297 }
298
299 /*
300  * register_codegen_region:
301  *
302  * Register a codegen region with the debugger if needed.
303  * Return a region id.
304  */
305 static int
306 register_codegen_region (gpointer region_start, int region_size, gboolean dynamic)
307 {
308         CodeRegionEntry *region_entry;
309         int id;
310         Buffer tmp_buf;
311         Buffer *buf = &tmp_buf;
312
313         if (dynamic) {
314                 lldb_lock ();
315                 id = ++id_generator;
316                 lldb_unlock ();
317         } else {
318                 lldb_lock ();
319                 if (!codegen_regions)
320                         codegen_regions = g_hash_table_new (NULL, NULL);
321                 id = GPOINTER_TO_INT (g_hash_table_lookup (codegen_regions, region_start));
322                 if (id) {
323                         lldb_unlock ();
324                         return id;
325                 }
326                 id = ++id_generator;
327                 g_hash_table_insert (codegen_regions, region_start, GINT_TO_POINTER (id));
328                 lldb_unlock ();
329         }
330
331         buffer_init (buf, 128);
332
333         region_entry = (CodeRegionEntry*)buf->p;
334         buf->p += sizeof (CodeRegionEntry);
335         memset (region_entry, 0, sizeof (CodeRegionEntry));
336         strcpy (region_entry->magic, OBJFILE_MAGIC);
337         region_entry->id = id;
338         region_entry->start = (gsize)region_start;
339         region_entry->size = (gsize)region_size;
340
341         add_entry (ENTRY_CODE_REGION, buf);
342         buffer_free (buf);
343         return id;
344 }
345
346 static void
347 emit_unwind_info (GSList *unwind_ops, Buffer *buf)
348 {
349         int ret_reg;
350         int nunwind_ops;
351         GSList *l;
352
353         ret_reg = mono_unwind_get_dwarf_pc_reg ();
354         g_assert (ret_reg < 256);
355
356         /* We use the unencoded version of the unwind info to make it easier to decode */
357         nunwind_ops = 0;
358         for (l = unwind_ops; l; l = l->next) {
359                 MonoUnwindOp *op = l->data;
360
361                 /* lldb can't handle these */
362                 if (op->op == DW_CFA_mono_advance_loc)
363                         break;
364                 nunwind_ops ++;
365         }
366
367         buffer_add_byte (buf, ret_reg);
368         buffer_add_int (buf, nunwind_ops);
369         for (l = unwind_ops; l; l = l->next) {
370                 MonoUnwindOp *op = l->data;
371
372                 if (op->op == DW_CFA_mono_advance_loc)
373                         break;
374                 buffer_add_int (buf, op->op);
375                 buffer_add_int (buf, op->when);
376                 int dreg;
377 #if TARGET_X86
378                 // LLDB doesn't see to use the switched esp/ebp
379                 if (op->reg == X86_ESP)
380                         dreg = X86_ESP;
381                 else if (op->reg == X86_EBP)
382                         dreg = X86_EBP;
383                 else
384                         dreg = mono_hw_reg_to_dwarf_reg (op->reg);
385 #else
386                 dreg = mono_hw_reg_to_dwarf_reg (op->reg);
387 #endif
388                 buffer_add_int (buf, dreg);
389                 buffer_add_int (buf, op->val);
390         }
391 }
392
393 void
394 mono_lldb_init (const char *options)
395 {
396         enabled = TRUE;
397         mono_os_mutex_init_recursive (&mutex);
398 }
399
400 typedef struct
401 {
402         MonoSymSeqPoint sp;
403         int native_offset;
404 } FullSeqPoint;
405
406 static int
407 compare_by_addr (const void *arg1, const void *arg2)
408 {
409         const FullSeqPoint *sp1 = arg1;
410         const FullSeqPoint *sp2 = arg2;
411
412         return sp1->native_offset - sp2->native_offset;
413 }
414
415 void
416 mono_lldb_save_method_info (MonoCompile *cfg)
417 {
418         MethodEntry *entry;
419         UserData udata;
420         int region_id;
421         Buffer tmpbuf;
422         Buffer *buf = &tmpbuf;
423         MonoDebugMethodInfo *minfo;
424         int i, j, n_il_offsets;
425         int *source_files;
426         GPtrArray *source_file_list;
427         MonoSymSeqPoint *sym_seq_points;
428         FullSeqPoint *locs;
429
430         if (!enabled)
431                 return;
432
433         /* Find the codegen region which contains the code */
434         memset (&udata, 0, sizeof (udata));
435         udata.code = cfg->native_code;
436         if (cfg->method->dynamic) {
437                 mono_code_manager_foreach (cfg->dynamic_info->code_mp, find_code_region, &udata);
438                 g_assert (udata.found);
439
440                 region_id = register_codegen_region (udata.region_start, udata.region_size, TRUE);
441
442                 lldb_lock ();
443                 if (!dyn_codegen_regions)
444                         dyn_codegen_regions = g_hash_table_new (NULL, NULL);
445                 g_hash_table_insert (dyn_codegen_regions, cfg->method, GINT_TO_POINTER (region_id));
446                 lldb_unlock ();
447         } else {
448                 mono_domain_code_foreach (cfg->domain, find_code_region, &udata);
449                 g_assert (udata.found);
450
451                 region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
452         }
453
454         buffer_init (buf, 256);
455
456         entry = (MethodEntry*)buf->p;
457         buf->p += sizeof (MethodEntry);
458         entry->id = ++id_generator;
459         entry->region_id = region_id;
460         entry->code = (gsize)cfg->native_code;
461         entry->code_size = cfg->code_size;
462
463         emit_unwind_info (cfg->unwind_ops, buf);
464
465         char *s = mono_method_full_name (cfg->method, TRUE);
466         buffer_add_string (buf, s);
467         g_free (s);
468
469         minfo = mono_debug_lookup_method (cfg->method);
470         MonoSeqPointInfo *seq_points = cfg->seq_point_info;
471         if (minfo && seq_points) {
472                 mono_debug_get_seq_points (minfo, NULL, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
473                 buffer_add_int (buf, source_file_list->len);
474                 for (i = 0; i < source_file_list->len; ++i) {
475                         MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, i);
476                         buffer_add_string (buf, sinfo->source_file);
477                         for (j = 0; j < 16; ++j)
478                                 buffer_add_byte (buf, sinfo->hash [j]);
479                 }
480
481                 // The sym seq points are ordered by il offset, need to order them by address
482                 int skipped = 0;
483                 locs = g_new0 (FullSeqPoint, n_il_offsets);
484                 for (i = 0; i < n_il_offsets; ++i) {
485                         locs [i].sp = sym_seq_points [i];
486
487                         // FIXME: O(n^2)
488                         SeqPoint seq_point;
489                         if (mono_seq_point_find_by_il_offset (seq_points, sym_seq_points [i].il_offset, &seq_point)) {
490                                 locs [i].native_offset = seq_point.native_offset;
491                         } else {
492                                 locs [i].native_offset = 0xffffff;
493                                 skipped ++;
494                         }
495                 }
496                 qsort (locs, n_il_offsets, sizeof (FullSeqPoint), compare_by_addr);
497
498                 n_il_offsets -= skipped;
499                 buffer_add_int (buf, n_il_offsets);
500                 for (i = 0; i < n_il_offsets; ++i) {
501                         MonoSymSeqPoint *sp = &locs [i].sp;
502                         const char *srcfile = "";
503
504                         if (source_files [i] != -1) {
505                                 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
506                                 srcfile = sinfo->source_file;
507                         }
508
509                         //printf ("%s %x %d %d\n", cfg->method->name, locs [i].native_offset, sp->il_offset, sp->line);
510                         buffer_add_int (buf, locs [i].native_offset);
511                         buffer_add_int (buf, sp->il_offset);
512                         buffer_add_int (buf, sp->line);
513                         buffer_add_int (buf, source_files [i]);
514                         buffer_add_int (buf, sp->column);
515                         buffer_add_int (buf, sp->end_line);
516                         buffer_add_int (buf, sp->end_column);
517                 }
518                 g_free (locs);
519                 g_free (source_files);
520                 g_free (sym_seq_points);
521                 g_ptr_array_free (source_file_list, TRUE);
522         } else {
523                 buffer_add_int (buf, 0);
524                 buffer_add_int (buf, 0);
525         }
526
527         add_entry (ENTRY_METHOD, buf);
528         buffer_free (buf);
529 }
530
531 void
532 mono_lldb_remove_method (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *info)
533 {
534         int region_id;
535         UnloadCodeRegionEntry *entry;
536         Buffer tmpbuf;
537         Buffer *buf = &tmpbuf;
538
539         g_assert (method->dynamic);
540
541         lldb_lock ();
542         region_id = GPOINTER_TO_INT (g_hash_table_lookup (dyn_codegen_regions, method));
543         g_hash_table_remove (dyn_codegen_regions, method);
544         lldb_unlock ();
545
546         buffer_init (buf, 256);
547
548         entry = (UnloadCodeRegionEntry*)buf->p;
549         buf->p += sizeof (UnloadCodeRegionEntry);
550         entry->id = region_id;
551
552         add_entry (ENTRY_UNLOAD_CODE_REGION, buf);
553         buffer_free (buf);
554
555         /* The method is associated with the code region, so it doesn't have to be unloaded */
556 }
557
558 void
559 mono_lldb_save_trampoline_info (MonoTrampInfo *info)
560 {
561         TrampolineEntry *entry;
562         UserData udata;
563         int region_id;
564         Buffer tmpbuf;
565         Buffer *buf = &tmpbuf;
566
567         if (!enabled)
568                 return;
569
570         /* Find the codegen region which contains the code */
571         memset (&udata, 0, sizeof (udata));
572         udata.code = info->code;
573         mono_global_codeman_foreach (find_code_region, &udata);
574         if (!udata.found)
575                 mono_domain_code_foreach (mono_get_root_domain (), find_code_region, &udata);
576         g_assert (udata.found);
577
578         region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
579
580         buffer_init (buf, 1024);
581
582         entry = (TrampolineEntry*)buf->p;
583         buf->p += sizeof (TrampolineEntry);
584         entry->id = ++id_generator;
585         entry->region_id = region_id;
586         entry->code = (gsize)info->code;
587         entry->code_size = info->code_size;
588
589         emit_unwind_info (info->unwind_ops, buf);
590
591         buffer_add_string (buf, info->name);
592
593         add_entry (ENTRY_TRAMPOLINE, buf);
594         buffer_free (buf);
595 }
596
597 void
598 mono_lldb_save_specific_trampoline_info (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, gpointer code, guint32 code_len)
599 {
600         TrampolineEntry *entry;
601         UserData udata;
602         int region_id;
603         Buffer tmpbuf;
604         Buffer *buf = &tmpbuf;
605
606         if (!enabled)
607                 return;
608
609         /* Find the codegen region which contains the code */
610         memset (&udata, 0, sizeof (udata));
611         udata.code = code;
612         mono_global_codeman_foreach (find_code_region, &udata);
613         if (!udata.found)
614                 mono_domain_code_foreach (mono_get_root_domain (), find_code_region, &udata);
615         g_assert (udata.found);
616
617         region_id = register_codegen_region (udata.region_start, udata.region_size, FALSE);
618
619         buffer_init (buf, 1024);
620
621         entry = (TrampolineEntry*)buf->p;
622         buf->p += sizeof (TrampolineEntry);
623         entry->id = ++id_generator;
624         entry->region_id = region_id;
625         entry->code = (gsize)code;
626         entry->code_size = code_len;
627
628         GSList *unwind_ops = mono_arch_get_cie_program ();
629         emit_unwind_info (unwind_ops, buf);
630
631         buffer_add_string (buf, "");
632
633         add_entry (ENTRY_TRAMPOLINE, buf);
634         buffer_free (buf);
635 }
636
637 /*
638 DESIGN:
639
640 Communication:
641 Similar to the gdb jit interface. The runtime communicates with a plugin running inside lldb.
642 - The runtime allocates a data packet, points a symbol with a well known name at it.
643 - It calls a dummy function with a well known name.
644 - The plugin sets a breakpoint at this function, causing the runtime to be suspended.
645 - The plugin reads the data pointed to by the other symbol and processes it.
646
647 The data packets are kept in a list, so lldb can read all of them after attaching.
648 Lldb will associate an object file with each mono codegen region.
649
650 Packet design:
651 - use a flat byte array so the whole data can be read in one operation.
652 - use 64 bit ints for pointers.
653 */
654
655 #else
656
657 void
658 mono_lldb_init (const char *options)
659 {
660         g_error ("lldb support has been disabled at configure time.");
661 }
662
663 void
664 mono_lldb_save_method_info (MonoCompile *cfg)
665 {
666 }
667
668 void
669 mono_lldb_save_trampoline_info (MonoTrampInfo *info)
670 {
671 }
672
673 void
674 mono_lldb_remove_method (MonoDomain *domain, MonoMethod *method, MonoJitDynamicMethodInfo *info)
675 {
676 }
677
678 void
679 mono_lldb_save_specific_trampoline_info (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, gpointer code, guint32 code_len)
680 {
681 }
682
683 #endif