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