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, cfa_offset, 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 cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
603 for (i = 0; i < NUM_REGS; ++i) {
604 if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
605 int hreg = mono_dwarf_reg_to_hw_reg (i);
606 g_assert (hreg < nregs);
607 regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
608 if (save_locations && hreg < save_locations_len)
609 save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
617 mono_unwind_init (void)
619 mono_mutex_init_recursive (&unwind_mutex);
621 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
625 mono_unwind_cleanup (void)
629 mono_mutex_destroy (&unwind_mutex);
634 for (i = 0; i < cached_info_next; ++i) {
635 MonoUnwindInfo *cached = cached_info [i];
640 g_free (cached_info);
644 * mono_cache_unwind_info
646 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
647 * to mono_get_cached_unwind_info to get a cached copy of the info.
648 * A copy is made of the unwind info.
649 * This function is useful for two reasons:
650 * - many methods have the same unwind info
651 * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
654 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
657 MonoUnwindInfo *info;
661 if (cached_info == NULL) {
662 cached_info_size = 16;
663 cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
666 for (i = 0; i < cached_info_next; ++i) {
667 MonoUnwindInfo *cached = cached_info [i];
669 if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
675 info = g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
676 info->len = unwind_info_len;
677 memcpy (&info->info, unwind_info, unwind_info_len);
679 i = cached_info_next;
681 if (cached_info_next >= cached_info_size) {
682 MonoUnwindInfo **old_table, **new_table;
685 * Avoid freeing the old table so mono_get_cached_unwind_info ()
686 * doesn't need locks/hazard pointers.
689 old_table = cached_info;
690 new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
692 memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
694 mono_memory_barrier ();
696 cached_info = new_table;
698 cached_info_list = g_slist_prepend (cached_info_list, cached_info);
700 cached_info_size *= 2;
703 cached_info [cached_info_next ++] = info;
705 unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
712 * This function is signal safe.
715 mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
717 MonoUnwindInfo **table;
718 MonoUnwindInfo *info;
722 * This doesn't need any locks/hazard pointers,
723 * since new tables are copies of the old ones.
727 info = table [index];
729 *unwind_info_len = info->len;
736 * mono_unwind_get_dwarf_data_align:
738 * Return the data alignment used by the encoded unwind information.
741 mono_unwind_get_dwarf_data_align (void)
743 return DWARF_DATA_ALIGN;
747 * mono_unwind_get_dwarf_pc_reg:
749 * Return the dwarf register number of the register holding the ip of the
753 mono_unwind_get_dwarf_pc_reg (void)
759 decode_cie_op (guint8 *p, guint8 **endp)
764 case DW_CFA_advance_loc:
769 decode_uleb128 (p, &p);
776 decode_uleb128 (p, &p);
777 decode_uleb128 (p, &p);
779 case DW_CFA_def_cfa_offset:
780 decode_uleb128 (p, &p);
782 case DW_CFA_def_cfa_register:
783 decode_uleb128 (p, &p);
785 case DW_CFA_advance_loc4:
788 case DW_CFA_offset_extended_sf:
789 decode_uleb128 (p, &p);
790 decode_uleb128 (p, &p);
793 g_assert_not_reached ();
798 g_assert_not_reached ();
805 read_encoded_val (guint32 encoding, guint8 *p, guint8 **endp)
809 switch (encoding & 0xf) {
810 case DW_EH_PE_sdata8:
814 case DW_EH_PE_sdata4:
819 g_assert_not_reached ();
829 * Decode the Mono specific Language Specific Data Area generated by LLVM.
832 decode_lsda (guint8 *lsda, guint8 *code, MonoJitExceptionInfo **ex_info, guint32 *ex_info_len, gpointer **type_info, int *this_reg, int *this_offset)
835 int i, ncall_sites, this_encoding;
836 guint32 mono_magic, version;
840 /* This is the modified LSDA generated by the LLVM mono branch */
841 mono_magic = decode_uleb128 (p, &p);
842 g_assert (mono_magic == 0x4d4fef4f);
843 version = decode_uleb128 (p, &p);
844 g_assert (version == 1);
847 if (this_encoding == DW_EH_PE_udata4) {
848 gint32 op, reg, offset;
850 /* 'this' location */
852 g_assert (op == DW_OP_bregx);
854 reg = decode_uleb128 (p, &p);
855 offset = decode_sleb128 (p, &p);
857 *this_reg = mono_dwarf_reg_to_hw_reg (reg);
858 *this_offset = offset;
860 g_assert (this_encoding == DW_EH_PE_omit);
865 ncall_sites = decode_uleb128 (p, &p);
866 p = (guint8*)ALIGN_TO ((mgreg_t)p, 4);
869 *ex_info = g_malloc0 (ncall_sites * sizeof (MonoJitExceptionInfo));
870 *ex_info_len = ncall_sites;
873 *type_info = g_malloc0 (ncall_sites * sizeof (gpointer));
875 for (i = 0; i < ncall_sites; ++i) {
876 int block_start_offset, block_size, landing_pad;
879 block_start_offset = read32 (p);
880 p += sizeof (gint32);
881 block_size = read32 (p);
882 p += sizeof (gint32);
883 landing_pad = read32 (p);
884 p += sizeof (gint32);
886 p += sizeof (gint32);
888 g_assert (landing_pad);
889 g_assert (((size_t)tinfo % 4) == 0);
890 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
894 (*type_info) [i] = tinfo;
895 (*ex_info)[i].try_start = code + block_start_offset;
896 (*ex_info)[i].try_end = code + block_start_offset + block_size;
897 (*ex_info)[i].handler_start = code + landing_pad;
903 * mono_unwind_decode_fde:
905 * Decode a DWARF FDE entry, returning the unwind opcodes.
906 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
907 * only try_start, try_end and handler_start is set.
908 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
912 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)
914 guint8 *p, *cie, *fde_current, *fde_aug = NULL, *code, *fde_cfi, *cie_cfi;
915 gint32 fde_len, cie_offset, pc_begin, pc_range, aug_len, fde_data_len;
916 gint32 cie_len, cie_id, cie_version, code_align, data_align, return_reg;
917 gint32 i, cie_aug_len, buf_len;
920 gboolean has_fde_augmentation = FALSE;
923 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
933 // FIXME: Endianess ?
934 fde_len = *(guint32*)p;
935 g_assert (fde_len != 0xffffffff && fde_len != 0);
937 cie_offset = *(guint32*)p;
938 cie = p - cie_offset;
944 cie_len = *(guint32*)p;
946 cie_id = *(guint32*)p;
947 g_assert (cie_id == 0);
950 g_assert (cie_version == 1);
952 cie_aug_str = (char*)p;
953 p += strlen (cie_aug_str) + 1;
954 code_align = decode_uleb128 (p, &p);
955 data_align = decode_sleb128 (p, &p);
956 return_reg = decode_uleb128 (p, &p);
957 if (strstr (cie_aug_str, "z")) {
961 cie_aug_len = decode_uleb128 (p, &p);
963 has_fde_augmentation = TRUE;
966 for (i = 0; cie_aug_str [i] != '\0'; ++i) {
967 switch (cie_aug_str [i]) {
973 read_encoded_val (p_encoding, p, &p);
976 g_assert ((*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel)) || (*p == (DW_EH_PE_sdata8|DW_EH_PE_pcrel)));
980 g_assert (*p == (DW_EH_PE_sdata4|DW_EH_PE_pcrel));
984 g_assert_not_reached ();
994 /* Continue decoding FDE */
996 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
997 pc_begin = *(gint32*)p;
1000 pc_range = *(guint32*)p;
1002 if (has_fde_augmentation) {
1003 aug_len = decode_uleb128 (p, &p);
1010 fde_data_len = fde + 4 + fde_len - p;
1013 *code_len = pc_range;
1020 /* Decode FDE augmention */
1025 /* sdata|pcrel encoding */
1027 lsda_offset = read32 (fde_aug);
1028 else if (aug_len == 8)
1029 lsda_offset = *(gint64*)fde_aug;
1031 g_assert_not_reached ();
1032 if (lsda_offset != 0) {
1033 lsda = fde_aug + lsda_offset;
1035 decode_lsda (lsda, code, ex_info, ex_info_len, type_info, this_reg, this_offset);
1039 /* Make sure the FDE uses the same constants as we do */
1040 g_assert (code_align == 1);
1041 g_assert (data_align == DWARF_DATA_ALIGN);
1042 g_assert (return_reg == DWARF_PC_REG);
1044 buf_len = (cie + cie_len + 4 - cie_cfi) + (fde + fde_len + 4 - fde_cfi);
1045 buf = g_malloc0 (buf_len);
1049 while (p < cie + cie_len + 4) {
1050 if (*p == DW_CFA_nop)
1053 decode_cie_op (p, &p);
1055 memcpy (buf + i, cie_cfi, p - cie_cfi);
1059 while (p < fde + fde_len + 4) {
1060 if (*p == DW_CFA_nop)
1063 decode_cie_op (p, &p);
1065 memcpy (buf + i, fde_cfi, p - fde_cfi);
1067 g_assert (i <= buf_len);
1071 return g_realloc (buf, i);
1075 * mono_unwind_decode_mono_fde:
1077 * Decode an FDE entry in the LLVM emitted mono EH frame.
1078 * info->ex_info is set to a malloc-ed array of MonoJitExceptionInfo structures,
1079 * only try_start, try_end and handler_start is set.
1080 * info->type_info is set to a malloc-ed array containing the ttype table from the
1084 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res)
1086 guint8 *p, *fde_aug, *cie_cfi, *fde_cfi, *buf;
1087 int has_aug, aug_len, cie_cfi_len, fde_cfi_len;
1088 gint32 code_align, data_align, return_reg, pers_encoding;
1090 memset (res, 0, sizeof (*res));
1092 res->this_offset = -1;
1094 /* fde points to data emitted by LLVM in DwarfException::EmitMonoEHFrame () */
1099 aug_len = read32 (p);
1111 /* The LSDA is embedded directly into the FDE */
1114 decode_lsda (lsda, code, &res->ex_info, &res->ex_info_len, &res->type_info, &res->this_reg, &res->this_offset);
1119 code_align = decode_uleb128 (p, &p);
1120 data_align = decode_sleb128 (p, &p);
1121 return_reg = decode_uleb128 (p, &p);
1124 if (pers_encoding != DW_EH_PE_omit)
1125 read_encoded_val (pers_encoding, p, &p);
1129 /* Make sure the FDE uses the same constants as we do */
1130 g_assert (code_align == 1);
1131 g_assert (data_align == DWARF_DATA_ALIGN);
1132 g_assert (return_reg == DWARF_PC_REG);
1134 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1137 if (*p == DW_CFA_nop)
1140 decode_cie_op (p, &p);
1142 cie_cfi_len = p - cie_cfi;
1143 fde_cfi_len = (fde + fde_len - fde_cfi);
1145 buf = g_malloc0 (cie_cfi_len + fde_cfi_len);
1146 memcpy (buf, cie_cfi, cie_cfi_len);
1147 memcpy (buf + cie_cfi_len, fde_cfi, fde_cfi_len);
1149 res->unw_info_len = cie_cfi_len + fde_cfi_len;
1150 res->unw_info = buf;
1154 * mono_unwind_get_cie_program:
1156 * Get the unwind bytecode for the DWARF CIE.
1159 mono_unwind_get_cie_program (void)
1161 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC)
1162 return mono_arch_get_cie_program ();