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