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