2 * unwind.c: Stack Unwinding Interface
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2008 Novell, Inc.
11 #include "mini-unwind.h"
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>
31 guint8 info [MONO_ZERO_LEN_ARRAY];
34 #define ALIGN_TO(val,align) ((((size_t)val) + ((align) - 1)) & ~((align) - 1))
36 static mono_mutex_t unwind_mutex;
38 static MonoUnwindInfo **cached_info;
39 static int cached_info_next, cached_info_size;
40 static GSList *cached_info_list;
42 static int unwind_info_size;
44 #define unwind_lock() mono_mutex_lock (&unwind_mutex)
45 #define unwind_unlock() mono_mutex_unlock (&unwind_mutex)
48 static int map_hw_reg_to_dwarf_reg [] = { 0, 2, 1, 3, 7, 6, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
49 #define NUM_REGS AMD64_NREG
50 #define DWARF_DATA_ALIGN (-8)
51 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (AMD64_RIP))
52 #elif defined(TARGET_ARM)
53 // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0040a/IHI0040A_aadwarf.pdf
54 /* Assign d8..d15 to hregs 16..24 */
55 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 264, 265, 266, 267, 268, 269, 270, 271 };
57 #define DWARF_DATA_ALIGN (-4)
58 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
59 #elif defined(TARGET_ARM64)
61 #define DWARF_DATA_ALIGN (-8)
63 #define DWARF_PC_REG 30
64 static int map_hw_reg_to_dwarf_reg [] = {
65 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
66 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
68 72, 73, 74, 75, 76, 77, 78, 79,
70 #elif defined (TARGET_X86)
73 * LLVM seems to generate unwind info where esp is encoded as 5, and ebp as 4, ie see this line:
74 * def ESP : RegisterWithSubRegs<"esp", [SP]>, DwarfRegNum<[-2, 5, 4]>;
75 * in lib/Target/X86/X86RegisterInfo.td in the llvm sources.
77 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 5, 4, 6, 7, 8 };
79 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
82 #define NUM_REGS X86_NREG + 1
83 #define DWARF_DATA_ALIGN (-4)
84 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
85 #elif defined (TARGET_POWERPC)
86 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
87 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
88 9, 10, 11, 12, 13, 14, 15, 16,
89 17, 18, 19, 20, 21, 22, 23, 24,
90 25, 26, 27, 28, 29, 30, 31 };
92 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
93 #define DWARF_PC_REG 108
94 #elif defined (TARGET_S390X)
95 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
97 #define DWARF_DATA_ALIGN (-8)
98 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
99 #elif defined (TARGET_MIPS)
101 static int map_hw_reg_to_dwarf_reg [32] = {
102 0, 1, 2, 3, 4, 5, 6, 7,
103 8, 9, 10, 11, 12, 13, 14, 15,
104 16, 17, 18, 19, 20, 21, 22, 23,
105 24, 25, 26, 27, 28, 29, 30, 31
108 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
109 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
111 static int map_hw_reg_to_dwarf_reg [16];
113 #define DWARF_DATA_ALIGN 0
114 #define DWARF_PC_REG -1
117 static gboolean dwarf_reg_to_hw_reg_inited;
119 static int map_dwarf_reg_to_hw_reg [NUM_REGS];
122 * mono_hw_reg_to_dwarf_reg:
124 * Map the hardware register number REG to the register number used by DWARF.
127 mono_hw_reg_to_dwarf_reg (int reg)
129 #ifdef TARGET_POWERPC
133 g_assert (reg < NUM_REGS);
137 g_assert_not_reached ();
140 return map_hw_reg_to_dwarf_reg [reg];
149 g_assert (NUM_REGS > 0);
150 for (i = 0; i < sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int); ++i) {
151 map_dwarf_reg_to_hw_reg [mono_hw_reg_to_dwarf_reg (i)] = i;
154 #ifdef TARGET_POWERPC
155 map_dwarf_reg_to_hw_reg [DWARF_PC_REG] = ppc_lr;
158 mono_memory_barrier ();
159 dwarf_reg_to_hw_reg_inited = TRUE;
163 mono_dwarf_reg_to_hw_reg (int reg)
165 if (!dwarf_reg_to_hw_reg_inited)
168 return map_dwarf_reg_to_hw_reg [reg];
171 static G_GNUC_UNUSED void
172 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
177 guint8 b = value & 0x7f;
179 if (value != 0) /* more bytes to come */
187 static G_GNUC_UNUSED void
188 encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
191 gboolean negative = (value < 0);
199 /* the following is unnecessary if the
200 * implementation of >>= uses an arithmetic rather
201 * than logical shift for a signed left operand
205 value |= - (1 <<(size - 7));
206 /* sign bit of byte is second high order bit (0x40) */
207 if ((value == 0 && !(byte & 0x40)) ||
208 (value == -1 && (byte & 0x40)))
218 static inline guint32
219 decode_uleb128 (guint8 *buf, guint8 **endbuf)
229 res = res | (((int)(b & 0x7f)) << shift);
241 decode_sleb128 (guint8 *buf, guint8 **endbuf)
251 res = res | (((int)(b & 0x7f)) << shift);
254 if (shift < 32 && (b & 0x40))
255 res |= - (1 << shift);
266 mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len)
269 int pos, reg, offset, cfa_reg, cfa_offset;
273 while (p < unwind_info + unwind_info_len) {
277 case DW_CFA_advance_loc:
284 offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
285 if (reg == DWARF_PC_REG)
286 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, "pc", -offset);
288 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
295 cfa_reg = decode_uleb128 (p, &p);
296 cfa_offset = decode_uleb128 (p, &p);
297 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)), cfa_offset);
299 case DW_CFA_def_cfa_offset:
300 cfa_offset = decode_uleb128 (p, &p);
301 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos, cfa_offset);
303 case DW_CFA_def_cfa_register:
304 cfa_reg = decode_uleb128 (p, &p);
305 printf ("CFA: [%x] def_cfa_reg: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)));
307 case DW_CFA_offset_extended_sf:
308 reg = decode_uleb128 (p, &p);
309 offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
310 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
312 case DW_CFA_same_value:
313 reg = decode_uleb128 (p, &p);
314 printf ("CFA: [%x] same_value: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)));
316 case DW_CFA_advance_loc4:
320 case DW_CFA_remember_state:
321 printf ("CFA: [%x] remember_state\n", pos);
323 case DW_CFA_restore_state:
324 printf ("CFA: [%x] restore_state\n", pos);
326 case DW_CFA_mono_advance_loc:
327 printf ("CFA: [%x] mono_advance_loc\n", pos);
330 g_assert_not_reached ();
335 g_assert_not_reached ();
341 * mono_unwind_ops_encode:
343 * Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
344 * Return a pointer to malloc'ed memory.
347 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
352 guint8 *buf, *p, *res;
354 p = buf = g_malloc0 (4096);
358 for (; l; l = l->next) {
363 /* Convert the register from the hw encoding to the dwarf encoding */
364 reg = mono_hw_reg_to_dwarf_reg (op->reg);
366 if (op->op == DW_CFA_mono_advance_loc) {
367 /* This advances loc to its location */
371 /* Emit an advance_loc if neccesary */
372 while (op->when > loc) {
373 if (op->when - loc > 65536) {
374 *p ++ = DW_CFA_advance_loc4;
375 *(guint32*)p = (guint32)(op->when - loc);
376 g_assert (read32 (p) == (guint32)(op->when - loc));
379 } else if (op->when - loc > 256) {
380 *p ++ = DW_CFA_advance_loc2;
381 *(guint16*)p = (guint16)(op->when - loc);
382 g_assert (read16 (p) == (guint32)(op->when - loc));
385 } else if (op->when - loc >= 32) {
386 *p ++ = DW_CFA_advance_loc1;
387 *(guint8*)p = (guint8)(op->when - loc);
390 } else if (op->when - loc < 32) {
391 *p ++ = DW_CFA_advance_loc | (op->when - loc);
394 *p ++ = DW_CFA_advance_loc | (30);
402 encode_uleb128 (reg, p, &p);
403 encode_uleb128 (op->val, p, &p);
405 case DW_CFA_def_cfa_offset:
407 encode_uleb128 (op->val, p, &p);
409 case DW_CFA_def_cfa_register:
411 encode_uleb128 (reg, p, &p);
413 case DW_CFA_same_value:
415 encode_uleb128 (reg, p, &p);
419 *p ++ = DW_CFA_offset_extended_sf;
420 encode_uleb128 (reg, p, &p);
421 encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
423 *p ++ = DW_CFA_offset | reg;
424 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
427 case DW_CFA_remember_state:
428 case DW_CFA_restore_state:
431 case DW_CFA_mono_advance_loc:
432 /* Only one location is supported */
433 g_assert (op->val == 0);
437 g_assert_not_reached ();
442 g_assert (p - buf < 4096);
444 res = g_malloc (p - buf);
445 memcpy (res, buf, p - buf);
451 #define UNW_DEBUG(stmt) do { stmt; } while (0)
453 #define UNW_DEBUG(stmt) do { } while (0)
456 static G_GNUC_UNUSED void
457 print_dwarf_state (int cfa_reg, int cfa_offset, int ip, int nregs, Loc *locations, guint8 *reg_saved)
461 printf ("\t%x: cfa=r%d+%d ", ip, cfa_reg, cfa_offset);
463 for (i = 0; i < nregs; ++i)
464 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET)
465 printf ("r%d@%d(cfa) ", i, locations [i].offset);
470 Loc locations [NUM_REGS];
471 guint8 reg_saved [NUM_REGS];
472 int cfa_reg, cfa_offset;
476 * Given the state of the current frame as stored in REGS, execute the unwind
477 * operations in unwind_info until the location counter reaches POS. The result is
478 * stored back into REGS. OUT_CFA will receive the value of the CFA.
479 * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
480 * On return, the nth entry will point to the address of the stack slot where register
481 * N was saved, or NULL, if it was not saved by this frame.
482 * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
483 * This function is signal safe.
486 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
487 guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
488 mgreg_t *regs, int nregs,
489 mgreg_t **save_locations, int save_locations_len,
492 Loc locations [NUM_REGS];
493 guint8 reg_saved [NUM_REGS];
494 int i, pos, reg, cfa_reg = -1, cfa_offset = 0, offset;
497 UnwindState state_stack [1];
500 memset (reg_saved, 0, sizeof (reg_saved));
507 while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
511 case DW_CFA_advance_loc:
512 UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
519 reg_saved [reg] = TRUE;
520 locations [reg].loc_type = LOC_OFFSET;
521 locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
528 cfa_reg = decode_uleb128 (p, &p);
529 cfa_offset = decode_uleb128 (p, &p);
531 case DW_CFA_def_cfa_offset:
532 cfa_offset = decode_uleb128 (p, &p);
534 case DW_CFA_def_cfa_register:
535 cfa_reg = decode_uleb128 (p, &p);
537 case DW_CFA_offset_extended_sf:
538 reg = decode_uleb128 (p, &p);
539 offset = decode_sleb128 (p, &p);
540 g_assert (reg < NUM_REGS);
541 reg_saved [reg] = TRUE;
542 locations [reg].loc_type = LOC_OFFSET;
543 locations [reg].offset = offset * DWARF_DATA_ALIGN;
545 case DW_CFA_offset_extended:
546 reg = decode_uleb128 (p, &p);
547 offset = decode_uleb128 (p, &p);
548 g_assert (reg < NUM_REGS);
549 reg_saved [reg] = TRUE;
550 locations [reg].loc_type = LOC_OFFSET;
551 locations [reg].offset = offset * DWARF_DATA_ALIGN;
553 case DW_CFA_same_value:
554 reg = decode_uleb128 (p, &p);
555 locations [reg].loc_type = LOC_SAME;
557 case DW_CFA_advance_loc1:
561 case DW_CFA_advance_loc2:
565 case DW_CFA_advance_loc4:
569 case DW_CFA_remember_state:
570 g_assert (state_stack_pos == 0);
571 memcpy (&state_stack [0].locations, &locations, sizeof (locations));
572 memcpy (&state_stack [0].reg_saved, ®_saved, sizeof (reg_saved));
573 state_stack [0].cfa_reg = cfa_reg;
574 state_stack [0].cfa_offset = cfa_offset;
577 case DW_CFA_restore_state:
578 g_assert (state_stack_pos == 1);
580 memcpy (&locations, &state_stack [0].locations, sizeof (locations));
581 memcpy (®_saved, &state_stack [0].reg_saved, sizeof (reg_saved));
582 cfa_reg = state_stack [0].cfa_reg;
583 cfa_offset = state_stack [0].cfa_offset;
585 case DW_CFA_mono_advance_loc:
586 g_assert (mark_locations [0]);
587 pos = mark_locations [0] - start_ip;
590 g_assert_not_reached ();
595 g_assert_not_reached ();
600 memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));
602 g_assert (cfa_reg != -1);
603 cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
604 for (i = 0; i < NUM_REGS; ++i) {
605 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
606 int hreg = mono_dwarf_reg_to_hw_reg (i);
607 g_assert (hreg < nregs);
608 regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
609 if (save_locations && hreg < save_locations_len)
610 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
618 mono_unwind_init (void)
620 mono_mutex_init_recursive (&unwind_mutex);
622 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
626 mono_unwind_cleanup (void)
630 mono_mutex_destroy (&unwind_mutex);
635 for (i = 0; i < cached_info_next; ++i) {
636 MonoUnwindInfo *cached = cached_info [i];
641 g_free (cached_info);
645 * mono_cache_unwind_info
647 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
648 * to mono_get_cached_unwind_info to get a cached copy of the info.
649 * A copy is made of the unwind info.
650 * This function is useful for two reasons:
651 * - many methods have the same unwind info
652 * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
655 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
658 MonoUnwindInfo *info;
662 if (cached_info == NULL) {
663 cached_info_size = 16;
664 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
667 for (i = 0; i < cached_info_next; ++i) {
668 MonoUnwindInfo *cached = cached_info [i];
670 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
676 info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
677 info->len = unwind_info_len;
678 memcpy (&info->info, unwind_info, unwind_info_len);
680 i = cached_info_next;
682 if (cached_info_next >= cached_info_size) {
683 MonoUnwindInfo **old_table, **new_table;
686 * Avoid freeing the old table so mono_get_cached_unwind_info ()
687 * doesn't need locks/hazard pointers.
690 old_table = cached_info;
691 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
693 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
695 mono_memory_barrier ();
697 cached_info = new_table;
699 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
701 cached_info_size *= 2;
704 cached_info [cached_info_next ++] = info;
706 unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
713 * This function is signal safe.
716 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
718 MonoUnwindInfo **table;
719 MonoUnwindInfo *info;
723 * This doesn't need any locks/hazard pointers,
724 * since new tables are copies of the old ones.
728 info = table [index];
730 *unwind_info_len = info->len;
737 * mono_unwind_get_dwarf_data_align:
739 * Return the data alignment used by the encoded unwind information.
742 mono_unwind_get_dwarf_data_align (void)
744 return DWARF_DATA_ALIGN;
748 * mono_unwind_get_dwarf_pc_reg:
750 * Return the dwarf register number of the register holding the ip of the
754 mono_unwind_get_dwarf_pc_reg (void)
760 decode_cie_op (guint8 *p, guint8 **endp)
765 case DW_CFA_advance_loc:
770 decode_uleb128 (p, &p);
777 decode_uleb128 (p, &p);
778 decode_uleb128 (p, &p);
780 case DW_CFA_def_cfa_offset:
781 decode_uleb128 (p, &p);
783 case DW_CFA_def_cfa_register:
784 decode_uleb128 (p, &p);
786 case DW_CFA_advance_loc4:
789 case DW_CFA_offset_extended_sf:
790 decode_uleb128 (p, &p);
791 decode_uleb128 (p, &p);
794 g_assert_not_reached ();
799 g_assert_not_reached ();
806 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
810 switch (encoding & 0xf) {
811 case DW_EH_PE_sdata8:
815 case DW_EH_PE_sdata4:
820 g_assert_not_reached ();
830 * Decode the Mono specific Language Specific Data Area generated by LLVM.
833 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
836 int i, ncall_sites, this_encoding;
837 guint32 mono_magic, version;
841 /* This is the modified LSDA generated by the LLVM mono branch */
842 mono_magic = decode_uleb128 (p, &p);
843 g_assert (mono_magic == 0x4d4fef4f);
844 version = decode_uleb128 (p, &p);
845 g_assert (version == 1);
848 if (this_encoding == DW_EH_PE_udata4) {
849 gint32 op, reg, offset;
851 /* 'this' location */
853 g_assert (op == DW_OP_bregx);
855 reg = decode_uleb128 (p, &p);
856 offset = decode_sleb128 (p, &p);
858 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
859 *this_offset = offset;
861 g_assert (this_encoding == DW_EH_PE_omit);
866 ncall_sites = decode_uleb128 (p, &p);
867 p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
870 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
871 *ex_info_len = ncall_sites;
874 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
876 for (i = 0; i < ncall_sites; ++i) {
877 int block_start_offset, block_size, landing_pad;
880 block_start_offset = read32 (p);
881 p += sizeof (gint32);
882 block_size = read32 (p);
883 p += sizeof (gint32);
884 landing_pad = read32 (p);
885 p += sizeof (gint32);
887 p += sizeof (gint32);
889 g_assert (landing_pad);
890 g_assert (((size_t)tinfo % 4) == 0);
891 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
895 (*type_info) [i] = tinfo;
896 (*ex_info)[i].try_start = code + block_start_offset;
897 (*ex_info)[i].try_end = code + block_start_offset + block_size;
898 (*ex_info)[i].handler_start = code + landing_pad;
904 * mono_unwind_decode_fde:
906 * Decode a DWARF FDE entry, returning the unwind opcodes.
907 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
908 * only try_start, try_end and handler_start is set.
909 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
913 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)
915 guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
916 gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
917 gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
918 gint32 i, cie_aug_len, buf_len;
921 gboolean has_fde_augmentation = FALSE;
924 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
934 // FIXME: Endianess ?
935 fde_len = *(guint32*)p;
936 g_assert (fde_len != 0xffffffff && fde_len != 0);
938 cie_offset = *(guint32*)p;
939 cie = p - cie_offset;
945 cie_len = *(guint32*)p;
947 cie_id = *(guint32*)p;
948 g_assert (cie_id == 0);
951 g_assert (cie_version == 1);
953 cie_aug_str = (char*)p;
954 p += strlen (cie_aug_str) + 1;
955 code_align = decode_uleb128 (p, &p);
956 data_align = decode_sleb128 (p, &p);
957 return_reg = decode_uleb128 (p, &p);
958 if (strstr (cie_aug_str, "z")) {
962 cie_aug_len = decode_uleb128 (p, &p);
964 has_fde_augmentation = TRUE;
967 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
968 switch (cie_aug_str [i]) {
974 read_encoded_val (p_encoding, p, &p);
977 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
981 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
985 g_assert_not_reached ();
995 /* Continue decoding FDE */
997 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
998 pc_begin = *(gint32*)p;
1001 pc_range = *(guint32*)p;
1003 if (has_fde_augmentation) {
1004 aug_len = decode_uleb128 (p, &p);
1011 fde_data_len = fde + 4 + fde_len - p;
1014 *code_len = pc_range;
1021 /* Decode FDE augmention */
1026 /* sdata|pcrel encoding */
1028 lsda_offset = read32 (fde_aug);
1029 else if (aug_len == 8)
1030 lsda_offset = *(gint64*)fde_aug;
1032 g_assert_not_reached ();
1033 if (lsda_offset != 0) {
1034 lsda = fde_aug + lsda_offset;
1036 decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
1040 /* Make sure the FDE uses the same constants as we do */
1041 g_assert (code_align == 1);
1042 g_assert (data_align == DWARF_DATA_ALIGN);
1043 g_assert (return_reg == DWARF_PC_REG);
1045 buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
1046 buf = g_malloc0 (buf_len);
1050 while (p < cie + cie_len + 4) {
1051 if (*p == DW_CFA_nop)
1054 decode_cie_op (p, &p);
1056 memcpy (buf + i, cie_cfi, p - cie_cfi);
1060 while (p < fde + fde_len + 4) {
1061 if (*p == DW_CFA_nop)
1064 decode_cie_op (p, &p);
1066 memcpy (buf + i, fde_cfi, p - fde_cfi);
1068 g_assert (i <= buf_len);
1072 return g_realloc (buf, i);
1076 * mono_unwind_decode_mono_fde:
1078 * Decode an FDE entry in the LLVM emitted mono EH frame.
1079 * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
1080 * only try_start, try_end and handler_start is set.
1081 * info->type_info is set to a malloc-ed array containing the ttype table from the
1085 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
1087 guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
1088 int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
1089 gint32 code_align, data_align, return_reg, pers_encoding;
1091 memset (res, 0, sizeof (*res));
1093 res->this_offset = -1;
1095 /* fde points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
1100 aug_len = read32 (p);
1112 /* The LSDA is embedded directly into the FDE */
1115 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1120 code_align = decode_uleb128 (p, &p);
1121 data_align = decode_sleb128 (p, &p);
1122 return_reg = decode_uleb128 (p, &p);
1125 if (pers_encoding != DW_EH_PE_omit)
1126 read_encoded_val (pers_encoding, p, &p);
1130 /* Make sure the FDE uses the same constants as we do */
1131 g_assert (code_align == 1);
1132 g_assert (data_align == DWARF_DATA_ALIGN);
1133 g_assert (return_reg == DWARF_PC_REG);
1135 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1138 if (*p == DW_CFA_nop)
1141 decode_cie_op (p, &p);
1143 cie_cfi_len = p - cie_cfi;
1144 fde_cfi_len = (fde + fde_len - fde_cfi);
1146 buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1147 memcpy (buf, cie_cfi, cie_cfi_len);
1148 memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1150 res->unw_info_len = cie_cfi_len + fde_cfi_len;
1151 res->unw_info = buf;
1155 * mono_unwind_get_cie_program:
1157 * Get the unwind bytecode for the DWARF CIE.
1160 mono_unwind_get_cie_program (void)
1162 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1163 return mono_arch_get_cie_program ();