3 * Stack Unwinding Interface
6 * Zoltan Varga (vargaz@gmail.com)
8 * (C) 2008 Novell, Inc.
12 #include "mini-unwind.h"
14 #include <mono/utils/mono-counters.h>
15 #include <mono/utils/freebsd-dwarf.h>
16 #include <mono/utils/hazard-pointer.h>
17 #include <mono/utils/mono-logger-internals.h>
18 #include <mono/metadata/threads-types.h>
19 #include <mono/metadata/mono-endian.h>
33 guint8 info
[MONO_ZERO_LEN_ARRAY
];
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_os_mutex_lock (&unwind_mutex)
45 #define unwind_unlock() mono_os_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_DWARF_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 (dwarf regs 264..271) */
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 };
56 #define NUM_DWARF_REGS 272
57 #define DWARF_DATA_ALIGN (-4)
58 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (ARMREG_LR))
59 #define IS_DOUBLE_REG(dwarf_reg) (((dwarf_reg) >= 264) && ((dwarf_reg) <= 271))
60 #elif defined(TARGET_ARM64)
61 #define NUM_DWARF_REGS 96
62 #define DWARF_DATA_ALIGN (-8)
64 #define DWARF_PC_REG 30
65 static int map_hw_reg_to_dwarf_reg
[] = {
66 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
67 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
69 72, 73, 74, 75, 76, 77, 78, 79,
71 #elif defined (TARGET_X86)
73 * ebp and esp are swapped:
74 * http://lists.cs.uiuc.edu/pipermail/lldb-dev/2014-January/003101.html
76 static int map_hw_reg_to_dwarf_reg
[] = { 0, 1, 2, 3, 5, 4, 6, 7, 8 };
78 #define NUM_DWARF_REGS (X86_NREG + 1)
79 #define DWARF_DATA_ALIGN (-4)
80 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (X86_NREG))
81 #elif defined (TARGET_POWERPC)
82 // http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi-1.9.html
83 static int map_hw_reg_to_dwarf_reg
[ppc_lr
+ 1] = { 0, 1, 2, 3, 4, 5, 6, 7, 8,
84 9, 10, 11, 12, 13, 14, 15, 16,
85 17, 18, 19, 20, 21, 22, 23, 24,
86 25, 26, 27, 28, 29, 30, 31 };
87 #define DWARF_DATA_ALIGN (-(gint32)sizeof (target_mgreg_t))
89 #define DWARF_PC_REG 65
91 #define DWARF_PC_REG 108
93 #define NUM_DWARF_REGS (DWARF_PC_REG + 1)
94 #elif defined (TARGET_S390X)
99 static int map_hw_reg_to_dwarf_reg
[] = { 0, 1, 2, 3, 4, 5, 6, 7,
100 8, 9, 10, 11, 12, 13, 14, 15,
101 16, 17, 18, 19, 20, 21, 22, 23,
102 24, 25, 26, 27, 28, 29, 30, 31};
103 #define NUM_DWARF_REGS 32
104 #define DWARF_DATA_ALIGN (-8)
105 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (14))
106 #elif defined (TARGET_MIPS)
108 static int map_hw_reg_to_dwarf_reg
[32] = {
109 0, 1, 2, 3, 4, 5, 6, 7,
110 8, 9, 10, 11, 12, 13, 14, 15,
111 16, 17, 18, 19, 20, 21, 22, 23,
112 24, 25, 26, 27, 28, 29, 30, 31
114 #define NUM_DWARF_REGS 32
115 #define DWARF_DATA_ALIGN (-(gint32)sizeof (target_mgreg_t))
116 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (mips_ra))
117 #elif defined(TARGET_RISCV)
120 * These values have not currently been formalized in the RISC-V psABI. See
121 * instead gcc/config/riscv/riscv.h in the GCC source tree.
124 #define NUM_DWARF_REGS (RISCV_N_GREGS + RISCV_N_FREGS)
125 #define DWARF_DATA_ALIGN (-4)
126 #define DWARF_PC_REG (mono_hw_reg_to_dwarf_reg (RISCV_RA))
128 static int map_hw_reg_to_dwarf_reg
[NUM_DWARF_REGS
] = {
130 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
131 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
133 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
134 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
138 static int map_hw_reg_to_dwarf_reg
[16];
139 #define NUM_DWARF_REGS 16
140 #define DWARF_DATA_ALIGN 1
141 #define DWARF_PC_REG -1
144 #define NUM_HW_REGS (sizeof (map_hw_reg_to_dwarf_reg) / sizeof (int))
146 #ifndef IS_DOUBLE_REG
147 #define IS_DOUBLE_REG(dwarf_reg) (dwarf_reg ? 0 : 0)
150 static gboolean dwarf_reg_to_hw_reg_inited
;
151 static gboolean hw_reg_to_dwarf_reg_inited
;
153 static int map_dwarf_reg_to_hw_reg
[NUM_DWARF_REGS
];
156 init_hw_reg_map (void)
158 #ifdef TARGET_POWERPC
159 map_hw_reg_to_dwarf_reg
[ppc_lr
] = DWARF_PC_REG
;
161 mono_memory_barrier ();
162 hw_reg_to_dwarf_reg_inited
= TRUE
;
166 * mono_hw_reg_to_dwarf_reg:
168 * Map the hardware register number REG to the register number used by DWARF.
171 mono_hw_reg_to_dwarf_reg (int reg
)
173 if (!hw_reg_to_dwarf_reg_inited
)
176 if (NUM_HW_REGS
== 0) {
177 g_assert_not_reached ();
180 return map_hw_reg_to_dwarf_reg
[reg
];
185 init_dwarf_reg_map (void)
189 g_assert (NUM_HW_REGS
> 0);
190 for (i
= 0; i
< NUM_HW_REGS
; ++i
) {
191 map_dwarf_reg_to_hw_reg
[mono_hw_reg_to_dwarf_reg (i
)] = i
;
194 mono_memory_barrier ();
195 dwarf_reg_to_hw_reg_inited
= TRUE
;
199 mono_dwarf_reg_to_hw_reg (int reg
)
201 if (!dwarf_reg_to_hw_reg_inited
)
202 init_dwarf_reg_map ();
204 return map_dwarf_reg_to_hw_reg
[reg
];
207 static G_GNUC_UNUSED
void
208 encode_uleb128 (guint32 value
, guint8
*buf
, guint8
**endbuf
)
213 guint8 b
= value
& 0x7f;
215 if (value
!= 0) /* more bytes to come */
223 static G_GNUC_UNUSED
void
224 encode_sleb128 (gint32 value
, guint8
*buf
, guint8
**endbuf
)
227 gboolean negative
= (value
< 0);
235 /* the following is unnecessary if the
236 * implementation of >>= uses an arithmetic rather
237 * than logical shift for a signed left operand
241 value
|= - (1 <<(size
- 7));
242 /* sign bit of byte is second high order bit (0x40) */
243 if ((value
== 0 && !(byte
& 0x40)) ||
244 (value
== -1 && (byte
& 0x40)))
255 decode_uleb128 (guint8
*buf
, guint8
**endbuf
)
265 res
= res
| (((int)(b
& 0x7f)) << shift
);
277 decode_sleb128 (guint8
*buf
, guint8
**endbuf
)
287 res
= res
| (((int)(b
& 0x7f)) << shift
);
290 if (shift
< 32 && (b
& 0x40))
291 res
|= - (1 << shift
);
302 mono_print_unwind_info (guint8
*unwind_info
, int unwind_info_len
)
305 int pos
, reg
, offset
, cfa_reg
, cfa_offset
;
309 while (p
< unwind_info
+ unwind_info_len
) {
313 case DW_CFA_advance_loc
:
320 offset
= decode_uleb128 (p
, &p
) * DWARF_DATA_ALIGN
;
321 if (reg
== DWARF_PC_REG
)
322 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos
, "pc", -offset
);
324 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg
)), -offset
);
331 cfa_reg
= decode_uleb128 (p
, &p
);
332 cfa_offset
= decode_uleb128 (p
, &p
);
333 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg
)), cfa_offset
);
335 case DW_CFA_def_cfa_offset
:
336 cfa_offset
= decode_uleb128 (p
, &p
);
337 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos
, cfa_offset
);
339 case DW_CFA_def_cfa_register
:
340 cfa_reg
= decode_uleb128 (p
, &p
);
341 printf ("CFA: [%x] def_cfa_reg: %s\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg
)));
343 case DW_CFA_offset_extended_sf
:
344 reg
= decode_uleb128 (p
, &p
);
345 offset
= decode_sleb128 (p
, &p
) * DWARF_DATA_ALIGN
;
346 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg
)), -offset
);
348 case DW_CFA_same_value
:
349 reg
= decode_uleb128 (p
, &p
);
350 printf ("CFA: [%x] same_value: %s\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg
)));
352 case DW_CFA_remember_state
:
353 printf ("CFA: [%x] remember_state\n", pos
);
355 case DW_CFA_restore_state
:
356 printf ("CFA: [%x] restore_state\n", pos
);
358 case DW_CFA_mono_advance_loc
:
359 printf ("CFA: [%x] mono_advance_loc\n", pos
);
361 case DW_CFA_advance_loc1
:
362 printf ("CFA: [%x] advance_loc1\n", pos
);
366 case DW_CFA_advance_loc2
:
367 printf ("CFA: [%x] advance_loc2\n", pos
);
371 case DW_CFA_advance_loc4
:
372 printf ("CFA: [%x] advance_loc4\n", pos
);
377 g_assert_not_reached ();
382 g_assert_not_reached ();
388 * mono_unwind_ops_encode_full:
390 * Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
391 * Return a pointer to malloc'ed memory.
392 * If ENABLE_EXTENSIONS is FALSE, avoid encoding the mono extension
393 * opcode (DW_CFA_mono_advance_loc).
396 mono_unwind_ops_encode_full (GSList
*unwind_ops
, guint32
*out_len
, gboolean enable_extensions
)
408 for (; l
; l
= l
->next
) {
411 op
= (MonoUnwindOp
*)l
->data
;
413 /* Convert the register from the hw encoding to the dwarf encoding */
414 reg
= mono_hw_reg_to_dwarf_reg (op
->reg
);
416 if (op
->op
== DW_CFA_mono_advance_loc
) {
417 /* This advances loc to its location */
421 /* Emit an advance_loc if neccesary */
422 while (op
->when
> loc
) {
423 if (op
->when
- loc
>= 65536) {
424 *p
++ = DW_CFA_advance_loc4
;
425 guint32 v
= (guint32
)(op
->when
- loc
);
427 g_assert (read32 (p
) == (guint32
)(op
->when
- loc
));
430 } else if (op
->when
- loc
>= 256) {
431 *p
++ = DW_CFA_advance_loc2
;
432 guint16 v
= (guint16
)(op
->when
- loc
);
434 g_assert (read16 (p
) == (guint32
)(op
->when
- loc
));
437 } else if (op
->when
- loc
>= 32) {
438 *p
++ = DW_CFA_advance_loc1
;
439 *(guint8
*)p
= (guint8
)(op
->when
- loc
);
442 } else if (op
->when
- loc
< 32) {
443 *p
++ = DW_CFA_advance_loc
| (op
->when
- loc
);
446 *p
++ = DW_CFA_advance_loc
| (30);
454 encode_uleb128 (reg
, p
, &p
);
455 encode_uleb128 (op
->val
, p
, &p
);
457 case DW_CFA_def_cfa_offset
:
459 encode_uleb128 (op
->val
, p
, &p
);
461 case DW_CFA_def_cfa_register
:
463 encode_uleb128 (reg
, p
, &p
);
465 case DW_CFA_same_value
:
467 encode_uleb128 (reg
, p
, &p
);
471 *p
++ = DW_CFA_offset_extended_sf
;
472 encode_uleb128 (reg
, p
, &p
);
473 encode_sleb128 (op
->val
/ DWARF_DATA_ALIGN
, p
, &p
);
475 *p
++ = DW_CFA_offset
| reg
;
476 encode_uleb128 (op
->val
/ DWARF_DATA_ALIGN
, p
, &p
);
479 case DW_CFA_remember_state
:
480 case DW_CFA_restore_state
:
483 case DW_CFA_mono_advance_loc
:
484 if (!enable_extensions
)
486 /* Only one location is supported */
487 g_assert (op
->val
== 0);
490 #if defined(TARGET_WIN32) && defined(TARGET_AMD64)
491 case DW_CFA_mono_sp_alloc_info_win64
:
492 case DW_CFA_mono_fp_alloc_info_win64
:
493 // Drop Windows specific unwind op's. These op's are currently
494 // only used when registering unwind info with Windows OS unwinder.
498 g_assert_not_reached ();
503 g_assert (p
- buf
< 4096);
505 res
= (guint8
*)g_malloc (p
- buf
);
506 memcpy (res
, buf
, p
- buf
);
511 mono_unwind_ops_encode (GSList
*unwind_ops
, guint32
*out_len
)
513 return mono_unwind_ops_encode_full (unwind_ops
, out_len
, TRUE
);
517 #define UNW_DEBUG(stmt) do { stmt; } while (0)
519 #define UNW_DEBUG(stmt) do { } while (0)
522 static G_GNUC_UNUSED
void
523 print_dwarf_state (int cfa_reg
, int cfa_offset
, int ip
, int nregs
, Loc
*locations
, guint8
*reg_saved
)
527 printf ("\t%x: cfa=r%d+%d ", ip
, cfa_reg
, cfa_offset
);
529 for (i
= 0; i
< nregs
; ++i
)
530 if (reg_saved
[i
] && locations
[i
].loc_type
== LOC_OFFSET
)
531 printf ("r%d@%d(cfa) ", i
, locations
[i
].offset
);
536 Loc locations
[NUM_HW_REGS
];
537 guint8 reg_saved
[NUM_HW_REGS
];
538 int cfa_reg
, cfa_offset
;
542 * Given the state of the current frame as stored in REGS, execute the unwind
543 * operations in unwind_info until the location counter reaches POS. The result is
544 * stored back into REGS. OUT_CFA will receive the value of the CFA.
545 * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
546 * On return, the nth entry will point to the address of the stack slot where register
547 * N was saved, or NULL, if it was not saved by this frame.
548 * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
549 * This function is signal safe.
551 * It returns FALSE on failure
554 mono_unwind_frame (guint8
*unwind_info
, guint32 unwind_info_len
,
555 guint8
*start_ip
, guint8
*end_ip
, guint8
*ip
, guint8
**mark_locations
,
556 mono_unwind_reg_t
*regs
, int nregs
,
557 host_mgreg_t
**save_locations
, int save_locations_len
,
560 Loc locations
[NUM_HW_REGS
];
561 guint8 reg_saved
[NUM_HW_REGS
];
562 int pos
, reg
, hwreg
, cfa_reg
= -1, cfa_offset
= 0, offset
;
565 UnwindState state_stack
[1];
568 memset (reg_saved
, 0, sizeof (reg_saved
));
569 state_stack
[0].cfa_reg
= -1;
570 state_stack
[0].cfa_offset
= 0;
577 while (pos
<= ip
- start_ip
&& p
< unwind_info
+ unwind_info_len
) {
581 case DW_CFA_advance_loc
:
582 UNW_DEBUG (print_dwarf_state (cfa_reg
, cfa_offset
, pos
, nregs
, locations
));
589 if (reg
>= NUM_DWARF_REGS
) {
590 /* Register we don't care about, like a caller save reg in a cold cconv */
591 decode_uleb128 (p
, &p
);
594 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
595 reg_saved
[hwreg
] = TRUE
;
596 locations
[hwreg
].loc_type
= LOC_OFFSET
;
597 locations
[hwreg
].offset
= decode_uleb128 (p
, &p
) * DWARF_DATA_ALIGN
;
604 cfa_reg
= decode_uleb128 (p
, &p
);
605 cfa_offset
= decode_uleb128 (p
, &p
);
607 case DW_CFA_def_cfa_offset
:
608 cfa_offset
= decode_uleb128 (p
, &p
);
610 case DW_CFA_def_cfa_register
:
611 cfa_reg
= decode_uleb128 (p
, &p
);
613 case DW_CFA_offset_extended_sf
:
614 reg
= decode_uleb128 (p
, &p
);
615 offset
= decode_sleb128 (p
, &p
);
616 if (reg
>= NUM_DWARF_REGS
)
618 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
619 reg_saved
[hwreg
] = TRUE
;
620 locations
[hwreg
].loc_type
= LOC_OFFSET
;
621 locations
[hwreg
].offset
= offset
* DWARF_DATA_ALIGN
;
623 case DW_CFA_offset_extended
:
624 reg
= decode_uleb128 (p
, &p
);
625 offset
= decode_uleb128 (p
, &p
);
626 if (reg
>= NUM_DWARF_REGS
)
628 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
629 reg_saved
[hwreg
] = TRUE
;
630 locations
[hwreg
].loc_type
= LOC_OFFSET
;
631 locations
[hwreg
].offset
= offset
* DWARF_DATA_ALIGN
;
633 case DW_CFA_same_value
:
634 reg
= decode_uleb128 (p
, &p
);
635 if (reg
>= NUM_DWARF_REGS
)
637 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
638 locations
[hwreg
].loc_type
= LOC_SAME
;
640 case DW_CFA_advance_loc1
:
644 case DW_CFA_advance_loc2
:
648 case DW_CFA_advance_loc4
:
652 case DW_CFA_remember_state
:
653 if (state_stack_pos
!= 0) {
654 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
657 memcpy (&state_stack
[0].locations
, &locations
, sizeof (locations
));
658 memcpy (&state_stack
[0].reg_saved
, ®_saved
, sizeof (reg_saved
));
659 state_stack
[0].cfa_reg
= cfa_reg
;
660 state_stack
[0].cfa_offset
= cfa_offset
;
663 case DW_CFA_restore_state
:
664 if (state_stack_pos
!= 1) {
665 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
669 memcpy (&locations
, &state_stack
[0].locations
, sizeof (locations
));
670 memcpy (®_saved
, &state_stack
[0].reg_saved
, sizeof (reg_saved
));
671 cfa_reg
= state_stack
[0].cfa_reg
;
672 cfa_offset
= state_stack
[0].cfa_offset
;
674 case DW_CFA_mono_advance_loc
:
675 if (!mark_locations
[0]) {
676 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
679 pos
= mark_locations
[0] - start_ip
;
682 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__
, __LINE__
);
688 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__
, __LINE__
);
694 memset (save_locations
, 0, save_locations_len
* sizeof (host_mgreg_t
*));
697 mono_runtime_printf_err ("Unset cfa_reg in method %s. Memory around ip (%p):", mono_get_method_from_ip (ip
), ip
);
698 mono_dump_mem (ip
- 0x10, 0x40);
701 cfa_val
= (guint8
*)regs
[mono_dwarf_reg_to_hw_reg (cfa_reg
)] + cfa_offset
;
702 for (hwreg
= 0; hwreg
< NUM_HW_REGS
; ++hwreg
) {
703 if (reg_saved
[hwreg
] && locations
[hwreg
].loc_type
== LOC_OFFSET
) {
704 int dwarfreg
= mono_hw_reg_to_dwarf_reg (hwreg
);
705 if (hwreg
>= nregs
) {
706 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
709 if (IS_DOUBLE_REG (dwarfreg
))
710 regs
[hwreg
] = *(guint64
*)(cfa_val
+ locations
[hwreg
].offset
);
712 regs
[hwreg
] = *(host_mgreg_t
*)(cfa_val
+ locations
[hwreg
].offset
);
713 if (save_locations
&& hwreg
< save_locations_len
)
714 save_locations
[hwreg
] = (host_mgreg_t
*)(cfa_val
+ locations
[hwreg
].offset
);
725 mono_unwind_init (void)
727 mono_os_mutex_init_recursive (&unwind_mutex
);
729 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &unwind_info_size
);
733 mono_unwind_cleanup (void)
737 mono_os_mutex_destroy (&unwind_mutex
);
742 for (i
= 0; i
< cached_info_next
; ++i
) {
743 MonoUnwindInfo
*cached
= cached_info
[i
];
747 g_free (cached_info
);
749 for (GSList
*cursor
= cached_info_list
; cursor
!= NULL
; cursor
= cursor
->next
)
750 g_free (cursor
->data
);
752 g_slist_free (cached_info_list
);
756 * mono_cache_unwind_info
758 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
759 * to mono_get_cached_unwind_info to get a cached copy of the info.
760 * A copy is made of the unwind info.
761 * This function is useful for two reasons:
762 * - many methods have the same unwind info
763 * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
766 mono_cache_unwind_info (guint8
*unwind_info
, guint32 unwind_info_len
)
769 MonoUnwindInfo
*info
;
773 if (cached_info
== NULL
) {
774 cached_info_size
= 16;
775 cached_info
= g_new0 (MonoUnwindInfo
*, cached_info_size
);
778 for (i
= 0; i
< cached_info_next
; ++i
) {
779 MonoUnwindInfo
*cached
= cached_info
[i
];
781 if (cached
->len
== unwind_info_len
&& memcmp (cached
->info
, unwind_info
, unwind_info_len
) == 0) {
787 info
= (MonoUnwindInfo
*)g_malloc (sizeof (MonoUnwindInfo
) + unwind_info_len
);
788 info
->len
= unwind_info_len
;
789 memcpy (&info
->info
, unwind_info
, unwind_info_len
);
791 i
= cached_info_next
;
793 if (cached_info_next
>= cached_info_size
) {
794 MonoUnwindInfo
**new_table
;
797 * Avoid freeing the old table so mono_get_cached_unwind_info ()
798 * doesn't need locks/hazard pointers.
801 new_table
= g_new0 (MonoUnwindInfo
*, cached_info_size
* 2);
803 memcpy (new_table
, cached_info
, cached_info_size
* sizeof (MonoUnwindInfo
*));
805 mono_memory_barrier ();
807 cached_info_list
= g_slist_prepend (cached_info_list
, cached_info
);
809 cached_info
= new_table
;
811 cached_info_size
*= 2;
814 cached_info
[cached_info_next
++] = info
;
816 unwind_info_size
+= sizeof (MonoUnwindInfo
) + unwind_info_len
;
823 * This function is signal safe.
826 mono_get_cached_unwind_info (guint32 index
, guint32
*unwind_info_len
)
828 MonoUnwindInfo
**table
;
829 MonoUnwindInfo
*info
;
833 * This doesn't need any locks/hazard pointers,
834 * since new tables are copies of the old ones.
838 info
= table
[index
];
840 *unwind_info_len
= info
->len
;
847 * mono_unwind_get_dwarf_data_align:
849 * Return the data alignment used by the encoded unwind information.
852 mono_unwind_get_dwarf_data_align (void)
854 return DWARF_DATA_ALIGN
;
858 * mono_unwind_get_dwarf_pc_reg:
860 * Return the dwarf register number of the register holding the ip of the
864 mono_unwind_get_dwarf_pc_reg (void)
870 decode_cie_op (guint8
*p
, guint8
**endp
)
875 case DW_CFA_advance_loc
:
880 decode_uleb128 (p
, &p
);
887 decode_uleb128 (p
, &p
);
888 decode_uleb128 (p
, &p
);
890 case DW_CFA_def_cfa_offset
:
891 decode_uleb128 (p
, &p
);
893 case DW_CFA_def_cfa_register
:
894 decode_uleb128 (p
, &p
);
896 case DW_CFA_advance_loc4
:
899 case DW_CFA_offset_extended_sf
:
900 decode_uleb128 (p
, &p
);
901 decode_uleb128 (p
, &p
);
904 g_assert_not_reached ();
909 g_assert_not_reached ();
916 read_encoded_val (guint32 encoding
, guint8
*p
, guint8
**endp
)
920 switch (encoding
& 0xf) {
921 case DW_EH_PE_sdata8
:
925 case DW_EH_PE_sdata4
:
930 g_assert_not_reached ();
940 * Decode the Mono specific Language Specific Data Area generated by LLVM.
941 * This function is async safe.
944 decode_lsda (guint8
*lsda
, guint8
*code
, MonoJitExceptionInfo
*ex_info
, gpointer
*type_info
, guint32
*ex_info_len
, int *this_reg
, int *this_offset
)
947 int i
, ncall_sites
, this_encoding
;
948 guint32 mono_magic
, version
;
952 /* This is the modified LSDA generated by the LLVM mono branch */
953 mono_magic
= decode_uleb128 (p
, &p
);
954 g_assert (mono_magic
== 0x4d4fef4f);
955 version
= decode_uleb128 (p
, &p
);
956 g_assert (version
== 1);
959 if (this_encoding
== DW_EH_PE_udata4
) {
960 gint32 op
, reg
, offset
;
962 /* 'this' location */
964 g_assert (op
== DW_OP_bregx
);
966 reg
= decode_uleb128 (p
, &p
);
967 offset
= decode_sleb128 (p
, &p
);
969 *this_reg
= mono_dwarf_reg_to_hw_reg (reg
);
970 *this_offset
= offset
;
972 g_assert (this_encoding
== DW_EH_PE_omit
);
977 ncall_sites
= decode_uleb128 (p
, &p
);
978 p
= (guint8
*)ALIGN_TO ((gsize
)p
, 4);
981 *ex_info_len
= ncall_sites
;
983 for (i
= 0; i
< ncall_sites
; ++i
) {
984 int block_start_offset
, block_size
, landing_pad
;
987 block_start_offset
= read32 (p
);
988 p
+= sizeof (gint32
);
989 block_size
= read32 (p
);
990 p
+= sizeof (gint32
);
991 landing_pad
= read32 (p
);
992 p
+= sizeof (gint32
);
994 p
+= sizeof (gint32
);
996 g_assert (landing_pad
);
997 g_assert (((size_t)tinfo
% 4) == 0);
998 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
1002 type_info
[i
] = tinfo
;
1003 ex_info
[i
].try_start
= code
+ block_start_offset
;
1004 ex_info
[i
].try_end
= code
+ block_start_offset
+ block_size
;
1005 ex_info
[i
].handler_start
= code
+ landing_pad
;
1011 * mono_unwind_decode_fde:
1013 * Decode a DWARF FDE entry, returning the unwind opcodes.
1014 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
1015 * only try_start, try_end and handler_start is set.
1016 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
1020 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
)
1022 guint8
*p
, *cie
, *fde_current
, *fde_aug
= NULL
, *code
, *fde_cfi
, *cie_cfi
;
1023 gint32 fde_len
, cie_offset
, pc_begin
, pc_range
, aug_len
;
1024 gint32 cie_len
, cie_id
, cie_version
, code_align
, data_align
, return_reg
;
1025 gint32 i
, cie_aug_len
, buf_len
;
1028 gboolean has_fde_augmentation
= FALSE
;
1031 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
1034 /* This is generated by JITDwarfEmitter::EmitEHFrame () */
1043 // FIXME: Endianess ?
1044 fde_len
= *(guint32
*)p
;
1045 g_assert (fde_len
!= 0xffffffff && fde_len
!= 0);
1047 cie_offset
= *(guint32
*)p
;
1048 cie
= p
- cie_offset
;
1054 cie_len
= *(guint32
*)p
;
1056 cie_id
= *(guint32
*)p
;
1057 g_assert (cie_id
== 0);
1060 g_assert (cie_version
== 1);
1062 cie_aug_str
= (char*)p
;
1063 p
+= strlen (cie_aug_str
) + 1;
1064 code_align
= decode_uleb128 (p
, &p
);
1065 data_align
= decode_sleb128 (p
, &p
);
1066 return_reg
= decode_uleb128 (p
, &p
);
1067 if (strstr (cie_aug_str
, "z")) {
1071 cie_aug_len
= decode_uleb128 (p
, &p
);
1073 has_fde_augmentation
= TRUE
;
1076 for (i
= 0; cie_aug_str
[i
] != '\0'; ++i
) {
1077 switch (cie_aug_str
[i
]) {
1083 read_encoded_val (p_encoding
, p
, &p
);
1086 g_assert ((*p
== (DW_EH_PE_sdata4
|DW_EH_PE_pcrel
)) || (*p
== (DW_EH_PE_sdata8
|DW_EH_PE_pcrel
)));
1090 g_assert (*p
== (DW_EH_PE_sdata4
|DW_EH_PE_pcrel
));
1094 g_assert_not_reached ();
1104 /* Continue decoding FDE */
1106 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
1107 pc_begin
= *(gint32
*)p
;
1108 code
= p
+ pc_begin
;
1110 pc_range
= *(guint32
*)p
;
1112 if (has_fde_augmentation
) {
1113 aug_len
= decode_uleb128 (p
, &p
);
1122 *code_len
= pc_range
;
1129 /* Decode FDE augmention */
1134 /* sdata|pcrel encoding */
1136 lsda_offset
= read32 (fde_aug
);
1137 else if (aug_len
== 8)
1138 lsda_offset
= *(gint64
*)fde_aug
;
1140 g_assert_not_reached ();
1141 if (lsda_offset
!= 0) {
1142 lsda
= fde_aug
+ lsda_offset
;
1144 /* Get the lengths first */
1146 decode_lsda (lsda
, code
, NULL
, NULL
, &len
, this_reg
, this_offset
);
1149 *ex_info
= (MonoJitExceptionInfo
*)g_malloc0 (len
* sizeof (MonoJitExceptionInfo
));
1151 *type_info
= (gpointer
*)g_malloc0 (len
* sizeof (gpointer
));
1153 decode_lsda (lsda
, code
, ex_info
? *ex_info
: NULL
, type_info
? *type_info
: NULL
, ex_info_len
, this_reg
, this_offset
);
1157 /* Make sure the FDE uses the same constants as we do */
1158 g_assert (code_align
== 1);
1159 g_assert (data_align
== DWARF_DATA_ALIGN
);
1160 g_assert (return_reg
== DWARF_PC_REG
);
1162 buf_len
= (cie
+ cie_len
+ 4 - cie_cfi
) + (fde
+ fde_len
+ 4 - fde_cfi
);
1163 buf
= (guint8
*)g_malloc0 (buf_len
);
1167 while (p
< cie
+ cie_len
+ 4) {
1168 if (*p
== DW_CFA_nop
)
1171 decode_cie_op (p
, &p
);
1173 memcpy (buf
+ i
, cie_cfi
, p
- cie_cfi
);
1177 while (p
< fde
+ fde_len
+ 4) {
1178 if (*p
== DW_CFA_nop
)
1181 decode_cie_op (p
, &p
);
1183 memcpy (buf
+ i
, fde_cfi
, p
- fde_cfi
);
1185 g_assert (i
<= buf_len
);
1189 return (guint8
*)g_realloc (buf
, i
);
1193 * mono_unwind_decode_mono_fde:
1195 * Decode an FDE entry in the LLVM emitted mono EH frame.
1196 * If EI/TYPE_INFO/UNW_INFO are NULL, compute only the value of the scalar fields in INFO.
1198 * - Fill out EX_INFO with try_start, try_end and handler_start.
1199 * - Fill out TYPE_INFO with the ttype table from the LSDA.
1200 * - Fill out UNW_INFO with the unwind info.
1201 * This function is async safe.
1204 mono_unwind_decode_llvm_mono_fde (guint8
*fde
, int fde_len
, guint8
*cie
, guint8
*code
, MonoLLVMFDEInfo
*res
, MonoJitExceptionInfo
*ex_info
, gpointer
*type_info
, guint8
*unw_info
)
1206 guint8
*p
, *fde_aug
, *cie_cfi
, *fde_cfi
, *buf
;
1207 int has_aug
, aug_len
, cie_cfi_len
, fde_cfi_len
;
1208 gint32 code_align
, data_align
, return_reg
, pers_encoding
;
1210 memset (res
, 0, sizeof (*res
));
1212 res
->this_offset
= -1;
1214 /* fde points to data emitted by LLVM in DwarfMonoException::EmitMonoEHFrame () */
1219 aug_len
= read32 (p
);
1231 /* The LSDA is embedded directly into the FDE */
1234 /* Get the lengths first */
1235 decode_lsda (lsda
, code
, NULL
, NULL
, &res
->ex_info_len
, &res
->this_reg
, &res
->this_offset
);
1237 decode_lsda (lsda
, code
, ex_info
, type_info
, NULL
, &res
->this_reg
, &res
->this_offset
);
1242 code_align
= decode_uleb128 (p
, &p
);
1243 data_align
= decode_sleb128 (p
, &p
);
1244 return_reg
= decode_uleb128 (p
, &p
);
1247 if (pers_encoding
!= DW_EH_PE_omit
)
1248 read_encoded_val (pers_encoding
, p
, &p
);
1252 /* Make sure the FDE uses the same constants as we do */
1253 g_assert (code_align
== 1);
1254 g_assert (data_align
== DWARF_DATA_ALIGN
);
1255 g_assert (return_reg
== DWARF_PC_REG
);
1257 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1260 if (*p
== DW_CFA_nop
)
1263 decode_cie_op (p
, &p
);
1265 cie_cfi_len
= p
- cie_cfi
;
1266 fde_cfi_len
= (fde
+ fde_len
- fde_cfi
);
1270 memcpy (buf
, cie_cfi
, cie_cfi_len
);
1271 memcpy (buf
+ cie_cfi_len
, fde_cfi
, fde_cfi_len
);
1274 res
->unw_info_len
= cie_cfi_len
+ fde_cfi_len
;
1278 * mono_unwind_get_cie_program:
1280 * Get the unwind bytecode for the DWARF CIE.
1283 mono_unwind_get_cie_program (void)
1285 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC) || defined(TARGET_ARM)
1286 return mono_arch_get_cie_program ();