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 CRITICAL_SECTION 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() EnterCriticalSection (&unwind_mutex)
45 #define unwind_unlock() LeaveCriticalSection (&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 NUM_REGS (32 + 1)
62 #define DWARF_DATA_ALIGN (-8)
63 #define DWARF_PC_REG 32
64 static int map_hw_reg_to_dwarf_reg [] = {
65 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
66 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
68 #elif defined (TARGET_X86)
71 * LLVM seems to generate unwind info where esp is encoded as 5, and ebp as 4, ie see this line:
72 * def ESP : RegisterWithSubRegs<"esp", [SP]>, DwarfRegNum<[-2, 5, 4]>;
73 * in lib/Target/X86/X86RegisterInfo.td in the llvm sources.
75 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 5, 4, 6, 7, 8 };
77 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
80 #define NUM_REGS X86_NREG + 1
81 #define DWARF_DATA_ALIGN (-4)
82 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
83 #elif defined (TARGET_POWERPC)
84 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
85 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
86 9, 10, 11, 12, 13, 14, 15, 16,
87 17, 18, 19, 20, 21, 22, 23, 24,
88 25, 26, 27, 28, 29, 30, 31 };
90 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
91 #define DWARF_PC_REG 108
92 #elif defined (TARGET_S390X)
93 static int map_hw_reg_to_dwarf_reg [] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
95 #define DWARF_DATA_ALIGN (-8)
96 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
97 #elif defined (TARGET_MIPS)
99 static int map_hw_reg_to_dwarf_reg [32] = {
100 0, 1, 2, 3, 4, 5, 6, 7,
101 8, 9, 10, 11, 12, 13, 14, 15,
102 16, 17, 18, 19, 20, 21, 22, 23,
103 24, 25, 26, 27, 28, 29, 30, 31
106 #define DWARF_DATA_ALIGN (-(gint32)sizeof (mgreg_t))
107 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
109 static int map_hw_reg_to_dwarf_reg [16];
111 #define DWARF_DATA_ALIGN 0
112 #define DWARF_PC_REG -1
115 static gboolean dwarf_reg_to_hw_reg_inited;
117 static int map_dwarf_reg_to_hw_reg [NUM_REGS];
120 * mono_hw_reg_to_dwarf_reg:
122 * Map the hardware register number REG to the register number used by DWARF.
125 mono_hw_reg_to_dwarf_reg (int reg)
127 #ifdef TARGET_POWERPC
131 g_assert (reg < NUM_REGS);
135 g_assert_not_reached ();
138 return map_hw_reg_to_dwarf_reg [reg];
147 g_assert (NUM_REGS > 0);
148 for (i = 0; i < sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int); ++i) {
149 map_dwarf_reg_to_hw_reg [mono_hw_reg_to_dwarf_reg (i)] = i;
152 #ifdef TARGET_POWERPC
153 map_dwarf_reg_to_hw_reg [DWARF_PC_REG] = ppc_lr;
156 mono_memory_barrier ();
157 dwarf_reg_to_hw_reg_inited = TRUE;
161 mono_dwarf_reg_to_hw_reg (int reg)
163 if (!dwarf_reg_to_hw_reg_inited)
166 return map_dwarf_reg_to_hw_reg [reg];
169 static G_GNUC_UNUSED void
170 encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
175 guint8 b = value & 0x7f;
177 if (value != 0) /* more bytes to come */
185 static G_GNUC_UNUSED void
186 encode_sleb128 (gint32 value, guint8 *buf, guint8 **endbuf)
189 gboolean negative = (value < 0);
197 /* the following is unnecessary if the
198 * implementation of >>= uses an arithmetic rather
199 * than logical shift for a signed left operand
203 value |= - (1 <<(size - 7));
204 /* sign bit of byte is second high order bit (0x40) */
205 if ((value == 0 && !(byte & 0x40)) ||
206 (value == -1 && (byte & 0x40)))
216 static inline guint32
217 decode_uleb128 (guint8 *buf, guint8 **endbuf)
227 res = res | (((int)(b & 0x7f)) << shift);
239 decode_sleb128 (guint8 *buf, guint8 **endbuf)
249 res = res | (((int)(b & 0x7f)) << shift);
252 if (shift < 32 && (b & 0x40))
253 res |= - (1 << shift);
264 mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len)
267 int pos, reg, offset, cfa_reg, cfa_offset;
271 while (p < unwind_info + unwind_info_len) {
275 case DW_CFA_advance_loc:
282 offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
283 if (reg == DWARF_PC_REG)
284 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, "pc", -offset);
286 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
293 cfa_reg = decode_uleb128 (p, &p);
294 cfa_offset = decode_uleb128 (p, &p);
295 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)), cfa_offset);
297 case DW_CFA_def_cfa_offset:
298 cfa_offset = decode_uleb128 (p, &p);
299 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos, cfa_offset);
301 case DW_CFA_def_cfa_register:
302 cfa_reg = decode_uleb128 (p, &p);
303 printf ("CFA: [%x] def_cfa_reg: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)));
305 case DW_CFA_offset_extended_sf:
306 reg = decode_uleb128 (p, &p);
307 offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
308 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
310 case DW_CFA_advance_loc4:
315 g_assert_not_reached ();
320 g_assert_not_reached ();
326 * mono_unwind_ops_encode:
328 * Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
329 * Return a pointer to malloc'ed memory.
332 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
337 guint8 *buf, *p, *res;
339 p = buf = g_malloc0 (4096);
343 for (; l; l = l->next) {
348 /* Convert the register from the hw encoding to the dwarf encoding */
349 reg = mono_hw_reg_to_dwarf_reg (op->reg);
351 /* Emit an advance_loc if neccesary */
352 while (op->when > loc) {
353 if (op->when - loc < 32) {
354 *p ++ = DW_CFA_advance_loc | (op->when - loc);
357 *p ++ = DW_CFA_advance_loc | (30);
365 encode_uleb128 (reg, p, &p);
366 encode_uleb128 (op->val, p, &p);
368 case DW_CFA_def_cfa_offset:
370 encode_uleb128 (op->val, p, &p);
372 case DW_CFA_def_cfa_register:
374 encode_uleb128 (reg, p, &p);
378 *p ++ = DW_CFA_offset_extended_sf;
379 encode_uleb128 (reg, p, &p);
380 encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
382 *p ++ = DW_CFA_offset | reg;
383 encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p);
387 g_assert_not_reached ();
392 g_assert (p - buf < 4096);
394 res = g_malloc (p - buf);
395 memcpy (res, buf, p - buf);
401 #define UNW_DEBUG(stmt) do { stmt; } while (0)
403 #define UNW_DEBUG(stmt) do { } while (0)
406 static G_GNUC_UNUSED void
407 print_dwarf_state (int cfa_reg, int cfa_offset, int ip, int nregs, Loc *locations, guint8 *reg_saved)
411 printf ("\t%x: cfa=r%d+%d ", ip, cfa_reg, cfa_offset);
413 for (i = 0; i < nregs; ++i)
414 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET)
415 printf ("r%d@%d(cfa) ", i, locations [i].offset);
420 * Given the state of the current frame as stored in REGS, execute the unwind
421 * operations in unwind_info until the location counter reaches POS. The result is
422 * stored back into REGS. OUT_CFA will receive the value of the CFA.
423 * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
424 * On return, the nth entry will point to the address of the stack slot where register
425 * N was saved, or NULL, if it was not saved by this frame.
426 * This function is signal safe.
429 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
430 guint8 *start_ip, guint8 *end_ip, guint8 *ip, mgreg_t *regs, int nregs,
431 mgreg_t **save_locations, int save_locations_len,
434 Loc locations [NUM_REGS];
435 guint8 reg_saved [NUM_REGS];
436 int i, pos, reg, cfa_reg, cfa_offset, offset;
440 memset (reg_saved, 0, sizeof (reg_saved));
446 while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
450 case DW_CFA_advance_loc:
451 UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
458 reg_saved [reg] = TRUE;
459 locations [reg].loc_type = LOC_OFFSET;
460 locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
467 cfa_reg = decode_uleb128 (p, &p);
468 cfa_offset = decode_uleb128 (p, &p);
470 case DW_CFA_def_cfa_offset:
471 cfa_offset = decode_uleb128 (p, &p);
473 case DW_CFA_def_cfa_register:
474 cfa_reg = decode_uleb128 (p, &p);
476 case DW_CFA_offset_extended_sf:
477 reg = decode_uleb128 (p, &p);
478 offset = decode_sleb128 (p, &p);
479 g_assert (reg < NUM_REGS);
480 reg_saved [reg] = TRUE;
481 locations [reg].loc_type = LOC_OFFSET;
482 locations [reg].offset = offset * DWARF_DATA_ALIGN;
484 case DW_CFA_offset_extended:
485 reg = decode_uleb128 (p, &p);
486 offset = decode_uleb128 (p, &p);
487 g_assert (reg < NUM_REGS);
488 reg_saved [reg] = TRUE;
489 locations [reg].loc_type = LOC_OFFSET;
490 locations [reg].offset = offset * DWARF_DATA_ALIGN;
492 case DW_CFA_advance_loc4:
497 g_assert_not_reached ();
502 g_assert_not_reached ();
507 memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));
509 cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
510 for (i = 0; i < NUM_REGS; ++i) {
511 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
512 int hreg = mono_dwarf_reg_to_hw_reg (i);
513 g_assert (hreg < nregs);
514 regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
515 if (save_locations && hreg < save_locations_len)
516 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
524 mono_unwind_init (void)
526 InitializeCriticalSection (&unwind_mutex);
528 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
532 mono_unwind_cleanup (void)
536 DeleteCriticalSection (&unwind_mutex);
541 for (i = 0; i < cached_info_next; ++i) {
542 MonoUnwindInfo *cached = cached_info [i];
547 g_free (cached_info);
551 * mono_cache_unwind_info
553 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
554 * to mono_get_cached_unwind_info to get a cached copy of the info.
555 * A copy is made of the unwind info.
556 * This function is useful for two reasons:
557 * - many methods have the same unwind info
558 * - MonoJitInfo->used_regs is an int so it can't store the pointer to the unwind info
561 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
564 MonoUnwindInfo *info;
568 if (cached_info == NULL) {
569 cached_info_size = 16;
570 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
573 for (i = 0; i < cached_info_next; ++i) {
574 MonoUnwindInfo *cached = cached_info [i];
576 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
582 info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
583 info->len = unwind_info_len;
584 memcpy (&info->info, unwind_info, unwind_info_len);
586 i = cached_info_next;
588 if (cached_info_next >= cached_info_size) {
589 MonoUnwindInfo **old_table, **new_table;
592 * Avoid freeing the old table so mono_get_cached_unwind_info ()
593 * doesn't need locks/hazard pointers.
596 old_table = cached_info;
597 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
599 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
601 mono_memory_barrier ();
603 cached_info = new_table;
605 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
607 cached_info_size *= 2;
610 cached_info [cached_info_next ++] = info;
612 unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
619 * This function is signal safe.
622 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
624 MonoUnwindInfo **table;
625 MonoUnwindInfo *info;
629 * This doesn't need any locks/hazard pointers,
630 * since new tables are copies of the old ones.
634 info = table [index];
636 *unwind_info_len = info->len;
643 * mono_unwind_get_dwarf_data_align:
645 * Return the data alignment used by the encoded unwind information.
648 mono_unwind_get_dwarf_data_align (void)
650 return DWARF_DATA_ALIGN;
654 * mono_unwind_get_dwarf_pc_reg:
656 * Return the dwarf register number of the register holding the ip of the
660 mono_unwind_get_dwarf_pc_reg (void)
666 decode_cie_op (guint8 *p, guint8 **endp)
671 case DW_CFA_advance_loc:
676 decode_uleb128 (p, &p);
683 decode_uleb128 (p, &p);
684 decode_uleb128 (p, &p);
686 case DW_CFA_def_cfa_offset:
687 decode_uleb128 (p, &p);
689 case DW_CFA_def_cfa_register:
690 decode_uleb128 (p, &p);
692 case DW_CFA_advance_loc4:
695 case DW_CFA_offset_extended_sf:
696 decode_uleb128 (p, &p);
697 decode_uleb128 (p, &p);
700 g_assert_not_reached ();
705 g_assert_not_reached ();
712 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
716 switch (encoding & 0xf) {
717 case DW_EH_PE_sdata8:
721 case DW_EH_PE_sdata4:
726 g_assert_not_reached ();
736 * Decode the Mono specific Language Specific Data Area generated by LLVM.
739 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
742 int i, ncall_sites, this_encoding;
743 guint32 mono_magic, version;
747 /* This is the modified LSDA generated by the LLVM mono branch */
748 mono_magic = decode_uleb128 (p, &p);
749 g_assert (mono_magic == 0x4d4fef4f);
750 version = decode_uleb128 (p, &p);
751 g_assert (version == 1);
754 if (this_encoding == DW_EH_PE_udata4) {
755 gint32 op, reg, offset;
757 /* 'this' location */
759 g_assert (op == DW_OP_bregx);
761 reg = decode_uleb128 (p, &p);
762 offset = decode_sleb128 (p, &p);
764 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
765 *this_offset = offset;
767 g_assert (this_encoding == DW_EH_PE_omit);
772 ncall_sites = decode_uleb128 (p, &p);
773 p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
776 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
777 *ex_info_len = ncall_sites;
780 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
782 for (i = 0; i < ncall_sites; ++i) {
783 int block_start_offset, block_size, landing_pad;
786 block_start_offset = read32 (p);
787 p += sizeof (gint32);
788 block_size = read32 (p);
789 p += sizeof (gint32);
790 landing_pad = read32 (p);
791 p += sizeof (gint32);
793 p += sizeof (gint32);
795 g_assert (landing_pad);
796 g_assert (((size_t)tinfo % 4) == 0);
797 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
801 (*type_info) [i] = tinfo;
802 (*ex_info)[i].try_start = code + block_start_offset;
803 (*ex_info)[i].try_end = code + block_start_offset + block_size;
804 (*ex_info)[i].handler_start = code + landing_pad;
810 * mono_unwind_decode_fde:
812 * Decode a DWARF FDE entry, returning the unwind opcodes.
813 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
814 * only try_start, try_end and handler_start is set.
815 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
819 mono_unwind_decode_fde (guint8 *fde, guint32 *out_len, guint32 *code_len, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
821 guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
822 gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
823 gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
824 gint32 i, cie_aug_len, buf_len;
827 gboolean has_fde_augmentation = FALSE;
830 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
840 // FIXME: Endianess ?
841 fde_len = *(guint32*)p;
842 g_assert (fde_len != 0xffffffff && fde_len != 0);
844 cie_offset = *(guint32*)p;
845 cie = p - cie_offset;
851 cie_len = *(guint32*)p;
853 cie_id = *(guint32*)p;
854 g_assert (cie_id == 0);
857 g_assert (cie_version == 1);
859 cie_aug_str = (char*)p;
860 p += strlen (cie_aug_str) + 1;
861 code_align = decode_uleb128 (p, &p);
862 data_align = decode_sleb128 (p, &p);
863 return_reg = decode_uleb128 (p, &p);
864 if (strstr (cie_aug_str, "z")) {
868 cie_aug_len = decode_uleb128 (p, &p);
870 has_fde_augmentation = TRUE;
873 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
874 switch (cie_aug_str [i]) {
880 read_encoded_val (p_encoding, p, &p);
883 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
887 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
891 g_assert_not_reached ();
901 /* Continue decoding FDE */
903 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
904 pc_begin = *(gint32*)p;
907 pc_range = *(guint32*)p;
909 if (has_fde_augmentation) {
910 aug_len = decode_uleb128 (p, &p);
917 fde_data_len = fde + 4 + fde_len - p;
920 *code_len = pc_range;
927 /* Decode FDE augmention */
932 /* sdata|pcrel encoding */
934 lsda_offset = read32 (fde_aug);
935 else if (aug_len == 8)
936 lsda_offset = *(gint64*)fde_aug;
938 g_assert_not_reached ();
939 if (lsda_offset != 0) {
940 lsda = fde_aug + lsda_offset;
942 decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
946 /* Make sure the FDE uses the same constants as we do */
947 g_assert (code_align == 1);
948 g_assert (data_align == DWARF_DATA_ALIGN);
949 g_assert (return_reg == DWARF_PC_REG);
951 buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
952 buf = g_malloc0 (buf_len);
956 while (p < cie + cie_len + 4) {
957 if (*p == DW_CFA_nop)
960 decode_cie_op (p, &p);
962 memcpy (buf + i, cie_cfi, p - cie_cfi);
966 while (p < fde + fde_len + 4) {
967 if (*p == DW_CFA_nop)
970 decode_cie_op (p, &p);
972 memcpy (buf + i, fde_cfi, p - fde_cfi);
974 g_assert (i <= buf_len);
978 return g_realloc (buf, i);
982 * mono_unwind_decode_mono_fde:
984 * Decode an FDE entry in the LLVM emitted mono EH frame.
985 * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
986 * only try_start, try_end and handler_start is set.
987 * info->type_info is set to a malloc-ed array containing the ttype table from the
991 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
993 guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
994 int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
995 gint32 code_align, data_align, return_reg, pers_encoding;
997 memset (res, 0, sizeof (*res));
999 res->this_offset = -1;
1001 /* fde points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
1006 aug_len = read32 (p);
1018 /* The LSDA is embedded directly into the FDE */
1021 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1026 code_align = decode_uleb128 (p, &p);
1027 data_align = decode_sleb128 (p, &p);
1028 return_reg = decode_uleb128 (p, &p);
1031 if (pers_encoding != DW_EH_PE_omit)
1032 read_encoded_val (pers_encoding, p, &p);
1036 /* Make sure the FDE uses the same constants as we do */
1037 g_assert (code_align == 1);
1038 g_assert (data_align == DWARF_DATA_ALIGN);
1039 g_assert (return_reg == DWARF_PC_REG);
1041 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1044 if (*p == DW_CFA_nop)
1047 decode_cie_op (p, &p);
1049 cie_cfi_len = p - cie_cfi;
1050 fde_cfi_len = (fde + fde_len - fde_cfi);
1052 buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1053 memcpy (buf, cie_cfi, cie_cfi_len);
1054 memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1056 res->unw_info_len = cie_cfi_len + fde_cfi_len;
1057 res->unw_info = buf;
1061 * mono_unwind_get_cie_program:
1063 * Get the unwind bytecode for the DWARF CIE.
1066 mono_unwind_get_cie_program (void)
1068 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1069 return mono_arch_get_cie_program ();