Implement precise scanning of registers by scanning the stack slots where they are...
[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  * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
323  * On return, the nth entry will point to the address of the stack slot where register
324  * N was saved, or NULL, if it was not saved by this frame.
325  * This function is signal safe.
326  */
327 void
328 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len, 
329                                    guint8 *start_ip, guint8 *end_ip, guint8 *ip, mgreg_t *regs, int nregs,
330                                    mgreg_t **save_locations, int save_locations_len,
331                                    guint8 **out_cfa)
332 {
333         Loc locations [NUM_REGS];
334         int i, pos, reg, cfa_reg, cfa_offset;
335         guint8 *p;
336         guint8 *cfa_val;
337
338         for (i = 0; i < NUM_REGS; ++i)
339                 locations [i].loc_type = LOC_SAME;
340
341         p = unwind_info;
342         pos = 0;
343         cfa_reg = -1;
344         cfa_offset = -1;
345         while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
346                 int op = *p & 0xc0;
347
348                 switch (op) {
349                 case DW_CFA_advance_loc:
350                         UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
351                         pos += *p & 0x3f;
352                         p ++;
353                         break;
354                 case DW_CFA_offset:
355                         reg = *p & 0x3f;
356                         p ++;
357                         locations [reg].loc_type = LOC_OFFSET;
358                         locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
359                         break;
360                 case 0: {
361                         int ext_op = *p;
362                         p ++;
363                         switch (ext_op) {
364                         case DW_CFA_def_cfa:
365                                 cfa_reg = decode_uleb128 (p, &p);
366                                 cfa_offset = decode_uleb128 (p, &p);
367                                 break;
368                         case DW_CFA_def_cfa_offset:
369                                 cfa_offset = decode_uleb128 (p, &p);
370                                 break;
371                         case DW_CFA_def_cfa_register:
372                                 cfa_reg = decode_uleb128 (p, &p);
373                                 break;
374                         case DW_CFA_offset_extended_sf:
375                                 reg = decode_uleb128 (p, &p);
376                                 locations [reg].loc_type = LOC_OFFSET;
377                                 locations [reg].offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
378                                 break;
379                         case DW_CFA_advance_loc4:
380                                 pos += read32 (p);
381                                 p += 4;
382                                 break;
383                         default:
384                                 g_assert_not_reached ();
385                         }
386                         break;
387                 }
388                 default:
389                         g_assert_not_reached ();
390                 }
391         }
392
393         if (save_locations)
394                 memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));
395
396         cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
397         for (i = 0; i < NUM_REGS; ++i) {
398                 if (locations [i].loc_type == LOC_OFFSET) {
399                         int hreg = mono_dwarf_reg_to_hw_reg (i);
400                         g_assert (hreg < nregs);
401                         regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
402                         if (save_locations && hreg < save_locations_len)
403                                 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
404                 }
405         }
406
407         *out_cfa = cfa_val;
408 }
409
410 void
411 mono_unwind_init (void)
412 {
413         InitializeCriticalSection (&unwind_mutex);
414
415         mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
416 }
417
418 void
419 mono_unwind_cleanup (void)
420 {
421         int i;
422
423         DeleteCriticalSection (&unwind_mutex);
424
425         if (!cached_info)
426                 return;
427
428         for (i = 0; i < cached_info_next; ++i) {
429                 MonoUnwindInfo *cached = cached_info [i];
430
431                 g_free (cached);
432         }
433
434         g_free (cached_info);
435 }
436
437 /*
438  * mono_cache_unwind_info
439  *
440  *   Save UNWIND_INFO in the unwind info cache and return an id which can be passed
441  * to mono_get_cached_unwind_info to get a cached copy of the info.
442  * A copy is made of the unwind info.
443  * This function is useful for two reasons:
444  * - many methods have the same unwind info
445  * - MonoJitInfo->used_regs is an int so it can't store the pointer to the unwind info
446  */
447 guint32
448 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
449 {
450         int i;
451         MonoUnwindInfo *info;
452
453         unwind_lock ();
454
455         if (cached_info == NULL) {
456                 cached_info_size = 16;
457                 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
458         }
459
460         for (i = 0; i < cached_info_next; ++i) {
461                 MonoUnwindInfo *cached = cached_info [i];
462
463                 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
464                         unwind_unlock ();
465                         return i;
466                 }
467         }
468
469         info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
470         info->len = unwind_info_len;
471         memcpy (&info->info, unwind_info, unwind_info_len);
472
473         i = cached_info_next;
474         
475         if (cached_info_next >= cached_info_size) {
476                 MonoUnwindInfo **old_table, **new_table;
477
478                 /*
479                  * Have to resize the table, while synchronizing with 
480                  * mono_get_cached_unwind_info () using hazard pointers.
481                  */
482
483                 old_table = cached_info;
484                 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
485
486                 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
487
488                 mono_memory_barrier ();
489
490                 cached_info = new_table;
491
492                 mono_memory_barrier ();
493
494                 mono_thread_hazardous_free_or_queue (old_table, g_free);
495
496                 cached_info_size *= 2;
497         }
498
499         cached_info [cached_info_next ++] = info;
500
501         unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
502
503         unwind_unlock ();
504         return i;
505 }
506
507 static gpointer
508 get_hazardous_pointer (gpointer volatile *pp, MonoThreadHazardPointers *hp, int hazard_index)
509 {
510         gpointer p;
511
512         for (;;) {
513                 /* Get the pointer */
514                 p = *pp;
515                 /* If we don't have hazard pointers just return the
516                    pointer. */
517                 if (!hp)
518                         return p;
519                 /* Make it hazardous */
520                 mono_hazard_pointer_set (hp, hazard_index, p);
521                 /* Check that it's still the same.  If not, try
522                    again. */
523                 if (*pp != p) {
524                         mono_hazard_pointer_clear (hp, hazard_index);
525                         continue;
526                 }
527                 break;
528         }
529
530         return p;
531 }
532
533 /*
534  * This function is signal safe.
535  */
536 guint8*
537 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
538 {
539         MonoUnwindInfo **table;
540         MonoUnwindInfo *info;
541         guint8 *data;
542         MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
543
544         table = get_hazardous_pointer ((gpointer volatile*)&cached_info, hp, 0);
545
546         info = table [index];
547
548         *unwind_info_len = info->len;
549         data = info->info;
550
551         mono_hazard_pointer_clear (hp, 0);
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                 default:
610                         g_assert_not_reached ();
611                 }
612                 break;
613         }
614         default:
615                 g_assert_not_reached ();
616         }
617
618         *endp = p;
619 }
620
621 /* Pointer Encoding in the .eh_frame */
622 enum {
623         DW_EH_PE_absptr = 0x00,
624         DW_EH_PE_omit = 0xff,
625
626         DW_EH_PE_udata4 = 0x03,
627         DW_EH_PE_sdata4 = 0x0b,
628         DW_EH_PE_sdata8 = 0x0c,
629
630         DW_EH_PE_pcrel = 0x10,
631         DW_EH_PE_textrel = 0x20,
632         DW_EH_PE_datarel = 0x30,
633         DW_EH_PE_funcrel = 0x40,
634         DW_EH_PE_aligned = 0x50,
635
636         DW_EH_PE_indirect = 0x80
637 };
638
639 static gint64
640 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
641 {
642         gint64 res;
643
644         switch (encoding & 0xf) {
645         case DW_EH_PE_sdata8:
646                 res = *(gint64*)p;
647                 p += 8;
648                 break;
649         case DW_EH_PE_sdata4:
650                 res = *(gint32*)p;
651                 p += 4;
652                 break;
653         default:
654                 g_assert_not_reached ();
655         }
656
657         *endp = p;
658         return res;
659 }
660
661 /*
662  * decode_lsda:
663  *
664  *   Decode the Language Specific Data Area generated by LLVM.
665  */
666 static void
667 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
668 {
669         gint32 ttype_offset, call_site_length;
670         gint32 ttype_encoding, call_site_encoding;
671         guint8 *ttype, *action_table, *call_site, *p;
672         int i, ncall_sites;
673
674         /*
675          * LLVM generates a c++ style LSDA, which can be decoded by looking at
676          * eh_personality.cc in gcc.
677          */
678         p = lsda;
679
680         if (*p == DW_EH_PE_udata4) {
681                 /* This is the modified LSDA generated by the LLVM mono branch */
682                 guint32 mono_magic, version;
683                 gint32 op, reg, offset;
684
685                 p ++;
686                 mono_magic = decode_uleb128 (p, &p);
687                 g_assert (mono_magic == 0x4d4fef4f);
688                 version = decode_uleb128 (p, &p);
689                 g_assert (version == 1);
690
691                 /* 'this' location */
692                 op = *p;
693                 g_assert (op == DW_OP_bregx);
694                 p ++;
695                 reg = decode_uleb128 (p, &p);
696                 offset = decode_sleb128 (p, &p);
697
698                 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
699                 *this_offset = offset;
700         } else {
701                 /* Read @LPStart */
702                 g_assert (*p == DW_EH_PE_omit);
703                 p ++;
704
705                 *this_reg = -1;
706                 *this_offset = -1;
707         }
708
709         /* Read @TType */
710         ttype_encoding = *p;
711         p ++;
712         ttype_offset = decode_uleb128 (p, &p);
713         ttype = p + ttype_offset;
714
715         /* Read call-site table */
716         call_site_encoding = *p;
717         g_assert (call_site_encoding == DW_EH_PE_udata4);
718         p ++;
719         call_site_length = decode_uleb128 (p, &p);
720         call_site = p;
721         p += call_site_length;
722         action_table = p;
723
724         /* Calculate the size of our table */
725         ncall_sites = 0;
726         p = call_site;
727         while (p < action_table) {
728                 int block_start_offset, block_size, landing_pad, action_offset;
729
730                 block_start_offset = read32 (p);
731                 p += sizeof (gint32);
732                 block_size = read32 (p);
733                 p += sizeof (gint32);
734                 landing_pad = read32 (p);
735                 p += sizeof (gint32);
736                 action_offset = decode_uleb128 (p, &p);
737
738                 /* landing_pad == 0 means the region has no landing pad */
739                 if (landing_pad)
740                         ncall_sites ++;
741         }
742
743         if (ex_info) {
744                 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
745                 *ex_info_len = ncall_sites;
746         }
747
748         if (type_info)
749                 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
750
751         p = call_site;
752         i = 0;
753         while (p < action_table) {
754                 int block_start_offset, block_size, landing_pad, action_offset, type_offset;
755                 guint8 *action, *tinfo;
756
757                 block_start_offset = read32 (p);
758                 p += sizeof (gint32);
759                 block_size = read32 (p);
760                 p += sizeof (gint32);
761                 landing_pad = read32 (p);
762                 p += sizeof (gint32);
763                 action_offset = decode_uleb128 (p, &p);
764
765                 action = action_table + action_offset - 1;
766
767                 type_offset = decode_sleb128 (action, &action);
768
769                 if (landing_pad) {
770                         //printf ("BLOCK: %p-%p %p, %d\n", code + block_start_offset, code + block_start_offset + block_size, code + landing_pad, action_offset);
771
772                         g_assert (ttype_offset);
773
774                         if (ttype_encoding == DW_EH_PE_absptr) {
775                                 guint8 *ttype_entry = (ttype - (type_offset * sizeof (gpointer)));
776                                 tinfo = *(gpointer*)ttype_entry;
777                         } else if (ttype_encoding == (DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4)) {
778                                 guint8 *ttype_entry = (ttype - (type_offset * 4));
779                                 gint32 offset = *(gint32*)ttype_entry;
780                                 guint8 *stub = ttype_entry + offset;
781                                 tinfo = *(gpointer*)stub;
782                         } else if (ttype_encoding == (DW_EH_PE_pcrel | DW_EH_PE_sdata4)) {
783                                 guint8 *ttype_entry = (ttype - (type_offset * 4));
784                                 gint32 offset = *(gint32*)ttype_entry;
785                                 tinfo = ttype_entry + offset;
786                         } else if (ttype_encoding == DW_EH_PE_udata4) {
787                                 /* Embedded directly */
788                                 guint8 *ttype_entry = (ttype - (type_offset * 4));
789                                 tinfo = ttype_entry;
790                         } else {
791                                 g_assert_not_reached ();
792                         }
793
794                         if (ex_info) {
795                                 if (*type_info)
796                                         (*type_info) [i] = tinfo;
797                                 (*ex_info)[i].try_start = code + block_start_offset;
798                                 (*ex_info)[i].try_end = code + block_start_offset + block_size;
799                                 (*ex_info)[i].handler_start = code + landing_pad;
800
801                         }
802                         i ++;
803                 }
804         }
805 }
806
807 /*
808  * mono_unwind_decode_fde:
809  *
810  *   Decode a DWARF FDE entry, returning the unwind opcodes.
811  * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
812  * only try_start, try_end and handler_start is set.
813  * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
814  * LSDA.
815  */
816 guint8*
817 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)
818 {
819         guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
820         gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
821         gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
822         gint32 i, cie_aug_len, buf_len;
823         char *cie_aug_str;
824         guint8 *buf;
825         gboolean has_fde_augmentation = FALSE;
826
827         /* 
828          * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
829          */
830
831         *type_info = NULL;
832         *this_reg = -1;
833         *this_offset = -1;
834
835         /* Decode FDE */
836
837         p = fde;
838         // FIXME: Endianess ?
839         fde_len = *(guint32*)p;
840         g_assert (fde_len != 0xffffffff && fde_len != 0);
841         p += 4;
842         cie_offset = *(guint32*)p;
843         cie = p - cie_offset;
844         p += 4;
845         fde_current = p;
846
847         /* Decode CIE */
848         p = cie;
849         cie_len = *(guint32*)p;
850         p += 4;
851         cie_id = *(guint32*)p;
852         g_assert (cie_id == 0);
853         p += 4;
854         cie_version = *p;
855         g_assert (cie_version == 1);
856         p += 1;
857         cie_aug_str = (char*)p;
858         p += strlen (cie_aug_str) + 1;
859         code_align = decode_uleb128 (p, &p);
860         data_align = decode_sleb128 (p, &p);
861         return_reg = decode_uleb128 (p, &p);
862         if (strstr (cie_aug_str, "z")) {
863                 guint8 *cie_aug;
864                 guint32 p_encoding;
865
866                 cie_aug_len = decode_uleb128 (p, &p);
867
868                 has_fde_augmentation = TRUE;
869
870                 cie_aug = p;
871                 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
872                         switch (cie_aug_str [i]) {
873                         case 'z':
874                                 break;
875                         case 'P':
876                                 p_encoding = *p;
877                                 p ++;
878                                 read_encoded_val (p_encoding, p, &p);
879                                 break;
880                         case 'L':
881                                 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
882                                 p ++;
883                                 break;
884                         case 'R':
885                                 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
886                                 p ++;
887                                 break;
888                         default:
889                                 g_assert_not_reached ();
890                                 break;
891                         }
892                 }
893                         
894                 p = cie_aug;
895                 p += cie_aug_len;
896         }
897         cie_cfi = p;
898
899         /* Continue decoding FDE */
900         p = fde_current;
901         /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
902         pc_begin = *(gint32*)p;
903         code = p + pc_begin;
904         p += 4;
905         pc_range = *(guint32*)p;
906         p += 4;
907         if (has_fde_augmentation) {
908                 aug_len = decode_uleb128 (p, &p);
909                 fde_aug = p;
910                 p += aug_len;
911         } else {
912                 aug_len = 0;
913         }
914         fde_cfi = p;
915         fde_data_len = fde + 4 + fde_len - p;
916
917         if (code_len)
918                 *code_len = pc_range;
919
920         if (ex_info) {
921                 *ex_info = NULL;
922                 *ex_info_len = 0;
923         }
924
925         /* Decode FDE augmention */
926         if (aug_len) {
927                 gint32 lsda_offset;
928                 guint8 *lsda;
929
930                 /* sdata|pcrel encoding */
931                 if (aug_len == 4)
932                         lsda_offset = read32 (fde_aug);
933                 else if (aug_len == 8)
934                         lsda_offset = *(gint64*)fde_aug;
935                 else
936                         g_assert_not_reached ();
937                 if (lsda_offset != 0) {
938                         lsda = fde_aug + lsda_offset;
939
940                         decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
941                 }
942         }
943
944         /* Make sure the FDE uses the same constants as we do */
945         g_assert (code_align == 1);
946         g_assert (data_align == DWARF_DATA_ALIGN);
947         g_assert (return_reg == DWARF_PC_REG);
948
949         buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
950         buf = g_malloc0 (buf_len);
951
952         i = 0;
953         p = cie_cfi;
954         while (p < cie + cie_len + 4) {
955                 if (*p == DW_CFA_nop)
956                         break;
957                 else
958                         decode_cie_op (p, &p);
959         }
960         memcpy (buf + i, cie_cfi, p - cie_cfi);
961         i += p - cie_cfi;
962
963         p = fde_cfi;
964         while (p < fde + fde_len + 4) {
965                 if (*p == DW_CFA_nop)
966                         break;
967                 else
968                         decode_cie_op (p, &p);
969         }
970         memcpy (buf + i, fde_cfi, p - fde_cfi);
971         i += p - fde_cfi;
972         g_assert (i <= buf_len);
973
974         *out_len = i;
975
976         return g_realloc (buf, i);
977 }
978
979 /*
980  * mono_unwind_decode_mono_fde:
981  *
982  *   Decode an FDE entry in the LLVM emitted mono EH frame.
983  * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
984  * only try_start, try_end and handler_start is set.
985  * info->type_info is set to a malloc-ed array containing the ttype table from the
986  * LSDA.
987  */
988 void
989 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
990 {
991         guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
992         int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
993         gint32 code_align, data_align, return_reg, pers_encoding;
994
995         memset (res, 0, sizeof (*res));
996         res->this_reg = -1;
997         res->this_offset = -1;
998
999         /* fde points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
1000         p = fde;
1001         has_aug = *p;
1002         p ++;
1003         if (has_aug) {
1004                 aug_len = read32 (p);
1005                 p += 4;
1006         } else {
1007                 aug_len = 0;
1008         }
1009         fde_aug = p;
1010         p += aug_len;
1011         fde_cfi = p;
1012
1013         if (has_aug) {
1014                 guint8 *lsda;
1015
1016                 /* The LSDA is embedded directly into the FDE */
1017                 lsda = fde_aug;
1018
1019                 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1020         }
1021
1022         /* Decode CIE */
1023         p = cie;
1024         code_align = decode_uleb128 (p, &p);
1025         data_align = decode_sleb128 (p, &p);
1026         return_reg = decode_uleb128 (p, &p);
1027         pers_encoding = *p;
1028         p ++;
1029         if (pers_encoding != DW_EH_PE_omit)
1030                 read_encoded_val (pers_encoding, p, &p);
1031
1032         cie_cfi = p;
1033
1034         /* Make sure the FDE uses the same constants as we do */
1035         g_assert (code_align == 1);
1036         g_assert (data_align == DWARF_DATA_ALIGN);
1037         g_assert (return_reg == DWARF_PC_REG);
1038
1039         /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1040         p = cie_cfi;
1041         while (TRUE) {
1042                 if (*p == DW_CFA_nop)
1043                         break;
1044                 else
1045                         decode_cie_op (p, &p);
1046         }
1047         cie_cfi_len = p - cie_cfi;
1048         fde_cfi_len = (fde + fde_len - fde_cfi);
1049
1050         buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1051         memcpy (buf, cie_cfi, cie_cfi_len);
1052         memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1053
1054         res->unw_info_len = cie_cfi_len + fde_cfi_len;
1055         res->unw_info = buf;
1056 }
1057
1058 /*
1059  * mono_unwind_get_cie_program:
1060  *
1061  *   Get the unwind bytecode for the DWARF CIE.
1062  */
1063 GSList*
1064 mono_unwind_get_cie_program (void)
1065 {
1066 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1067         return mono_arch_get_cie_program ();
1068 #else
1069         return NULL;
1070 #endif
1071 }