Use TARGET_POWERPC instead of PPC.
[mono.git] / mono / mini / unwind.c
1 /*
2  * unwind.c: Stack Unwinding Interface
3  *
4  * Authors:
5  *   Zoltan Varga (vargaz@gmail.com)
6  *
7  * (C) 2008 Novell, Inc.
8  */
9
10 #include "mini.h"
11 #include "unwind.h"
12
13 #include <mono/utils/mono-counters.h>
14 #include <mono/metadata/threads-types.h>
15
16 typedef enum {
17         LOC_SAME,
18         LOC_OFFSET
19 } LocType;
20
21 typedef struct {
22         LocType loc_type;
23         int offset;
24 } Loc;
25
26 typedef struct {
27         guint32 len;
28         guint8 info [MONO_ZERO_LEN_ARRAY];
29 } MonoUnwindInfo;
30
31 static CRITICAL_SECTION unwind_mutex;
32
33 static MonoUnwindInfo **cached_info;
34 static int cached_info_next, cached_info_size;
35 /* Statistics */
36 static int unwind_info_size;
37
38 #define unwind_lock() EnterCriticalSection (&unwind_mutex)
39 #define unwind_unlock() LeaveCriticalSection (&unwind_mutex)
40
41 #ifdef __x86_64__
42 static int map_hw_reg_to_dwarf_reg [] = { 0, 2, 1, 3, 7, 6, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
43 #define NUM_REGS AMD64_NREG
44 #define DWARF_DATA_ALIGN (-8)
45 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (AMD64_RIP))
46 #elif defined(TARGET_ARM)
47 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
48 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
49 #define NUM_REGS 16
50 #define DWARF_DATA_ALIGN (-4)
51 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
52 #elif defined (TARGET_X86)
53 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
54 /* + 1 is for IP */
55 #define NUM_REGS X86_NREG + 1
56 #define DWARF_DATA_ALIGN (-4)
57 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
58 #elif defined (TARGET_POWERPC)
59 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
60 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 
61                                                                                   9, 10, 11, 12, 13, 14, 15, 16,
62                                                                                   17, 18, 19, 20, 21, 22, 23, 24,
63                                                                                   25, 26, 27, 28, 29, 30, 31 };
64 #define NUM_REGS 110
65 #define DWARF_DATA_ALIGN (-sizeof (mgreg_t))
66 #define DWARF_PC_REG 108
67 #else
68 static int map_hw_reg_to_dwarf_reg [16];
69 #define NUM_REGS 16
70 #define DWARF_DATA_ALIGN 0
71 #define DWARF_PC_REG -1
72 #endif
73
74 static gboolean dwarf_reg_to_hw_reg_inited;
75
76 static int map_dwarf_reg_to_hw_reg [NUM_REGS];
77
78 /*
79  * mono_hw_reg_to_dwarf_reg:
80  *
81  *   Map the hardware register number REG to the register number used by DWARF.
82  */
83 int
84 mono_hw_reg_to_dwarf_reg (int reg)
85 {
86 #ifdef TARGET_PPC
87         if (reg == ppc_lr)
88                 return 108;
89         else
90                 g_assert (reg < NUM_REGS);
91 #endif
92
93         if (NUM_REGS == 0) {
94                 g_assert_not_reached ();
95                 return -1;
96         } else {
97                 return map_hw_reg_to_dwarf_reg [reg];
98         }
99 }
100
101 static void
102 init_reg_map (void)
103 {
104         int i;
105
106         g_assert (NUM_REGS > 0);
107         g_assert (sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int) == NUM_REGS);
108         for (i = 0; i < NUM_REGS; ++i) {
109                 map_dwarf_reg_to_hw_reg [mono_hw_reg_to_dwarf_reg (i)] = i;
110         }
111
112         mono_memory_barrier ();
113         dwarf_reg_to_hw_reg_inited = TRUE;
114 }
115
116 static inline int
117 mono_dwarf_reg_to_hw_reg (int reg)
118 {
119         if (!dwarf_reg_to_hw_reg_inited)
120                 init_reg_map ();
121
122         return map_dwarf_reg_to_hw_reg [reg];
123 }
124
125 static G_GNUC_UNUSED void
126 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
127 {
128         guint8 *p = buf;
129
130         do {
131                 guint8 b = value & 0x7f;
132                 value >>= 7;
133                 if (value != 0) /* more bytes to come */
134                         b |= 0x80;
135                 *p ++ = b;
136         } while (value);
137
138         *endbuf = p;
139 }
140
141 static inline guint32
142 decode_uleb128 (guint8 *buf, guint8 **endbuf)
143 {
144         guint8 *p = buf;
145         guint32 res = 0;
146         int shift = 0;
147
148         while (TRUE) {
149                 guint8 b = *p;
150                 p ++;
151
152                 res = res | (((int)(b & 0x7f)) << shift);
153                 if (!(b & 0x80))
154                         break;
155                 shift += 7;
156         }
157
158         *endbuf = p;
159
160         return res;
161 }
162
163 static inline gint32
164 decode_sleb128 (guint8 *buf, guint8 **endbuf)
165 {
166         guint8 *p = buf;
167         gint32 res = 0;
168         int shift = 0;
169
170         while (TRUE) {
171                 guint8 b = *p;
172                 p ++;
173
174                 res = res | (((int)(b & 0x7f)) << shift);
175                 shift += 7;
176                 if (!(b & 0x80)) {
177                         if (shift < 32 && (b & 0x40))
178                                 res |= - (1 << shift);
179                         break;
180                 }
181         }
182
183         *endbuf = p;
184
185         return res;
186 }
187
188 /*
189  * mono_unwind_ops_encode:
190  *
191  *   Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
192  * Return a pointer to malloc'ed memory.
193  */
194 guint8*
195 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
196 {
197         GSList *l;
198         MonoUnwindOp *op;
199         int loc;
200         guint8 *buf, *p, *res;
201
202         p = buf = g_malloc0 (4096);
203
204         loc = 0;
205         l = unwind_ops;
206         for (; l; l = l->next) {
207                 int reg;
208
209                 op = l->data;
210
211                 /* Convert the register from the hw encoding to the dwarf encoding */
212                 reg = mono_hw_reg_to_dwarf_reg (op->reg);
213
214                 /* Emit an advance_loc if neccesary */
215                 while (op->when > loc) {
216                         if (op->when - loc < 32) {
217                                 *p ++ = DW_CFA_advance_loc | (op->when - loc);
218                                 loc = op->when;
219                         } else {
220                                 *p ++ = DW_CFA_advance_loc | (30);
221                                 loc += 30;
222                         }
223                 }                       
224
225                 switch (op->op) {
226                 case DW_CFA_def_cfa:
227                         *p ++ = op->op;
228                         encode_uleb128 (reg, p, &p);
229                         encode_uleb128 (op->val, p, &p);
230                         break;
231                 case DW_CFA_def_cfa_offset:
232                         *p ++ = op->op;
233                         encode_uleb128 (op->val, p, &p);
234                         break;
235                 case DW_CFA_def_cfa_register:
236                         *p ++ = op->op;
237                         encode_uleb128 (reg, p, &p);
238                         break;
239                 case DW_CFA_offset:
240                         if (reg > 63) {
241                                 *p ++ = DW_CFA_offset_extended_sf;
242                                 encode_uleb128 (reg, p, &p);
243                                 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
244                         } else {
245                                 *p ++ = DW_CFA_offset | reg;
246                                 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
247                         }
248                         break;
249                 default:
250                         g_assert_not_reached ();
251                         break;
252                 }
253         }
254         
255         g_assert (p - buf < 4096);
256         *out_len = p - buf;
257         res = g_malloc (p - buf);
258         memcpy (res, buf, p - buf);
259         g_free (buf);
260         return res;
261 }
262
263 #if 0
264 #define UNW_DEBUG(stmt) do { stmt; } while (0)
265 #else
266 #define UNW_DEBUG(stmt) do { } while (0)
267 #endif
268
269 static G_GNUC_UNUSED void
270 print_dwarf_state (int cfa_reg, int cfa_offset, int ip, int nregs, Loc *locations)
271 {
272         int i;
273
274         printf ("\t%x: cfa=r%d+%d ", ip, cfa_reg, cfa_offset);
275
276         for (i = 0; i < nregs; ++i)
277                 if (locations [i].loc_type == LOC_OFFSET)
278                         printf ("r%d@%d(cfa) ", i, locations [i].offset);
279         printf ("\n");
280 }
281
282 /*
283  * Given the state of the current frame as stored in REGS, execute the unwind 
284  * operations in unwind_info until the location counter reaches POS. The result is 
285  * stored back into REGS. OUT_CFA will receive the value of the CFA.
286  * This function is signal safe.
287  */
288 void
289 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 
290                                    guint8 *start_ip, guint8 *end_ip, guint8 *ip, gssize *regs, 
291                                    int nregs, guint8 **out_cfa) 
292 {
293         Loc locations [NUM_REGS];
294         int i, pos, reg, cfa_reg, cfa_offset, offset;
295         guint8 *p;
296         guint8 *cfa_val;
297
298         g_assert (nregs <= NUM_REGS);
299
300         for (i = 0; i < nregs; ++i)
301                 locations [i].loc_type = LOC_SAME;
302
303         p = unwind_info;
304         pos = 0;
305         cfa_reg = -1;
306         cfa_offset = -1;
307         while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
308                 int op = *p & 0xc0;
309
310                 switch (op) {
311                 case DW_CFA_advance_loc:
312                         UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
313                         pos += *p & 0x3f;
314                         p ++;
315                         break;
316                 case DW_CFA_offset:
317                         reg = mono_dwarf_reg_to_hw_reg (*p & 0x3f);
318                         p ++;
319                         locations [reg].loc_type = LOC_OFFSET;
320                         locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
321                         break;
322                 case 0: {
323                         int ext_op = *p;
324                         p ++;
325                         switch (ext_op) {
326                         case DW_CFA_def_cfa:
327                                 cfa_reg = mono_dwarf_reg_to_hw_reg (decode_uleb128 (p, &p));
328                                 cfa_offset = decode_uleb128 (p, &p);
329                                 break;
330                         case DW_CFA_def_cfa_offset:
331                                 cfa_offset = decode_uleb128 (p, &p);
332                                 break;
333                         case DW_CFA_def_cfa_register:
334                                 cfa_reg = mono_dwarf_reg_to_hw_reg (decode_uleb128 (p, &p));
335                                 break;
336                         case DW_CFA_offset_extended_sf:
337                                 reg = mono_dwarf_reg_to_hw_reg (decode_uleb128 (p, &p));
338                                 offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
339                                 break;
340                         case DW_CFA_advance_loc4:
341                                 pos += *(guint32*)p;
342                                 p += 4;
343                                 break;
344                         default:
345                                 g_assert_not_reached ();
346                         }
347                         break;
348                 }
349                 default:
350                         g_assert_not_reached ();
351                 }
352         }
353
354         cfa_val = (guint8*)regs [cfa_reg] + cfa_offset;
355         for (i = 0; i < nregs; ++i) {
356                 if (locations [i].loc_type == LOC_OFFSET)
357                         regs [i] = *(gssize*)(cfa_val + locations [i].offset);
358         }
359
360         *out_cfa = cfa_val;
361 }
362
363 void
364 mono_unwind_init (void)
365 {
366         InitializeCriticalSection (&unwind_mutex);
367
368         mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
369 }
370
371 void
372 mono_unwind_cleanup (void)
373 {
374         int i;
375
376         DeleteCriticalSection (&unwind_mutex);
377
378         if (!cached_info)
379                 return;
380
381         for (i = 0; i < cached_info_next; ++i) {
382                 MonoUnwindInfo *cached = cached_info [i];
383
384                 g_free (cached);
385         }
386
387         g_free (cached_info);
388 }
389
390 /*
391  * mono_cache_unwind_info
392  *
393  *   Save UNWIND_INFO in the unwind info cache and return an id which can be passed
394  * to mono_get_cached_unwind_info to get a cached copy of the info.
395  * A copy is made of the unwind info.
396  * This function is useful for two reasons:
397  * - many methods have the same unwind info
398  * - MonoJitInfo->used_regs is an int so it can't store the pointer to the unwind info
399  */
400 guint32
401 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
402 {
403         int i;
404         MonoUnwindInfo *info;
405
406         unwind_lock ();
407
408         if (cached_info == NULL) {
409                 cached_info_size = 16;
410                 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
411         }
412
413         for (i = 0; i < cached_info_next; ++i) {
414                 MonoUnwindInfo *cached = cached_info [i];
415
416                 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
417                         unwind_unlock ();
418                         return i;
419                 }
420         }
421
422         info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
423         info->len = unwind_info_len;
424         memcpy (&info->info, unwind_info, unwind_info_len);
425
426         i = cached_info_next;
427         
428         if (cached_info_next >= cached_info_size) {
429                 MonoUnwindInfo **old_table, **new_table;
430
431                 /*
432                  * Have to resize the table, while synchronizing with 
433                  * mono_get_cached_unwind_info () using hazard pointers.
434                  */
435
436                 old_table = cached_info;
437                 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
438
439                 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
440
441                 mono_memory_barrier ();
442
443                 cached_info = new_table;
444
445                 mono_memory_barrier ();
446
447                 mono_thread_hazardous_free_or_queue (old_table, g_free);
448
449                 cached_info_size *= 2;
450         }
451
452         cached_info [cached_info_next ++] = info;
453
454         unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
455
456         unwind_unlock ();
457         return i;
458 }
459
460 static gpointer
461 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
462 {
463         gpointer p;
464
465         for (;;) {
466                 /* Get the pointer */
467                 p = *pp;
468                 /* If we don't have hazard pointers just return the
469                    pointer. */
470                 if (!hp)
471                         return p;
472                 /* Make it hazardous */
473                 mono_hazard_pointer_set (hp, hazard_index, p);
474                 /* Check that it's still the same.  If not, try
475                    again. */
476                 if (*pp != p) {
477                         mono_hazard_pointer_clear (hp, hazard_index);
478                         continue;
479                 }
480                 break;
481         }
482
483         return p;
484 }
485
486 /*
487  * This function is signal safe.
488  */
489 guint8*
490 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
491 {
492         MonoUnwindInfo **table;
493         MonoUnwindInfo *info;
494         guint8 *data;
495         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
496
497         table = get_hazardous_pointer ((gpointer volatile*)&cached_info, hp, 0);
498
499         info = table [index];
500
501         *unwind_info_len = info->len;
502         data = info->info;
503
504         mono_hazard_pointer_clear (hp, 0);
505
506         return data;
507 }
508
509 /*
510  * mono_unwind_get_dwarf_data_align:
511  *
512  *   Return the data alignment used by the encoded unwind information.
513  */
514 int
515 mono_unwind_get_dwarf_data_align (void)
516 {
517         return DWARF_DATA_ALIGN;
518 }
519
520 /*
521  * mono_unwind_get_dwarf_pc_reg:
522  *
523  *   Return the dwarf register number of the register holding the ip of the
524  * previous frame.
525  */
526 int
527 mono_unwind_get_dwarf_pc_reg (void)
528 {
529         return DWARF_PC_REG;
530 }
531
532 static void
533 decode_cie_op (guint8 *p, guint8 **endp)
534 {
535         int op = *p & 0xc0;
536
537         switch (op) {
538         case DW_CFA_advance_loc:
539                 p ++;
540                 break;
541         case DW_CFA_offset:
542                 p ++;
543                 decode_uleb128 (p, &p);
544                 break;
545         case 0: {
546                 int ext_op = *p;
547                 p ++;
548                 switch (ext_op) {
549                 case DW_CFA_def_cfa:
550                         decode_uleb128 (p, &p);
551                         decode_uleb128 (p, &p);
552                         break;
553                 case DW_CFA_def_cfa_offset:
554                         decode_uleb128 (p, &p);
555                         break;
556                 case DW_CFA_def_cfa_register:
557                         decode_uleb128 (p, &p);
558                         break;
559                 case DW_CFA_advance_loc4:
560                         p += 4;
561                         break;
562                 default:
563                         g_assert_not_reached ();
564                 }
565                 break;
566         }
567         default:
568                 g_assert_not_reached ();
569         }
570
571         *endp = p;
572 }
573
574 /*
575  * mono_unwind_get_ops_from_fde:
576  *
577  *   Return the unwind opcodes encoded in a DWARF FDE entry.
578  */
579 guint8*
580 mono_unwind_get_ops_from_fde (guint8 *fde, guint32 *out_len)
581 {
582         guint8 *p, *cie, *code, *fde_cfi, *cie_cfi;
583         gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
584         gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
585         gint32 i, cie_aug_len, buf_len;
586         char *cie_aug_str;
587         guint8 *buf;
588
589         /* 
590          * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
591          */
592
593         /* Decode FDE */
594
595         p = fde;
596         // FIXME: Endianess ?
597         fde_len = *(guint32*)p;
598         g_assert (fde_len != 0xffffffff && fde_len != 0);
599         p += 4;
600         cie_offset = *(guint32*)p;
601         cie = p - cie_offset;
602         p += 4;
603         pc_begin = *(gint32*)p;
604         code = p + pc_begin;
605         p += 4;
606         pc_range = *(guint32*)p;
607         p += 4;
608         aug_len = decode_uleb128 (p, &p);
609         g_assert (aug_len == 0);
610         fde_cfi = p;
611         fde_data_len = fde + 4 + fde_len - p;
612
613         /* Decode CIE */
614         p = cie;
615         cie_len = *(guint32*)p;
616         p += 4;
617         cie_id = *(guint32*)p;
618         g_assert (cie_id == 0);
619         p += 4;
620         cie_version = *p;
621         g_assert (cie_version == 1);
622         p += 1;
623         cie_aug_str = (char*)p;
624         p += strlen (cie_aug_str) + 1;
625         code_align = decode_uleb128 (p, &p);
626         data_align = decode_sleb128 (p, &p);
627         return_reg = decode_uleb128 (p, &p);
628         if (strstr (cie_aug_str, "z")) {
629                 cie_aug_len = decode_uleb128 (p, &p);
630                 p += cie_aug_len;
631         }
632         cie_cfi = p;
633
634         /* Make sure the FDE uses the same constants as we do */
635         g_assert (code_align == 1);
636         g_assert (data_align == DWARF_DATA_ALIGN);
637         g_assert (return_reg == DWARF_PC_REG);
638
639         buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
640         buf = g_malloc0 (buf_len);
641
642         i = 0;
643         p = cie_cfi;
644         while (p < cie + cie_len + 4) {
645                 if (*p == DW_CFA_nop)
646                         break;
647                 else
648                         decode_cie_op (p, &p);
649         }
650         memcpy (buf + i, cie_cfi, p - cie_cfi);
651         i += p - cie_cfi;
652
653         p = fde_cfi;
654         while (p < fde + fde_len + 4) {
655                 if (*p == DW_CFA_nop)
656                         break;
657                 else
658                         decode_cie_op (p, &p);
659         }
660         memcpy (buf + i, fde_cfi, p - fde_cfi);
661         i += p - fde_cfi;
662         g_assert (i <= buf_len);
663
664         *out_len = i;
665
666         return g_realloc (buf, i);
667 }