Merge pull request #1337 from RyanMelenaNoesis/master
[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 "mini-unwind.h"
12
13 #include <mono/utils/mono-counters.h>
14 #include <mono/utils/freebsd-dwarf.h>
15 #include <mono/utils/hazard-pointer.h>
16 #include <mono/metadata/threads-types.h>
17 #include <mono/metadata/mono-endian.h>
18
19 typedef enum {
20         LOC_SAME,
21         LOC_OFFSET
22 } LocType;
23
24 typedef struct {
25         LocType loc_type;
26         int offset;
27 } Loc;
28
29 typedef struct {
30         guint32 len;
31         guint8 info [MONO_ZERO_LEN_ARRAY];
32 } MonoUnwindInfo;
33
34 #define ALIGN_TO(val,align) ((((size_t)val) + ((align) - 1)) & ~((align) - 1))
35
36 static mono_mutex_t unwind_mutex;
37
38 static MonoUnwindInfo **cached_info;
39 static int cached_info_next, cached_info_size;
40 static GSList *cached_info_list;
41 /* Statistics */
42 static int unwind_info_size;
43
44 #define unwind_lock() mono_mutex_lock (&unwind_mutex)
45 #define unwind_unlock() mono_mutex_unlock (&unwind_mutex)
46
47 #ifdef TARGET_AMD64
48 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 };
49 #define NUM_REGS AMD64_NREG
50 #define DWARF_DATA_ALIGN (-8)
51 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (AMD64_RIP))
52 #elif defined(TARGET_ARM)
53 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
54 /* Assign d8..d15 to hregs 16..24 */
55 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 264, 265, 266, 267, 268, 269, 270, 271 };
56 #define NUM_REGS 272
57 #define DWARF_DATA_ALIGN (-4)
58 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
59 #elif defined(TARGET_ARM64)
60 #define NUM_REGS 96
61 #define DWARF_DATA_ALIGN (-8)
62 /* LR */
63 #define DWARF_PC_REG 30
64 static int map_hw_reg_to_dwarf_reg [] = {
65         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
66         16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
67         /* v8..v15 */
68         72, 73, 74, 75, 76, 77, 78, 79,
69 };
70 #elif defined (TARGET_X86)
71 #ifdef __APPLE__
72 /*
73  * LLVM seems to generate unwind info where esp is encoded as 5, and ebp as 4, ie see this line:
74  *   def ESP : RegisterWithSubRegs<"esp", [SP]>, DwarfRegNum<[-2, 5, 4]>;
75  * in lib/Target/X86/X86RegisterInfo.td in the llvm sources.
76  */
77 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 5, 4, 6, 7, 8 };
78 #else
79 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
80 #endif
81 /* + 1 is for IP */
82 #define NUM_REGS X86_NREG + 1
83 #define DWARF_DATA_ALIGN (-4)
84 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
85 #elif defined (TARGET_POWERPC)
86 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
87 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 
88                                                                                   9, 10, 11, 12, 13, 14, 15, 16,
89                                                                                   17, 18, 19, 20, 21, 22, 23, 24,
90                                                                                   25, 26, 27, 28, 29, 30, 31 };
91 #define NUM_REGS 110
92 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
93 #define DWARF_PC_REG 108
94 #elif defined (TARGET_S390X)
95 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
96 #define NUM_REGS 16
97 #define DWARF_DATA_ALIGN (-8)
98 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
99 #elif defined (TARGET_MIPS)
100 /* FIXME: */
101 static int map_hw_reg_to_dwarf_reg [32] = {
102         0, 1, 2, 3, 4, 5, 6, 7,
103         8, 9, 10, 11, 12, 13, 14, 15,
104         16, 17, 18, 19, 20, 21, 22, 23,
105         24, 25, 26, 27, 28, 29, 30, 31
106 };
107 #define NUM_REGS 32
108 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
109 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
110 #else
111 static int map_hw_reg_to_dwarf_reg [16];
112 #define NUM_REGS 16
113 #define DWARF_DATA_ALIGN 0
114 #define DWARF_PC_REG -1
115 #endif
116
117 static gboolean dwarf_reg_to_hw_reg_inited;
118
119 static int map_dwarf_reg_to_hw_reg [NUM_REGS];
120
121 /*
122  * mono_hw_reg_to_dwarf_reg:
123  *
124  *   Map the hardware register number REG to the register number used by DWARF.
125  */
126 int
127 mono_hw_reg_to_dwarf_reg (int reg)
128 {
129 #ifdef TARGET_POWERPC
130         if (reg == ppc_lr)
131                 return 108;
132         else
133                 g_assert (reg < NUM_REGS);
134 #endif
135
136         if (NUM_REGS == 0) {
137                 g_assert_not_reached ();
138                 return -1;
139         } else {
140                 return map_hw_reg_to_dwarf_reg [reg];
141         }
142 }
143
144 static void
145 init_reg_map (void)
146 {
147         int i;
148
149         g_assert (NUM_REGS > 0);
150         for (i = 0; i < sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int); ++i) {
151                 map_dwarf_reg_to_hw_reg [mono_hw_reg_to_dwarf_reg (i)] = i;
152         }
153
154 #ifdef TARGET_POWERPC
155         map_dwarf_reg_to_hw_reg [DWARF_PC_REG] = ppc_lr;
156 #endif
157
158         mono_memory_barrier ();
159         dwarf_reg_to_hw_reg_inited = TRUE;
160 }
161
162 int
163 mono_dwarf_reg_to_hw_reg (int reg)
164 {
165         if (!dwarf_reg_to_hw_reg_inited)
166                 init_reg_map ();
167
168         return map_dwarf_reg_to_hw_reg [reg];
169 }
170
171 static G_GNUC_UNUSED void
172 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
173 {
174         guint8 *p = buf;
175
176         do {
177                 guint8 b = value & 0x7f;
178                 value >>= 7;
179                 if (value != 0) /* more bytes to come */
180                         b |= 0x80;
181                 *p ++ = b;
182         } while (value);
183
184         *endbuf = p;
185 }
186
187 static G_GNUC_UNUSED void
188 encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
189 {
190         gboolean more = 1;
191         gboolean negative = (value < 0);
192         guint32 size = 32;
193         guint8 byte;
194         guint8 *p = buf;
195
196         while (more) {
197                 byte = value & 0x7f;
198                 value >>= 7;
199                 /* the following is unnecessary if the
200                  * implementation of >>= uses an arithmetic rather
201                  * than logical shift for a signed left operand
202                  */
203                 if (negative)
204                         /* sign extend */
205                         value |= - (1 <<(size - 7));
206                 /* sign bit of byte is second high order bit (0x40) */
207                 if ((value == 0 && !(byte & 0x40)) ||
208                         (value == -1 && (byte & 0x40)))
209                         more = 0;
210                 else
211                         byte |= 0x80;
212                 *p ++= byte;
213         }
214
215         *endbuf = p;
216 }
217
218 static inline guint32
219 decode_uleb128 (guint8 *buf, guint8 **endbuf)
220 {
221         guint8 *p = buf;
222         guint32 res = 0;
223         int shift = 0;
224
225         while (TRUE) {
226                 guint8 b = *p;
227                 p ++;
228
229                 res = res | (((int)(b & 0x7f)) << shift);
230                 if (!(b & 0x80))
231                         break;
232                 shift += 7;
233         }
234
235         *endbuf = p;
236
237         return res;
238 }
239
240 static inline gint32
241 decode_sleb128 (guint8 *buf, guint8 **endbuf)
242 {
243         guint8 *p = buf;
244         gint32 res = 0;
245         int shift = 0;
246
247         while (TRUE) {
248                 guint8 b = *p;
249                 p ++;
250
251                 res = res | (((int)(b & 0x7f)) << shift);
252                 shift += 7;
253                 if (!(b & 0x80)) {
254                         if (shift < 32 && (b & 0x40))
255                                 res |= - (1 << shift);
256                         break;
257                 }
258         }
259
260         *endbuf = p;
261
262         return res;
263 }
264
265 void
266 mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len)
267 {
268         guint8 *p;
269         int pos, reg, offset, cfa_reg, cfa_offset;
270
271         p = unwind_info;
272         pos = 0;
273         while (p < unwind_info + unwind_info_len) {
274                 int op = *p & 0xc0;
275
276                 switch (op) {
277                 case DW_CFA_advance_loc:
278                         pos += *p & 0x3f;
279                         p ++;
280                         break;
281                 case DW_CFA_offset:
282                         reg = *p & 0x3f;
283                         p ++;
284                         offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
285                         if (reg == DWARF_PC_REG)
286                                 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, "pc", -offset);
287                         else
288                                 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
289                         break;
290                 case 0: {
291                         int ext_op = *p;
292                         p ++;
293                         switch (ext_op) {
294                         case DW_CFA_def_cfa:
295                                 cfa_reg = decode_uleb128 (p, &p);
296                                 cfa_offset = decode_uleb128 (p, &p);
297                                 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)), cfa_offset);
298                                 break;
299                         case DW_CFA_def_cfa_offset:
300                                 cfa_offset = decode_uleb128 (p, &p);
301                                 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos, cfa_offset);
302                                 break;
303                         case DW_CFA_def_cfa_register:
304                                 cfa_reg = decode_uleb128 (p, &p);
305                                 printf ("CFA: [%x] def_cfa_reg: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)));
306                                 break;
307                         case DW_CFA_offset_extended_sf:
308                                 reg = decode_uleb128 (p, &p);
309                                 offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
310                                 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
311                                 break;
312                         case DW_CFA_same_value:
313                                 reg = decode_uleb128 (p, &p);
314                                 printf ("CFA: [%x] same_value: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)));
315                                 break;
316                         case DW_CFA_advance_loc4:
317                                 pos += read32 (p);
318                                 p += 4;
319                                 break;
320                         case DW_CFA_remember_state:
321                                 printf ("CFA: [%x] remember_state\n", pos);
322                                 break;
323                         case DW_CFA_restore_state:
324                                 printf ("CFA: [%x] restore_state\n", pos);
325                                 break;
326                         case DW_CFA_mono_advance_loc:
327                                 printf ("CFA: [%x] mono_advance_loc\n", pos);
328                                 break;
329                         default:
330                                 g_assert_not_reached ();
331                         }
332                         break;
333                 }
334                 default:
335                         g_assert_not_reached ();
336                 }
337         }
338 }
339
340 /*
341  * mono_unwind_ops_encode:
342  *
343  *   Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
344  * Return a pointer to malloc'ed memory.
345  */
346 guint8*
347 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
348 {
349         GSList *l;
350         MonoUnwindOp *op;
351         int loc;
352         guint8 buf [4096];
353         guint8 *p, *res;
354
355         p = buf;
356
357         loc = 0;
358         l = unwind_ops;
359         for (; l; l = l->next) {
360                 int reg;
361
362                 op = l->data;
363
364                 /* Convert the register from the hw encoding to the dwarf encoding */
365                 reg = mono_hw_reg_to_dwarf_reg (op->reg);
366
367                 if (op->op == DW_CFA_mono_advance_loc) {
368                         /* This advances loc to its location */
369                         loc = op->when;
370                 }
371
372                 /* Emit an advance_loc if neccesary */
373                 while (op->when > loc) {
374                         if (op->when - loc > 65536) {
375                                 *p ++ = DW_CFA_advance_loc4;
376                                 *(guint32*)p = (guint32)(op->when - loc);
377                                 g_assert (read32 (p) == (guint32)(op->when - loc));
378                                 p += 4;
379                                 loc = op->when;
380                         } else if (op->when - loc > 256) {
381                                 *p ++ = DW_CFA_advance_loc2;
382                                 *(guint16*)p = (guint16)(op->when - loc);
383                                 g_assert (read16 (p) == (guint32)(op->when - loc));
384                                 p += 2;
385                                 loc = op->when;
386                         } else if (op->when - loc >= 32) {
387                                 *p ++ = DW_CFA_advance_loc1;
388                                 *(guint8*)p = (guint8)(op->when - loc);
389                                 p += 1;
390                                 loc = op->when;
391                         } else if (op->when - loc < 32) {
392                                 *p ++ = DW_CFA_advance_loc | (op->when - loc);
393                                 loc = op->when;
394                         } else {
395                                 *p ++ = DW_CFA_advance_loc | (30);
396                                 loc += 30;
397                         }
398                 }                       
399
400                 switch (op->op) {
401                 case DW_CFA_def_cfa:
402                         *p ++ = op->op;
403                         encode_uleb128 (reg, p, &p);
404                         encode_uleb128 (op->val, p, &p);
405                         break;
406                 case DW_CFA_def_cfa_offset:
407                         *p ++ = op->op;
408                         encode_uleb128 (op->val, p, &p);
409                         break;
410                 case DW_CFA_def_cfa_register:
411                         *p ++ = op->op;
412                         encode_uleb128 (reg, p, &p);
413                         break;
414                 case DW_CFA_same_value:
415                         *p ++ = op->op;
416                         encode_uleb128 (reg, p, &p);
417                         break;
418                 case DW_CFA_offset:
419                         if (reg > 63) {
420                                 *p ++ = DW_CFA_offset_extended_sf;
421                                 encode_uleb128 (reg, p, &p);
422                                 encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
423                         } else {
424                                 *p ++ = DW_CFA_offset | reg;
425                                 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
426                         }
427                         break;
428                 case DW_CFA_remember_state:
429                 case DW_CFA_restore_state:
430                         *p ++ = op->op;
431                         break;
432                 case DW_CFA_mono_advance_loc:
433                         /* Only one location is supported */
434                         g_assert (op->val == 0);
435                         *p ++ = op->op;
436                         break;
437                 default:
438                         g_assert_not_reached ();
439                         break;
440                 }
441         }
442         
443         g_assert (p - buf < 4096);
444         *out_len = p - buf;
445         res = g_malloc (p - buf);
446         memcpy (res, buf, p - buf);
447         return res;
448 }
449
450 #if 0
451 #define UNW_DEBUG(stmt) do { stmt; } while (0)
452 #else
453 #define UNW_DEBUG(stmt) do { } while (0)
454 #endif
455
456 static G_GNUC_UNUSED void
457 print_dwarf_state (int cfa_reg, int cfa_offset, int ip, int nregs, Loc *locations, guint8 *reg_saved)
458 {
459         int i;
460
461         printf ("\t%x: cfa=r%d+%d ", ip, cfa_reg, cfa_offset);
462
463         for (i = 0; i < nregs; ++i)
464                 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET)
465                         printf ("r%d@%d(cfa) ", i, locations [i].offset);
466         printf ("\n");
467 }
468
469 typedef struct {
470         Loc locations [NUM_REGS];
471         guint8 reg_saved [NUM_REGS];
472         int cfa_reg, cfa_offset;
473 } UnwindState;
474
475 /*
476  * Given the state of the current frame as stored in REGS, execute the unwind 
477  * operations in unwind_info until the location counter reaches POS. The result is 
478  * stored back into REGS. OUT_CFA will receive the value of the CFA.
479  * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
480  * On return, the nth entry will point to the address of the stack slot where register
481  * N was saved, or NULL, if it was not saved by this frame.
482  * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
483  * This function is signal safe.
484  */
485 void
486 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 
487                                    guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
488                                    mgreg_t *regs, int nregs,
489                                    mgreg_t **save_locations, int save_locations_len,
490                                    guint8 **out_cfa)
491 {
492         Loc locations [NUM_REGS];
493         guint8 reg_saved [NUM_REGS];
494         int i, pos, reg, cfa_reg = -1, cfa_offset = 0, offset;
495         guint8 *p;
496         guint8 *cfa_val;
497         UnwindState state_stack [1];
498         int state_stack_pos;
499
500         memset (reg_saved, 0, sizeof (reg_saved));
501         state_stack [0].cfa_reg = -1;
502         state_stack [0].cfa_offset = 0;
503
504         p = unwind_info;
505         pos = 0;
506         cfa_reg = -1;
507         cfa_offset = -1;
508         state_stack_pos = 0;
509         while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
510                 int op = *p & 0xc0;
511
512                 switch (op) {
513                 case DW_CFA_advance_loc:
514                         UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
515                         pos += *p & 0x3f;
516                         p ++;
517                         break;
518                 case DW_CFA_offset:
519                         reg = *p & 0x3f;
520                         p ++;
521                         reg_saved [reg] = TRUE;
522                         locations [reg].loc_type = LOC_OFFSET;
523                         locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
524                         break;
525                 case 0: {
526                         int ext_op = *p;
527                         p ++;
528                         switch (ext_op) {
529                         case DW_CFA_def_cfa:
530                                 cfa_reg = decode_uleb128 (p, &p);
531                                 cfa_offset = decode_uleb128 (p, &p);
532                                 break;
533                         case DW_CFA_def_cfa_offset:
534                                 cfa_offset = decode_uleb128 (p, &p);
535                                 break;
536                         case DW_CFA_def_cfa_register:
537                                 cfa_reg = decode_uleb128 (p, &p);
538                                 break;
539                         case DW_CFA_offset_extended_sf:
540                                 reg = decode_uleb128 (p, &p);
541                                 offset = decode_sleb128 (p, &p);
542                                 g_assert (reg < NUM_REGS);
543                                 reg_saved [reg] = TRUE;
544                                 locations [reg].loc_type = LOC_OFFSET;
545                                 locations [reg].offset = offset * DWARF_DATA_ALIGN;
546                                 break;
547                         case DW_CFA_offset_extended:
548                                 reg = decode_uleb128 (p, &p);
549                                 offset = decode_uleb128 (p, &p);
550                                 g_assert (reg < NUM_REGS);
551                                 reg_saved [reg] = TRUE;
552                                 locations [reg].loc_type = LOC_OFFSET;
553                                 locations [reg].offset = offset * DWARF_DATA_ALIGN;
554                                 break;
555                         case DW_CFA_same_value:
556                                 reg = decode_uleb128 (p, &p);
557                                 locations [reg].loc_type = LOC_SAME;
558                                 break;
559                         case DW_CFA_advance_loc1:
560                                 pos += *p;
561                                 p += 1;
562                                 break;
563                         case DW_CFA_advance_loc2:
564                                 pos += read16 (p);
565                                 p += 2;
566                                 break;
567                         case DW_CFA_advance_loc4:
568                                 pos += read32 (p);
569                                 p += 4;
570                                 break;
571                         case DW_CFA_remember_state:
572                                 g_assert (state_stack_pos == 0);
573                                 memcpy (&state_stack [0].locations, &locations, sizeof (locations));
574                                 memcpy (&state_stack [0].reg_saved, &reg_saved, sizeof (reg_saved));
575                                 state_stack [0].cfa_reg = cfa_reg;
576                                 state_stack [0].cfa_offset = cfa_offset;
577                                 state_stack_pos ++;
578                                 break;
579                         case DW_CFA_restore_state:
580                                 g_assert (state_stack_pos == 1);
581                                 state_stack_pos --;
582                                 memcpy (&locations, &state_stack [0].locations, sizeof (locations));
583                                 memcpy (&reg_saved, &state_stack [0].reg_saved, sizeof (reg_saved));
584                                 cfa_reg = state_stack [0].cfa_reg;
585                                 cfa_offset = state_stack [0].cfa_offset;
586                                 break;
587                         case DW_CFA_mono_advance_loc:
588                                 g_assert (mark_locations [0]);
589                                 pos = mark_locations [0] - start_ip;
590                                 break;
591                         default:
592                                 g_assert_not_reached ();
593                         }
594                         break;
595                 }
596                 default:
597                         g_assert_not_reached ();
598                 }
599         }
600
601         if (save_locations)
602                 memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));
603
604         g_assert (cfa_reg != -1);
605         cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
606         for (i = 0; i < NUM_REGS; ++i) {
607                 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
608                         int hreg = mono_dwarf_reg_to_hw_reg (i);
609                         g_assert (hreg < nregs);
610                         regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
611                         if (save_locations && hreg < save_locations_len)
612                                 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
613                 }
614         }
615
616         *out_cfa = cfa_val;
617 }
618
619 void
620 mono_unwind_init (void)
621 {
622         mono_mutex_init_recursive (&unwind_mutex);
623
624         mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
625 }
626
627 void
628 mono_unwind_cleanup (void)
629 {
630         int i;
631
632         mono_mutex_destroy (&unwind_mutex);
633
634         if (!cached_info)
635                 return;
636
637         for (i = 0; i < cached_info_next; ++i) {
638                 MonoUnwindInfo *cached = cached_info [i];
639
640                 g_free (cached);
641         }
642
643         g_free (cached_info);
644 }
645
646 /*
647  * mono_cache_unwind_info
648  *
649  *   Save UNWIND_INFO in the unwind info cache and return an id which can be passed
650  * to mono_get_cached_unwind_info to get a cached copy of the info.
651  * A copy is made of the unwind info.
652  * This function is useful for two reasons:
653  * - many methods have the same unwind info
654  * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
655  */
656 guint32
657 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
658 {
659         int i;
660         MonoUnwindInfo *info;
661
662         unwind_lock ();
663
664         if (cached_info == NULL) {
665                 cached_info_size = 16;
666                 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
667         }
668
669         for (i = 0; i < cached_info_next; ++i) {
670                 MonoUnwindInfo *cached = cached_info [i];
671
672                 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
673                         unwind_unlock ();
674                         return i;
675                 }
676         }
677
678         info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
679         info->len = unwind_info_len;
680         memcpy (&info->info, unwind_info, unwind_info_len);
681
682         i = cached_info_next;
683         
684         if (cached_info_next >= cached_info_size) {
685                 MonoUnwindInfo **old_table, **new_table;
686
687                 /*
688                  * Avoid freeing the old table so mono_get_cached_unwind_info ()
689                  * doesn't need locks/hazard pointers.
690                  */
691
692                 old_table = cached_info;
693                 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
694
695                 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
696
697                 mono_memory_barrier ();
698
699                 cached_info = new_table;
700
701                 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
702
703                 cached_info_size *= 2;
704         }
705
706         cached_info [cached_info_next ++] = info;
707
708         unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
709
710         unwind_unlock ();
711         return i;
712 }
713
714 /*
715  * This function is signal safe.
716  */
717 guint8*
718 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
719 {
720         MonoUnwindInfo **table;
721         MonoUnwindInfo *info;
722         guint8 *data;
723
724         /*
725          * This doesn't need any locks/hazard pointers,
726          * since new tables are copies of the old ones.
727          */
728         table = cached_info;
729
730         info = table [index];
731
732         *unwind_info_len = info->len;
733         data = info->info;
734
735         return data;
736 }
737
738 /*
739  * mono_unwind_get_dwarf_data_align:
740  *
741  *   Return the data alignment used by the encoded unwind information.
742  */
743 int
744 mono_unwind_get_dwarf_data_align (void)
745 {
746         return DWARF_DATA_ALIGN;
747 }
748
749 /*
750  * mono_unwind_get_dwarf_pc_reg:
751  *
752  *   Return the dwarf register number of the register holding the ip of the
753  * previous frame.
754  */
755 int
756 mono_unwind_get_dwarf_pc_reg (void)
757 {
758         return DWARF_PC_REG;
759 }
760
761 static void
762 decode_cie_op (guint8 *p, guint8 **endp)
763 {
764         int op = *p & 0xc0;
765
766         switch (op) {
767         case DW_CFA_advance_loc:
768                 p ++;
769                 break;
770         case DW_CFA_offset:
771                 p ++;
772                 decode_uleb128 (p, &p);
773                 break;
774         case 0: {
775                 int ext_op = *p;
776                 p ++;
777                 switch (ext_op) {
778                 case DW_CFA_def_cfa:
779                         decode_uleb128 (p, &p);
780                         decode_uleb128 (p, &p);
781                         break;
782                 case DW_CFA_def_cfa_offset:
783                         decode_uleb128 (p, &p);
784                         break;
785                 case DW_CFA_def_cfa_register:
786                         decode_uleb128 (p, &p);
787                         break;
788                 case DW_CFA_advance_loc4:
789                         p += 4;
790                         break;
791                 case DW_CFA_offset_extended_sf:
792                         decode_uleb128 (p, &p);
793                         decode_uleb128 (p, &p);
794                         break;
795                 default:
796                         g_assert_not_reached ();
797                 }
798                 break;
799         }
800         default:
801                 g_assert_not_reached ();
802         }
803
804         *endp = p;
805 }
806
807 static gint64
808 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
809 {
810         gint64 res;
811
812         switch (encoding & 0xf) {
813         case DW_EH_PE_sdata8:
814                 res = *(gint64*)p;
815                 p += 8;
816                 break;
817         case DW_EH_PE_sdata4:
818                 res = *(gint32*)p;
819                 p += 4;
820                 break;
821         default:
822                 g_assert_not_reached ();
823         }
824
825         *endp = p;
826         return res;
827 }
828
829 /*
830  * decode_lsda:
831  *
832  *   Decode the Mono specific Language Specific Data Area generated by LLVM.
833  */
834 static void
835 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
836 {
837         guint8 *p;
838         int i, ncall_sites, this_encoding;
839         guint32 mono_magic, version;
840
841         p = lsda;
842
843         /* This is the modified LSDA generated by the LLVM mono branch */
844         mono_magic = decode_uleb128 (p, &p);
845         g_assert (mono_magic == 0x4d4fef4f);
846         version = decode_uleb128 (p, &p);
847         g_assert (version == 1);
848         this_encoding = *p;
849         p ++;
850         if (this_encoding == DW_EH_PE_udata4) {
851                 gint32 op, reg, offset;
852
853                 /* 'this' location */
854                 op = *p;
855                 g_assert (op == DW_OP_bregx);
856                 p ++;
857                 reg = decode_uleb128 (p, &p);
858                 offset = decode_sleb128 (p, &p);
859
860                 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
861                 *this_offset = offset;
862         } else {
863                 g_assert (this_encoding == DW_EH_PE_omit);
864
865                 *this_reg = -1;
866                 *this_offset = -1;
867         }
868         ncall_sites = decode_uleb128 (p, &p);
869         p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
870
871         if (ex_info) {
872                 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
873                 *ex_info_len = ncall_sites;
874         }
875         if (type_info)
876                 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
877
878         for (i = 0; i < ncall_sites; ++i) {
879                 int block_start_offset, block_size, landing_pad;
880                 guint8 *tinfo;
881
882                 block_start_offset = read32 (p);
883                 p += sizeof (gint32);
884                 block_size = read32 (p);
885                 p += sizeof (gint32);
886                 landing_pad = read32 (p);
887                 p += sizeof (gint32);
888                 tinfo = p;
889                 p += sizeof (gint32);
890
891                 g_assert (landing_pad);
892                 g_assert (((size_t)tinfo % 4) == 0);
893                 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
894
895                 if (ex_info) {
896                         if (*type_info)
897                                 (*type_info) [i] = tinfo;
898                         (*ex_info)[i].try_start = code + block_start_offset;
899                         (*ex_info)[i].try_end = code + block_start_offset + block_size;
900                         (*ex_info)[i].handler_start = code + landing_pad;
901                 }
902         }
903 }
904
905 /*
906  * mono_unwind_decode_fde:
907  *
908  *   Decode a DWARF FDE entry, returning the unwind opcodes.
909  * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
910  * only try_start, try_end and handler_start is set.
911  * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
912  * LSDA.
913  */
914 guint8*
915 mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
916 {
917         guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
918         gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
919         gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
920         gint32 i, cie_aug_len, buf_len;
921         char *cie_aug_str;
922         guint8 *buf;
923         gboolean has_fde_augmentation = FALSE;
924
925         /* 
926          * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
927          */
928
929         *type_info = NULL;
930         *this_reg = -1;
931         *this_offset = -1;
932
933         /* Decode FDE */
934
935         p = fde;
936         // FIXME: Endianess ?
937         fde_len = *(guint32*)p;
938         g_assert (fde_len != 0xffffffff && fde_len != 0);
939         p += 4;
940         cie_offset = *(guint32*)p;
941         cie = p - cie_offset;
942         p += 4;
943         fde_current = p;
944
945         /* Decode CIE */
946         p = cie;
947         cie_len = *(guint32*)p;
948         p += 4;
949         cie_id = *(guint32*)p;
950         g_assert (cie_id == 0);
951         p += 4;
952         cie_version = *p;
953         g_assert (cie_version == 1);
954         p += 1;
955         cie_aug_str = (char*)p;
956         p += strlen (cie_aug_str) + 1;
957         code_align = decode_uleb128 (p, &p);
958         data_align = decode_sleb128 (p, &p);
959         return_reg = decode_uleb128 (p, &p);
960         if (strstr (cie_aug_str, "z")) {
961                 guint8 *cie_aug;
962                 guint32 p_encoding;
963
964                 cie_aug_len = decode_uleb128 (p, &p);
965
966                 has_fde_augmentation = TRUE;
967
968                 cie_aug = p;
969                 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
970                         switch (cie_aug_str [i]) {
971                         case 'z':
972                                 break;
973                         case 'P':
974                                 p_encoding = *p;
975                                 p ++;
976                                 read_encoded_val (p_encoding, p, &p);
977                                 break;
978                         case 'L':
979                                 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
980                                 p ++;
981                                 break;
982                         case 'R':
983                                 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
984                                 p ++;
985                                 break;
986                         default:
987                                 g_assert_not_reached ();
988                                 break;
989                         }
990                 }
991                         
992                 p = cie_aug;
993                 p += cie_aug_len;
994         }
995         cie_cfi = p;
996
997         /* Continue decoding FDE */
998         p = fde_current;
999         /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
1000         pc_begin = *(gint32*)p;
1001         code = p + pc_begin;
1002         p += 4;
1003         pc_range = *(guint32*)p;
1004         p += 4;
1005         if (has_fde_augmentation) {
1006                 aug_len = decode_uleb128 (p, &p);
1007                 fde_aug = p;
1008                 p += aug_len;
1009         } else {
1010                 aug_len = 0;
1011         }
1012         fde_cfi = p;
1013         fde_data_len = fde + 4 + fde_len - p;
1014
1015         if (code_len)
1016                 *code_len = pc_range;
1017
1018         if (ex_info) {
1019                 *ex_info = NULL;
1020                 *ex_info_len = 0;
1021         }
1022
1023         /* Decode FDE augmention */
1024         if (aug_len) {
1025                 gint32 lsda_offset;
1026                 guint8 *lsda;
1027
1028                 /* sdata|pcrel encoding */
1029                 if (aug_len == 4)
1030                         lsda_offset = read32 (fde_aug);
1031                 else if (aug_len == 8)
1032                         lsda_offset = *(gint64*)fde_aug;
1033                 else
1034                         g_assert_not_reached ();
1035                 if (lsda_offset != 0) {
1036                         lsda = fde_aug + lsda_offset;
1037
1038                         decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
1039                 }
1040         }
1041
1042         /* Make sure the FDE uses the same constants as we do */
1043         g_assert (code_align == 1);
1044         g_assert (data_align == DWARF_DATA_ALIGN);
1045         g_assert (return_reg == DWARF_PC_REG);
1046
1047         buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
1048         buf = g_malloc0 (buf_len);
1049
1050         i = 0;
1051         p = cie_cfi;
1052         while (p < cie + cie_len + 4) {
1053                 if (*p == DW_CFA_nop)
1054                         break;
1055                 else
1056                         decode_cie_op (p, &p);
1057         }
1058         memcpy (buf + i, cie_cfi, p - cie_cfi);
1059         i += p - cie_cfi;
1060
1061         p = fde_cfi;
1062         while (p < fde + fde_len + 4) {
1063                 if (*p == DW_CFA_nop)
1064                         break;
1065                 else
1066                         decode_cie_op (p, &p);
1067         }
1068         memcpy (buf + i, fde_cfi, p - fde_cfi);
1069         i += p - fde_cfi;
1070         g_assert (i <= buf_len);
1071
1072         *out_len = i;
1073
1074         return g_realloc (buf, i);
1075 }
1076
1077 /*
1078  * mono_unwind_decode_mono_fde:
1079  *
1080  *   Decode an FDE entry in the LLVM emitted mono EH frame.
1081  * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
1082  * only try_start, try_end and handler_start is set.
1083  * info->type_info is set to a malloc-ed array containing the ttype table from the
1084  * LSDA.
1085  */
1086 void
1087 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
1088 {
1089         guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
1090         int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
1091         gint32 code_align, data_align, return_reg, pers_encoding;
1092
1093         memset (res, 0, sizeof (*res));
1094         res->this_reg = -1;
1095         res->this_offset = -1;
1096
1097         /* fde points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
1098         p = fde;
1099         has_aug = *p;
1100         p ++;
1101         if (has_aug) {
1102                 aug_len = read32 (p);
1103                 p += 4;
1104         } else {
1105                 aug_len = 0;
1106         }
1107         fde_aug = p;
1108         p += aug_len;
1109         fde_cfi = p;
1110
1111         if (has_aug) {
1112                 guint8 *lsda;
1113
1114                 /* The LSDA is embedded directly into the FDE */
1115                 lsda = fde_aug;
1116
1117                 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1118         }
1119
1120         /* Decode CIE */
1121         p = cie;
1122         code_align = decode_uleb128 (p, &p);
1123         data_align = decode_sleb128 (p, &p);
1124         return_reg = decode_uleb128 (p, &p);
1125         pers_encoding = *p;
1126         p ++;
1127         if (pers_encoding != DW_EH_PE_omit)
1128                 read_encoded_val (pers_encoding, p, &p);
1129
1130         cie_cfi = p;
1131
1132         /* Make sure the FDE uses the same constants as we do */
1133         g_assert (code_align == 1);
1134         g_assert (data_align == DWARF_DATA_ALIGN);
1135         g_assert (return_reg == DWARF_PC_REG);
1136
1137         /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1138         p = cie_cfi;
1139         while (TRUE) {
1140                 if (*p == DW_CFA_nop)
1141                         break;
1142                 else
1143                         decode_cie_op (p, &p);
1144         }
1145         cie_cfi_len = p - cie_cfi;
1146         fde_cfi_len = (fde + fde_len - fde_cfi);
1147
1148         buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1149         memcpy (buf, cie_cfi, cie_cfi_len);
1150         memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1151
1152         res->unw_info_len = cie_cfi_len + fde_cfi_len;
1153         res->unw_info = buf;
1154 }
1155
1156 /*
1157  * mono_unwind_get_cie_program:
1158  *
1159  *   Get the unwind bytecode for the DWARF CIE.
1160  */
1161 GSList*
1162 mono_unwind_get_cie_program (void)
1163 {
1164 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1165         return mono_arch_get_cie_program ();
1166 #else
1167         return NULL;
1168 #endif
1169 }