Merge pull request #1219 from panzone/los_partial_marking
[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, *p, *res;
353
354         p = buf = g_malloc0 (4096);
355
356         loc = 0;
357         l = unwind_ops;
358         for (; l; l = l->next) {
359                 int reg;
360
361                 op = l->data;
362
363                 /* Convert the register from the hw encoding to the dwarf encoding */
364                 reg = mono_hw_reg_to_dwarf_reg (op->reg);
365
366                 if (op->op == DW_CFA_mono_advance_loc) {
367                         /* This advances loc to its location */
368                         loc = op->when;
369                 }
370
371                 /* Emit an advance_loc if neccesary */
372                 while (op->when > loc) {
373                         if (op->when - loc > 65536) {
374                                 *p ++ = DW_CFA_advance_loc4;
375                                 *(guint32*)p = (guint32)(op->when - loc);
376                                 g_assert (read32 (p) == (guint32)(op->when - loc));
377                                 p += 4;
378                                 loc = op->when;
379                         } else if (op->when - loc > 256) {
380                                 *p ++ = DW_CFA_advance_loc2;
381                                 *(guint16*)p = (guint16)(op->when - loc);
382                                 g_assert (read16 (p) == (guint32)(op->when - loc));
383                                 p += 2;
384                                 loc = op->when;
385                         } else if (op->when - loc >= 32) {
386                                 *p ++ = DW_CFA_advance_loc1;
387                                 *(guint8*)p = (guint8)(op->when - loc);
388                                 p += 1;
389                                 loc = op->when;
390                         } else if (op->when - loc < 32) {
391                                 *p ++ = DW_CFA_advance_loc | (op->when - loc);
392                                 loc = op->when;
393                         } else {
394                                 *p ++ = DW_CFA_advance_loc | (30);
395                                 loc += 30;
396                         }
397                 }                       
398
399                 switch (op->op) {
400                 case DW_CFA_def_cfa:
401                         *p ++ = op->op;
402                         encode_uleb128 (reg, p, &p);
403                         encode_uleb128 (op->val, p, &p);
404                         break;
405                 case DW_CFA_def_cfa_offset:
406                         *p ++ = op->op;
407                         encode_uleb128 (op->val, p, &p);
408                         break;
409                 case DW_CFA_def_cfa_register:
410                         *p ++ = op->op;
411                         encode_uleb128 (reg, p, &p);
412                         break;
413                 case DW_CFA_same_value:
414                         *p ++ = op->op;
415                         encode_uleb128 (reg, p, &p);
416                         break;
417                 case DW_CFA_offset:
418                         if (reg > 63) {
419                                 *p ++ = DW_CFA_offset_extended_sf;
420                                 encode_uleb128 (reg, p, &p);
421                                 encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
422                         } else {
423                                 *p ++ = DW_CFA_offset | reg;
424                                 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
425                         }
426                         break;
427                 case DW_CFA_remember_state:
428                 case DW_CFA_restore_state:
429                         *p ++ = op->op;
430                         break;
431                 case DW_CFA_mono_advance_loc:
432                         /* Only one location is supported */
433                         g_assert (op->val == 0);
434                         *p ++ = op->op;
435                         break;
436                 default:
437                         g_assert_not_reached ();
438                         break;
439                 }
440         }
441         
442         g_assert (p - buf < 4096);
443         *out_len = p - buf;
444         res = g_malloc (p - buf);
445         memcpy (res, buf, p - buf);
446         g_free (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
502         p = unwind_info;
503         pos = 0;
504         cfa_reg = -1;
505         cfa_offset = -1;
506         state_stack_pos = 0;
507         while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
508                 int op = *p & 0xc0;
509
510                 switch (op) {
511                 case DW_CFA_advance_loc:
512                         UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
513                         pos += *p & 0x3f;
514                         p ++;
515                         break;
516                 case DW_CFA_offset:
517                         reg = *p & 0x3f;
518                         p ++;
519                         reg_saved [reg] = TRUE;
520                         locations [reg].loc_type = LOC_OFFSET;
521                         locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
522                         break;
523                 case 0: {
524                         int ext_op = *p;
525                         p ++;
526                         switch (ext_op) {
527                         case DW_CFA_def_cfa:
528                                 cfa_reg = decode_uleb128 (p, &p);
529                                 cfa_offset = decode_uleb128 (p, &p);
530                                 break;
531                         case DW_CFA_def_cfa_offset:
532                                 cfa_offset = decode_uleb128 (p, &p);
533                                 break;
534                         case DW_CFA_def_cfa_register:
535                                 cfa_reg = decode_uleb128 (p, &p);
536                                 break;
537                         case DW_CFA_offset_extended_sf:
538                                 reg = decode_uleb128 (p, &p);
539                                 offset = decode_sleb128 (p, &p);
540                                 g_assert (reg < NUM_REGS);
541                                 reg_saved [reg] = TRUE;
542                                 locations [reg].loc_type = LOC_OFFSET;
543                                 locations [reg].offset = offset * DWARF_DATA_ALIGN;
544                                 break;
545                         case DW_CFA_offset_extended:
546                                 reg = decode_uleb128 (p, &p);
547                                 offset = decode_uleb128 (p, &p);
548                                 g_assert (reg < NUM_REGS);
549                                 reg_saved [reg] = TRUE;
550                                 locations [reg].loc_type = LOC_OFFSET;
551                                 locations [reg].offset = offset * DWARF_DATA_ALIGN;
552                                 break;
553                         case DW_CFA_same_value:
554                                 reg = decode_uleb128 (p, &p);
555                                 locations [reg].loc_type = LOC_SAME;
556                                 break;
557                         case DW_CFA_advance_loc1:
558                                 pos += *p;
559                                 p += 1;
560                                 break;
561                         case DW_CFA_advance_loc2:
562                                 pos += read16 (p);
563                                 p += 2;
564                                 break;
565                         case DW_CFA_advance_loc4:
566                                 pos += read32 (p);
567                                 p += 4;
568                                 break;
569                         case DW_CFA_remember_state:
570                                 g_assert (state_stack_pos == 0);
571                                 memcpy (&state_stack [0].locations, &locations, sizeof (locations));
572                                 memcpy (&state_stack [0].reg_saved, &reg_saved, sizeof (reg_saved));
573                                 state_stack [0].cfa_reg = cfa_reg;
574                                 state_stack [0].cfa_offset = cfa_offset;
575                                 state_stack_pos ++;
576                                 break;
577                         case DW_CFA_restore_state:
578                                 g_assert (state_stack_pos == 1);
579                                 state_stack_pos --;
580                                 memcpy (&locations, &state_stack [0].locations, sizeof (locations));
581                                 memcpy (&reg_saved, &state_stack [0].reg_saved, sizeof (reg_saved));
582                                 cfa_reg = state_stack [0].cfa_reg;
583                                 cfa_offset = state_stack [0].cfa_offset;
584                                 break;
585                         case DW_CFA_mono_advance_loc:
586                                 g_assert (mark_locations [0]);
587                                 pos = mark_locations [0] - start_ip;
588                                 break;
589                         default:
590                                 g_assert_not_reached ();
591                         }
592                         break;
593                 }
594                 default:
595                         g_assert_not_reached ();
596                 }
597         }
598
599         if (save_locations)
600                 memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));
601
602         g_assert (cfa_reg != -1);
603         cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
604         for (i = 0; i < NUM_REGS; ++i) {
605                 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
606                         int hreg = mono_dwarf_reg_to_hw_reg (i);
607                         g_assert (hreg < nregs);
608                         regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
609                         if (save_locations && hreg < save_locations_len)
610                                 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
611                 }
612         }
613
614         *out_cfa = cfa_val;
615 }
616
617 void
618 mono_unwind_init (void)
619 {
620         mono_mutex_init_recursive (&unwind_mutex);
621
622         mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
623 }
624
625 void
626 mono_unwind_cleanup (void)
627 {
628         int i;
629
630         mono_mutex_destroy (&unwind_mutex);
631
632         if (!cached_info)
633                 return;
634
635         for (i = 0; i < cached_info_next; ++i) {
636                 MonoUnwindInfo *cached = cached_info [i];
637
638                 g_free (cached);
639         }
640
641         g_free (cached_info);
642 }
643
644 /*
645  * mono_cache_unwind_info
646  *
647  *   Save UNWIND_INFO in the unwind info cache and return an id which can be passed
648  * to mono_get_cached_unwind_info to get a cached copy of the info.
649  * A copy is made of the unwind info.
650  * This function is useful for two reasons:
651  * - many methods have the same unwind info
652  * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
653  */
654 guint32
655 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
656 {
657         int i;
658         MonoUnwindInfo *info;
659
660         unwind_lock ();
661
662         if (cached_info == NULL) {
663                 cached_info_size = 16;
664                 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
665         }
666
667         for (i = 0; i < cached_info_next; ++i) {
668                 MonoUnwindInfo *cached = cached_info [i];
669
670                 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
671                         unwind_unlock ();
672                         return i;
673                 }
674         }
675
676         info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
677         info->len = unwind_info_len;
678         memcpy (&info->info, unwind_info, unwind_info_len);
679
680         i = cached_info_next;
681         
682         if (cached_info_next >= cached_info_size) {
683                 MonoUnwindInfo **old_table, **new_table;
684
685                 /*
686                  * Avoid freeing the old table so mono_get_cached_unwind_info ()
687                  * doesn't need locks/hazard pointers.
688                  */
689
690                 old_table = cached_info;
691                 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
692
693                 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
694
695                 mono_memory_barrier ();
696
697                 cached_info = new_table;
698
699                 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
700
701                 cached_info_size *= 2;
702         }
703
704         cached_info [cached_info_next ++] = info;
705
706         unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
707
708         unwind_unlock ();
709         return i;
710 }
711
712 /*
713  * This function is signal safe.
714  */
715 guint8*
716 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
717 {
718         MonoUnwindInfo **table;
719         MonoUnwindInfo *info;
720         guint8 *data;
721
722         /*
723          * This doesn't need any locks/hazard pointers,
724          * since new tables are copies of the old ones.
725          */
726         table = cached_info;
727
728         info = table [index];
729
730         *unwind_info_len = info->len;
731         data = info->info;
732
733         return data;
734 }
735
736 /*
737  * mono_unwind_get_dwarf_data_align:
738  *
739  *   Return the data alignment used by the encoded unwind information.
740  */
741 int
742 mono_unwind_get_dwarf_data_align (void)
743 {
744         return DWARF_DATA_ALIGN;
745 }
746
747 /*
748  * mono_unwind_get_dwarf_pc_reg:
749  *
750  *   Return the dwarf register number of the register holding the ip of the
751  * previous frame.
752  */
753 int
754 mono_unwind_get_dwarf_pc_reg (void)
755 {
756         return DWARF_PC_REG;
757 }
758
759 static void
760 decode_cie_op (guint8 *p, guint8 **endp)
761 {
762         int op = *p & 0xc0;
763
764         switch (op) {
765         case DW_CFA_advance_loc:
766                 p ++;
767                 break;
768         case DW_CFA_offset:
769                 p ++;
770                 decode_uleb128 (p, &p);
771                 break;
772         case 0: {
773                 int ext_op = *p;
774                 p ++;
775                 switch (ext_op) {
776                 case DW_CFA_def_cfa:
777                         decode_uleb128 (p, &p);
778                         decode_uleb128 (p, &p);
779                         break;
780                 case DW_CFA_def_cfa_offset:
781                         decode_uleb128 (p, &p);
782                         break;
783                 case DW_CFA_def_cfa_register:
784                         decode_uleb128 (p, &p);
785                         break;
786                 case DW_CFA_advance_loc4:
787                         p += 4;
788                         break;
789                 case DW_CFA_offset_extended_sf:
790                         decode_uleb128 (p, &p);
791                         decode_uleb128 (p, &p);
792                         break;
793                 default:
794                         g_assert_not_reached ();
795                 }
796                 break;
797         }
798         default:
799                 g_assert_not_reached ();
800         }
801
802         *endp = p;
803 }
804
805 static gint64
806 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
807 {
808         gint64 res;
809
810         switch (encoding & 0xf) {
811         case DW_EH_PE_sdata8:
812                 res = *(gint64*)p;
813                 p += 8;
814                 break;
815         case DW_EH_PE_sdata4:
816                 res = *(gint32*)p;
817                 p += 4;
818                 break;
819         default:
820                 g_assert_not_reached ();
821         }
822
823         *endp = p;
824         return res;
825 }
826
827 /*
828  * decode_lsda:
829  *
830  *   Decode the Mono specific Language Specific Data Area generated by LLVM.
831  */
832 static void
833 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
834 {
835         guint8 *p;
836         int i, ncall_sites, this_encoding;
837         guint32 mono_magic, version;
838
839         p = lsda;
840
841         /* This is the modified LSDA generated by the LLVM mono branch */
842         mono_magic = decode_uleb128 (p, &p);
843         g_assert (mono_magic == 0x4d4fef4f);
844         version = decode_uleb128 (p, &p);
845         g_assert (version == 1);
846         this_encoding = *p;
847         p ++;
848         if (this_encoding == DW_EH_PE_udata4) {
849                 gint32 op, reg, offset;
850
851                 /* 'this' location */
852                 op = *p;
853                 g_assert (op == DW_OP_bregx);
854                 p ++;
855                 reg = decode_uleb128 (p, &p);
856                 offset = decode_sleb128 (p, &p);
857
858                 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
859                 *this_offset = offset;
860         } else {
861                 g_assert (this_encoding == DW_EH_PE_omit);
862
863                 *this_reg = -1;
864                 *this_offset = -1;
865         }
866         ncall_sites = decode_uleb128 (p, &p);
867         p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
868
869         if (ex_info) {
870                 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
871                 *ex_info_len = ncall_sites;
872         }
873         if (type_info)
874                 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
875
876         for (i = 0; i < ncall_sites; ++i) {
877                 int block_start_offset, block_size, landing_pad;
878                 guint8 *tinfo;
879
880                 block_start_offset = read32 (p);
881                 p += sizeof (gint32);
882                 block_size = read32 (p);
883                 p += sizeof (gint32);
884                 landing_pad = read32 (p);
885                 p += sizeof (gint32);
886                 tinfo = p;
887                 p += sizeof (gint32);
888
889                 g_assert (landing_pad);
890                 g_assert (((size_t)tinfo % 4) == 0);
891                 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
892
893                 if (ex_info) {
894                         if (*type_info)
895                                 (*type_info) [i] = tinfo;
896                         (*ex_info)[i].try_start = code + block_start_offset;
897                         (*ex_info)[i].try_end = code + block_start_offset + block_size;
898                         (*ex_info)[i].handler_start = code + landing_pad;
899                 }
900         }
901 }
902
903 /*
904  * mono_unwind_decode_fde:
905  *
906  *   Decode a DWARF FDE entry, returning the unwind opcodes.
907  * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
908  * only try_start, try_end and handler_start is set.
909  * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
910  * LSDA.
911  */
912 guint8*
913 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)
914 {
915         guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
916         gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
917         gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
918         gint32 i, cie_aug_len, buf_len;
919         char *cie_aug_str;
920         guint8 *buf;
921         gboolean has_fde_augmentation = FALSE;
922
923         /* 
924          * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
925          */
926
927         *type_info = NULL;
928         *this_reg = -1;
929         *this_offset = -1;
930
931         /* Decode FDE */
932
933         p = fde;
934         // FIXME: Endianess ?
935         fde_len = *(guint32*)p;
936         g_assert (fde_len != 0xffffffff && fde_len != 0);
937         p += 4;
938         cie_offset = *(guint32*)p;
939         cie = p - cie_offset;
940         p += 4;
941         fde_current = p;
942
943         /* Decode CIE */
944         p = cie;
945         cie_len = *(guint32*)p;
946         p += 4;
947         cie_id = *(guint32*)p;
948         g_assert (cie_id == 0);
949         p += 4;
950         cie_version = *p;
951         g_assert (cie_version == 1);
952         p += 1;
953         cie_aug_str = (char*)p;
954         p += strlen (cie_aug_str) + 1;
955         code_align = decode_uleb128 (p, &p);
956         data_align = decode_sleb128 (p, &p);
957         return_reg = decode_uleb128 (p, &p);
958         if (strstr (cie_aug_str, "z")) {
959                 guint8 *cie_aug;
960                 guint32 p_encoding;
961
962                 cie_aug_len = decode_uleb128 (p, &p);
963
964                 has_fde_augmentation = TRUE;
965
966                 cie_aug = p;
967                 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
968                         switch (cie_aug_str [i]) {
969                         case 'z':
970                                 break;
971                         case 'P':
972                                 p_encoding = *p;
973                                 p ++;
974                                 read_encoded_val (p_encoding, p, &p);
975                                 break;
976                         case 'L':
977                                 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
978                                 p ++;
979                                 break;
980                         case 'R':
981                                 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
982                                 p ++;
983                                 break;
984                         default:
985                                 g_assert_not_reached ();
986                                 break;
987                         }
988                 }
989                         
990                 p = cie_aug;
991                 p += cie_aug_len;
992         }
993         cie_cfi = p;
994
995         /* Continue decoding FDE */
996         p = fde_current;
997         /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
998         pc_begin = *(gint32*)p;
999         code = p + pc_begin;
1000         p += 4;
1001         pc_range = *(guint32*)p;
1002         p += 4;
1003         if (has_fde_augmentation) {
1004                 aug_len = decode_uleb128 (p, &p);
1005                 fde_aug = p;
1006                 p += aug_len;
1007         } else {
1008                 aug_len = 0;
1009         }
1010         fde_cfi = p;
1011         fde_data_len = fde + 4 + fde_len - p;
1012
1013         if (code_len)
1014                 *code_len = pc_range;
1015
1016         if (ex_info) {
1017                 *ex_info = NULL;
1018                 *ex_info_len = 0;
1019         }
1020
1021         /* Decode FDE augmention */
1022         if (aug_len) {
1023                 gint32 lsda_offset;
1024                 guint8 *lsda;
1025
1026                 /* sdata|pcrel encoding */
1027                 if (aug_len == 4)
1028                         lsda_offset = read32 (fde_aug);
1029                 else if (aug_len == 8)
1030                         lsda_offset = *(gint64*)fde_aug;
1031                 else
1032                         g_assert_not_reached ();
1033                 if (lsda_offset != 0) {
1034                         lsda = fde_aug + lsda_offset;
1035
1036                         decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
1037                 }
1038         }
1039
1040         /* Make sure the FDE uses the same constants as we do */
1041         g_assert (code_align == 1);
1042         g_assert (data_align == DWARF_DATA_ALIGN);
1043         g_assert (return_reg == DWARF_PC_REG);
1044
1045         buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
1046         buf = g_malloc0 (buf_len);
1047
1048         i = 0;
1049         p = cie_cfi;
1050         while (p < cie + cie_len + 4) {
1051                 if (*p == DW_CFA_nop)
1052                         break;
1053                 else
1054                         decode_cie_op (p, &p);
1055         }
1056         memcpy (buf + i, cie_cfi, p - cie_cfi);
1057         i += p - cie_cfi;
1058
1059         p = fde_cfi;
1060         while (p < fde + fde_len + 4) {
1061                 if (*p == DW_CFA_nop)
1062                         break;
1063                 else
1064                         decode_cie_op (p, &p);
1065         }
1066         memcpy (buf + i, fde_cfi, p - fde_cfi);
1067         i += p - fde_cfi;
1068         g_assert (i <= buf_len);
1069
1070         *out_len = i;
1071
1072         return g_realloc (buf, i);
1073 }
1074
1075 /*
1076  * mono_unwind_decode_mono_fde:
1077  *
1078  *   Decode an FDE entry in the LLVM emitted mono EH frame.
1079  * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
1080  * only try_start, try_end and handler_start is set.
1081  * info->type_info is set to a malloc-ed array containing the ttype table from the
1082  * LSDA.
1083  */
1084 void
1085 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
1086 {
1087         guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
1088         int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
1089         gint32 code_align, data_align, return_reg, pers_encoding;
1090
1091         memset (res, 0, sizeof (*res));
1092         res->this_reg = -1;
1093         res->this_offset = -1;
1094
1095         /* fde points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
1096         p = fde;
1097         has_aug = *p;
1098         p ++;
1099         if (has_aug) {
1100                 aug_len = read32 (p);
1101                 p += 4;
1102         } else {
1103                 aug_len = 0;
1104         }
1105         fde_aug = p;
1106         p += aug_len;
1107         fde_cfi = p;
1108
1109         if (has_aug) {
1110                 guint8 *lsda;
1111
1112                 /* The LSDA is embedded directly into the FDE */
1113                 lsda = fde_aug;
1114
1115                 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1116         }
1117
1118         /* Decode CIE */
1119         p = cie;
1120         code_align = decode_uleb128 (p, &p);
1121         data_align = decode_sleb128 (p, &p);
1122         return_reg = decode_uleb128 (p, &p);
1123         pers_encoding = *p;
1124         p ++;
1125         if (pers_encoding != DW_EH_PE_omit)
1126                 read_encoded_val (pers_encoding, p, &p);
1127
1128         cie_cfi = p;
1129
1130         /* Make sure the FDE uses the same constants as we do */
1131         g_assert (code_align == 1);
1132         g_assert (data_align == DWARF_DATA_ALIGN);
1133         g_assert (return_reg == DWARF_PC_REG);
1134
1135         /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1136         p = cie_cfi;
1137         while (TRUE) {
1138                 if (*p == DW_CFA_nop)
1139                         break;
1140                 else
1141                         decode_cie_op (p, &p);
1142         }
1143         cie_cfi_len = p - cie_cfi;
1144         fde_cfi_len = (fde + fde_len - fde_cfi);
1145
1146         buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1147         memcpy (buf, cie_cfi, cie_cfi_len);
1148         memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1149
1150         res->unw_info_len = cie_cfi_len + fde_cfi_len;
1151         res->unw_info = buf;
1152 }
1153
1154 /*
1155  * mono_unwind_get_cie_program:
1156  *
1157  *   Get the unwind bytecode for the DWARF CIE.
1158  */
1159 GSList*
1160 mono_unwind_get_cie_program (void)
1161 {
1162 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1163         return mono_arch_get_cie_program ();
1164 #else
1165         return NULL;
1166 #endif
1167 }