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