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 ();
181 return map_hw_reg_to_dwarf_reg
[reg
];
185 init_dwarf_reg_map (void)
187 g_assert (NUM_HW_REGS
> 0);
188 for (int i
= 0; i
< NUM_HW_REGS
; ++i
) {
189 map_dwarf_reg_to_hw_reg
[mono_hw_reg_to_dwarf_reg (i
)] = i
;
192 mono_memory_barrier ();
193 dwarf_reg_to_hw_reg_inited
= TRUE
;
197 mono_dwarf_reg_to_hw_reg (int reg
)
199 if (!dwarf_reg_to_hw_reg_inited
)
200 init_dwarf_reg_map ();
202 return map_dwarf_reg_to_hw_reg
[reg
];
205 static G_GNUC_UNUSED
void
206 encode_uleb128 (guint32 value
, guint8
*buf
, guint8
**endbuf
)
211 guint8 b
= value
& 0x7f;
213 if (value
!= 0) /* more bytes to come */
221 static G_GNUC_UNUSED
void
222 encode_sleb128 (gint32 value
, guint8
*buf
, guint8
**endbuf
)
225 gboolean negative
= (value
< 0);
233 /* the following is unnecessary if the
234 * implementation of >>= uses an arithmetic rather
235 * than logical shift for a signed left operand
239 value
|= - (1 <<(size
- 7));
240 /* sign bit of byte is second high order bit (0x40) */
241 if ((value
== 0 && !(byte
& 0x40)) ||
242 (value
== -1 && (byte
& 0x40)))
253 decode_uleb128 (guint8
*buf
, guint8
**endbuf
)
263 res
= res
| (((int)(b
& 0x7f)) << shift
);
275 decode_sleb128 (guint8
*buf
, guint8
**endbuf
)
287 res
= res
| (((int)(b
& 0x7f)) << shift
);
291 if (shift
< 32 && (b
& 0x40))
292 res
|= - (1 << shift
);
300 mono_print_unwind_info (guint8
*unwind_info
, int unwind_info_len
)
303 int pos
, reg
, offset
, cfa_reg
, cfa_offset
;
307 while (p
< unwind_info
+ unwind_info_len
) {
311 case DW_CFA_advance_loc
:
313 printf ("CFA: [%x] advance loc\n",pos
);
319 offset
= decode_uleb128 (p
, &p
) * DWARF_DATA_ALIGN
;
320 if (reg
== DWARF_PC_REG
)
321 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos
, "pc", -offset
);
323 printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg
)), -offset
);
330 cfa_reg
= decode_uleb128 (p
, &p
);
331 cfa_offset
= decode_uleb128 (p
, &p
);
332 printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg
)), cfa_offset
);
334 case DW_CFA_def_cfa_offset
:
335 cfa_offset
= decode_uleb128 (p
, &p
);
336 printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos
, cfa_offset
);
338 case DW_CFA_def_cfa_register
:
339 cfa_reg
= decode_uleb128 (p
, &p
);
340 printf ("CFA: [%x] def_cfa_reg: %s\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg
)));
342 case DW_CFA_offset_extended_sf
:
343 reg
= decode_uleb128 (p
, &p
);
344 offset
= decode_sleb128 (p
, &p
) * DWARF_DATA_ALIGN
;
345 printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg
)), -offset
);
347 case DW_CFA_same_value
:
348 reg
= decode_uleb128 (p
, &p
);
349 printf ("CFA: [%x] same_value: %s\n", pos
, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg
)));
351 case DW_CFA_remember_state
:
352 printf ("CFA: [%x] remember_state\n", pos
);
354 case DW_CFA_restore_state
:
355 printf ("CFA: [%x] restore_state\n", pos
);
357 case DW_CFA_mono_advance_loc
:
358 printf ("CFA: [%x] mono_advance_loc\n", pos
);
360 case DW_CFA_advance_loc1
:
361 printf ("CFA: [%x] advance_loc1\n", pos
);
365 case DW_CFA_advance_loc2
:
366 printf ("CFA: [%x] advance_loc2\n", pos
);
370 case DW_CFA_advance_loc4
:
371 printf ("CFA: [%x] advance_loc4\n", pos
);
376 g_assert_not_reached ();
381 g_assert_not_reached ();
387 * mono_unwind_ops_encode_full:
389 * Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
390 * Return a pointer to malloc'ed memory.
391 * If ENABLE_EXTENSIONS is FALSE, avoid encoding the mono extension
392 * opcode (DW_CFA_mono_advance_loc).
395 mono_unwind_ops_encode_full (GSList
*unwind_ops
, guint32
*out_len
, gboolean enable_extensions
)
404 for (GSList
*l
= unwind_ops
; l
; l
= l
->next
) {
407 op
= (MonoUnwindOp
*)l
->data
;
409 /* Convert the register from the hw encoding to the dwarf encoding */
410 reg
= mono_hw_reg_to_dwarf_reg (op
->reg
);
412 if (op
->op
== DW_CFA_mono_advance_loc
) {
413 /* This advances loc to its location */
417 /* Emit an advance_loc if neccesary */
418 while (op
->when
> loc
) {
419 if (op
->when
- loc
>= 65536) {
420 *p
++ = DW_CFA_advance_loc4
;
421 guint32 v
= (guint32
)(op
->when
- loc
);
423 g_assert (read32 (p
) == GUINT32_TO_LE((guint32
)(op
->when
- loc
)));
426 } else if (op
->when
- loc
>= 256) {
427 *p
++ = DW_CFA_advance_loc2
;
428 guint16 v
= (guint16
)(op
->when
- loc
);
430 g_assert (read16 (p
) == GUINT16_TO_LE((guint32
)(op
->when
- loc
)));
433 } else if (op
->when
- loc
>= 32) {
434 *p
++ = DW_CFA_advance_loc1
;
435 *(guint8
*)p
= (guint8
)(op
->when
- loc
);
438 } else if (op
->when
- loc
< 32) {
439 *p
++ = DW_CFA_advance_loc
| (op
->when
- loc
);
442 *p
++ = DW_CFA_advance_loc
| (30);
450 encode_uleb128 (reg
, p
, &p
);
451 encode_uleb128 (op
->val
, p
, &p
);
453 case DW_CFA_def_cfa_offset
:
455 encode_uleb128 (op
->val
, p
, &p
);
457 case DW_CFA_def_cfa_register
:
459 encode_uleb128 (reg
, p
, &p
);
461 case DW_CFA_same_value
:
463 encode_uleb128 (reg
, p
, &p
);
467 *p
++ = DW_CFA_offset_extended_sf
;
468 encode_uleb128 (reg
, p
, &p
);
469 encode_sleb128 (op
->val
/ DWARF_DATA_ALIGN
, p
, &p
);
471 *p
++ = DW_CFA_offset
| reg
;
472 encode_uleb128 (op
->val
/ DWARF_DATA_ALIGN
, p
, &p
);
475 case DW_CFA_remember_state
:
476 case DW_CFA_restore_state
:
479 case DW_CFA_mono_advance_loc
:
480 if (!enable_extensions
)
482 /* Only one location is supported */
483 g_assert (op
->val
== 0);
486 #if defined(TARGET_WIN32) && defined(TARGET_AMD64)
487 case DW_CFA_mono_sp_alloc_info_win64
:
488 case DW_CFA_mono_fp_alloc_info_win64
:
489 // Drop Windows specific unwind op's. These op's are currently
490 // only used when registering unwind info with Windows OS unwinder.
494 g_assert_not_reached ();
499 g_assert (p
- buf
< 4096);
501 res
= (guint8
*)g_malloc (p
- buf
);
502 memcpy (res
, buf
, p
- buf
);
507 mono_unwind_ops_encode (GSList
*unwind_ops
, guint32
*out_len
)
509 return mono_unwind_ops_encode_full (unwind_ops
, out_len
, TRUE
);
513 #define UNW_DEBUG(stmt) do { stmt; } while (0)
515 #define UNW_DEBUG(stmt) do { } while (0)
518 static G_GNUC_UNUSED
void
519 print_dwarf_state (int cfa_reg
, int cfa_offset
, int ip
, int nregs
, Loc
*locations
, guint8
*reg_saved
)
521 printf ("\t%x: cfa=r%d+%d ", ip
, cfa_reg
, cfa_offset
);
523 for (int i
= 0; i
< nregs
; ++i
)
524 if (reg_saved
[i
] && locations
[i
].loc_type
== LOC_OFFSET
)
525 printf ("r%d@%d(cfa) ", i
, locations
[i
].offset
);
530 Loc locations
[NUM_HW_REGS
];
531 guint8 reg_saved
[NUM_HW_REGS
];
532 int cfa_reg
, cfa_offset
;
536 * Given the state of the current frame as stored in REGS, execute the unwind
537 * operations in unwind_info until the location counter reaches POS. The result is
538 * stored back into REGS. OUT_CFA will receive the value of the CFA.
539 * If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
540 * On return, the nth entry will point to the address of the stack slot where register
541 * N was saved, or NULL, if it was not saved by this frame.
542 * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
543 * This function is signal safe.
545 * It returns FALSE on failure
548 mono_unwind_frame (guint8
*unwind_info
, guint32 unwind_info_len
,
549 guint8
*start_ip
, guint8
*end_ip
, guint8
*ip
, guint8
**mark_locations
,
550 mono_unwind_reg_t
*regs
, int nregs
,
551 host_mgreg_t
**save_locations
, int save_locations_len
,
554 Loc locations
[NUM_HW_REGS
];
555 guint8 reg_saved
[NUM_HW_REGS
];
556 int pos
, reg
, hwreg
, cfa_reg
= -1, cfa_offset
= 0, offset
;
559 UnwindState state_stack
[1];
562 memset (reg_saved
, 0, sizeof (reg_saved
));
563 state_stack
[0].cfa_reg
= -1;
564 state_stack
[0].cfa_offset
= 0;
571 while (pos
<= ip
- start_ip
&& p
< unwind_info
+ unwind_info_len
) {
575 case DW_CFA_advance_loc
:
576 UNW_DEBUG (print_dwarf_state (cfa_reg
, cfa_offset
, pos
, nregs
, locations
));
583 if (reg
>= NUM_DWARF_REGS
) {
584 /* Register we don't care about, like a caller save reg in a cold cconv */
585 decode_uleb128 (p
, &p
);
588 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
589 reg_saved
[hwreg
] = TRUE
;
590 locations
[hwreg
].loc_type
= LOC_OFFSET
;
591 locations
[hwreg
].offset
= decode_uleb128 (p
, &p
) * DWARF_DATA_ALIGN
;
598 cfa_reg
= decode_uleb128 (p
, &p
);
599 cfa_offset
= decode_uleb128 (p
, &p
);
601 case DW_CFA_def_cfa_offset
:
602 cfa_offset
= decode_uleb128 (p
, &p
);
604 case DW_CFA_def_cfa_register
:
605 cfa_reg
= decode_uleb128 (p
, &p
);
607 case DW_CFA_offset_extended_sf
:
608 reg
= decode_uleb128 (p
, &p
);
609 offset
= decode_sleb128 (p
, &p
);
610 if (reg
>= NUM_DWARF_REGS
)
612 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
613 reg_saved
[hwreg
] = TRUE
;
614 locations
[hwreg
].loc_type
= LOC_OFFSET
;
615 locations
[hwreg
].offset
= offset
* DWARF_DATA_ALIGN
;
617 case DW_CFA_offset_extended
:
618 reg
= decode_uleb128 (p
, &p
);
619 offset
= decode_uleb128 (p
, &p
);
620 if (reg
>= NUM_DWARF_REGS
)
622 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
623 reg_saved
[hwreg
] = TRUE
;
624 locations
[hwreg
].loc_type
= LOC_OFFSET
;
625 locations
[hwreg
].offset
= offset
* DWARF_DATA_ALIGN
;
627 case DW_CFA_same_value
:
628 reg
= decode_uleb128 (p
, &p
);
629 if (reg
>= NUM_DWARF_REGS
)
631 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
632 locations
[hwreg
].loc_type
= LOC_SAME
;
634 case DW_CFA_advance_loc1
:
638 case DW_CFA_advance_loc2
:
642 case DW_CFA_advance_loc4
:
646 case DW_CFA_remember_state
:
647 if (state_stack_pos
!= 0) {
648 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
651 memcpy (&state_stack
[0].locations
, &locations
, sizeof (locations
));
652 memcpy (&state_stack
[0].reg_saved
, ®_saved
, sizeof (reg_saved
));
653 state_stack
[0].cfa_reg
= cfa_reg
;
654 state_stack
[0].cfa_offset
= cfa_offset
;
657 case DW_CFA_restore_state
:
658 if (state_stack_pos
!= 1) {
659 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
663 memcpy (&locations
, &state_stack
[0].locations
, sizeof (locations
));
664 memcpy (®_saved
, &state_stack
[0].reg_saved
, sizeof (reg_saved
));
665 cfa_reg
= state_stack
[0].cfa_reg
;
666 cfa_offset
= state_stack
[0].cfa_offset
;
668 case DW_CFA_mono_advance_loc
:
669 if (!mark_locations
[0]) {
670 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
673 pos
= mark_locations
[0] - start_ip
;
676 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__
, __LINE__
);
682 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__
, __LINE__
);
688 memset (save_locations
, 0, save_locations_len
* sizeof (host_mgreg_t
*));
691 mono_runtime_printf_err ("Unset cfa_reg in method %s. Memory around ip (%p):", mono_get_method_from_ip (ip
), ip
);
692 mono_dump_mem (ip
- 0x10, 0x40);
695 cfa_val
= (guint8
*)regs
[mono_dwarf_reg_to_hw_reg (cfa_reg
)] + cfa_offset
;
696 for (hwreg
= 0; hwreg
< NUM_HW_REGS
; ++hwreg
) {
697 if (reg_saved
[hwreg
] && locations
[hwreg
].loc_type
== LOC_OFFSET
) {
698 int dwarfreg
= mono_hw_reg_to_dwarf_reg (hwreg
);
699 if (hwreg
>= nregs
) {
700 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
703 if (IS_DOUBLE_REG (dwarfreg
))
704 regs
[hwreg
] = *(guint64
*)(cfa_val
+ locations
[hwreg
].offset
);
706 regs
[hwreg
] = *(host_mgreg_t
*)(cfa_val
+ locations
[hwreg
].offset
);
707 if (save_locations
&& hwreg
< save_locations_len
)
708 save_locations
[hwreg
] = (host_mgreg_t
*)(cfa_val
+ locations
[hwreg
].offset
);
719 mono_unwind_init (void)
721 mono_os_mutex_init_recursive (&unwind_mutex
);
723 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &unwind_info_size
);
727 mono_unwind_cleanup (void)
729 mono_os_mutex_destroy (&unwind_mutex
);
734 for (int i
= 0; i
< cached_info_next
; ++i
) {
735 MonoUnwindInfo
*cached
= cached_info
[i
];
739 g_free (cached_info
);
741 for (GSList
*cursor
= cached_info_list
; cursor
!= NULL
; cursor
= cursor
->next
)
742 g_free (cursor
->data
);
744 g_slist_free (cached_info_list
);
748 * mono_cache_unwind_info
750 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
751 * to mono_get_cached_unwind_info to get a cached copy of the info.
752 * A copy is made of the unwind info.
753 * This function is useful for two reasons:
754 * - many methods have the same unwind info
755 * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
758 mono_cache_unwind_info (guint8
*unwind_info
, guint32 unwind_info_len
)
761 MonoUnwindInfo
*info
;
765 if (cached_info
== NULL
) {
766 cached_info_size
= 16;
767 cached_info
= g_new0 (MonoUnwindInfo
*, cached_info_size
);
770 for (i
= 0; i
< cached_info_next
; ++i
) {
771 MonoUnwindInfo
*cached
= cached_info
[i
];
773 if (cached
->len
== unwind_info_len
&& memcmp (cached
->info
, unwind_info
, unwind_info_len
) == 0) {
779 info
= (MonoUnwindInfo
*)g_malloc (sizeof (MonoUnwindInfo
) + unwind_info_len
);
780 info
->len
= unwind_info_len
;
781 memcpy (&info
->info
, unwind_info
, unwind_info_len
);
783 i
= cached_info_next
;
785 if (cached_info_next
>= cached_info_size
) {
786 MonoUnwindInfo
**new_table
;
789 * Avoid freeing the old table so mono_get_cached_unwind_info ()
790 * doesn't need locks/hazard pointers.
793 new_table
= g_new0 (MonoUnwindInfo
*, cached_info_size
* 2);
795 memcpy (new_table
, cached_info
, cached_info_size
* sizeof (MonoUnwindInfo
*));
797 mono_memory_barrier ();
799 cached_info_list
= g_slist_prepend (cached_info_list
, cached_info
);
801 cached_info
= new_table
;
803 cached_info_size
*= 2;
806 cached_info
[cached_info_next
++] = info
;
808 unwind_info_size
+= sizeof (MonoUnwindInfo
) + unwind_info_len
;
815 * This function is signal safe.
818 mono_get_cached_unwind_info (guint32 index
, guint32
*unwind_info_len
)
820 MonoUnwindInfo
**table
;
821 MonoUnwindInfo
*info
;
825 * This doesn't need any locks/hazard pointers,
826 * since new tables are copies of the old ones.
830 info
= table
[index
];
832 *unwind_info_len
= info
->len
;
839 * mono_unwind_get_dwarf_data_align:
841 * Return the data alignment used by the encoded unwind information.
844 mono_unwind_get_dwarf_data_align (void)
846 return DWARF_DATA_ALIGN
;
850 * mono_unwind_get_dwarf_pc_reg:
852 * Return the dwarf register number of the register holding the ip of the
856 mono_unwind_get_dwarf_pc_reg (void)
862 decode_cie_op (guint8
*p
, guint8
**endp
)
867 case DW_CFA_advance_loc
:
872 decode_uleb128 (p
, &p
);
879 decode_uleb128 (p
, &p
);
880 decode_uleb128 (p
, &p
);
882 case DW_CFA_def_cfa_offset
:
883 decode_uleb128 (p
, &p
);
885 case DW_CFA_def_cfa_register
:
886 decode_uleb128 (p
, &p
);
888 case DW_CFA_advance_loc4
:
891 case DW_CFA_offset_extended_sf
:
892 decode_uleb128 (p
, &p
);
893 decode_uleb128 (p
, &p
);
896 g_assert_not_reached ();
901 g_assert_not_reached ();
908 read_encoded_val (guint32 encoding
, guint8
*p
, guint8
**endp
)
912 switch (encoding
& 0xf) {
913 case DW_EH_PE_sdata8
:
917 case DW_EH_PE_sdata4
:
922 g_assert_not_reached ();
932 * Decode the Mono specific Language Specific Data Area generated by LLVM.
933 * This function is async safe.
936 decode_lsda (guint8
*lsda
, guint8
*code
, MonoJitExceptionInfo
*ex_info
, gpointer
*type_info
, guint32
*ex_info_len
, int *this_reg
, int *this_offset
)
939 int ncall_sites
, this_encoding
;
940 guint32 mono_magic
, version
;
944 /* This is the modified LSDA generated by the LLVM mono branch */
945 mono_magic
= decode_uleb128 (p
, &p
);
946 g_assert (mono_magic
== 0x4d4fef4f);
947 version
= decode_uleb128 (p
, &p
);
948 g_assert (version
== 1);
951 if (this_encoding
== DW_EH_PE_udata4
) {
952 gint32 op
, reg
, offset
;
954 /* 'this' location */
956 g_assert (op
== DW_OP_bregx
);
958 reg
= decode_uleb128 (p
, &p
);
959 offset
= decode_sleb128 (p
, &p
);
961 *this_reg
= mono_dwarf_reg_to_hw_reg (reg
);
962 *this_offset
= offset
;
964 g_assert (this_encoding
== DW_EH_PE_omit
);
969 ncall_sites
= decode_uleb128 (p
, &p
);
970 p
= (guint8
*)ALIGN_TO ((gsize
)p
, 4);
973 *ex_info_len
= ncall_sites
;
975 for (int i
= 0; i
< ncall_sites
; ++i
) {
976 int block_start_offset
, block_size
, landing_pad
;
979 block_start_offset
= read32 (p
);
980 p
+= sizeof (gint32
);
981 block_size
= read32 (p
);
982 p
+= sizeof (gint32
);
983 landing_pad
= read32 (p
);
984 p
+= sizeof (gint32
);
986 p
+= sizeof (gint32
);
988 g_assert (landing_pad
);
989 g_assert (((size_t)tinfo
% 4) == 0);
990 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
994 type_info
[i
] = tinfo
;
995 ex_info
[i
].try_start
= code
+ block_start_offset
;
996 ex_info
[i
].try_end
= code
+ block_start_offset
+ block_size
;
997 ex_info
[i
].handler_start
= code
+ landing_pad
;
1003 * mono_unwind_decode_fde:
1005 * Decode a DWARF FDE entry, returning the unwind opcodes.
1006 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
1007 * only try_start, try_end and handler_start is set.
1008 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
1012 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
)
1014 guint8
*p
, *cie
, *fde_current
, *fde_aug
= NULL
, *code
, *fde_cfi
, *cie_cfi
;
1015 gint32 fde_len
, cie_offset
, pc_begin
, pc_range
, aug_len
;
1016 gint32 cie_len
, cie_id
, cie_version
, code_align
, data_align
, return_reg
;
1017 gint32 i
, cie_aug_len
, buf_len
;
1020 gboolean has_fde_augmentation
= FALSE
;
1023 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
1026 /* This is generated by JITDwarfEmitter::EmitEHFrame () */
1035 // FIXME: Endianess ?
1036 fde_len
= *(guint32
*)p
;
1037 g_assert (fde_len
!= 0xffffffff && fde_len
!= 0);
1039 cie_offset
= *(guint32
*)p
;
1040 cie
= p
- cie_offset
;
1046 cie_len
= *(guint32
*)p
;
1048 cie_id
= *(guint32
*)p
;
1049 g_assert (cie_id
== 0);
1052 g_assert (cie_version
== 1);
1054 cie_aug_str
= (char*)p
;
1055 p
+= strlen (cie_aug_str
) + 1;
1056 code_align
= decode_uleb128 (p
, &p
);
1057 data_align
= decode_sleb128 (p
, &p
);
1058 return_reg
= decode_uleb128 (p
, &p
);
1059 if (strstr (cie_aug_str
, "z")) {
1063 cie_aug_len
= decode_uleb128 (p
, &p
);
1065 has_fde_augmentation
= TRUE
;
1068 for (i
= 0; cie_aug_str
[i
] != '\0'; ++i
) {
1069 switch (cie_aug_str
[i
]) {
1075 read_encoded_val (p_encoding
, p
, &p
);
1078 g_assert ((*p
== (DW_EH_PE_sdata4
|DW_EH_PE_pcrel
)) || (*p
== (DW_EH_PE_sdata8
|DW_EH_PE_pcrel
)));
1082 g_assert (*p
== (DW_EH_PE_sdata4
|DW_EH_PE_pcrel
));
1086 g_assert_not_reached ();
1096 /* Continue decoding FDE */
1098 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
1099 pc_begin
= *(gint32
*)p
;
1100 code
= p
+ pc_begin
;
1102 pc_range
= *(guint32
*)p
;
1104 if (has_fde_augmentation
) {
1105 aug_len
= decode_uleb128 (p
, &p
);
1114 *code_len
= pc_range
;
1121 /* Decode FDE augmention */
1126 /* sdata|pcrel encoding */
1128 lsda_offset
= read32 (fde_aug
);
1129 else if (aug_len
== 8)
1130 lsda_offset
= *(gint64
*)fde_aug
;
1132 g_assert_not_reached ();
1133 if (lsda_offset
!= 0) {
1134 lsda
= fde_aug
+ lsda_offset
;
1136 /* Get the lengths first */
1138 decode_lsda (lsda
, code
, NULL
, NULL
, &len
, this_reg
, this_offset
);
1141 *ex_info
= (MonoJitExceptionInfo
*)g_malloc0 (len
* sizeof (MonoJitExceptionInfo
));
1143 *type_info
= (gpointer
*)g_malloc0 (len
* sizeof (gpointer
));
1145 decode_lsda (lsda
, code
, ex_info
? *ex_info
: NULL
, type_info
? *type_info
: NULL
, ex_info_len
, this_reg
, this_offset
);
1149 /* Make sure the FDE uses the same constants as we do */
1150 g_assert (code_align
== 1);
1151 g_assert (data_align
== DWARF_DATA_ALIGN
);
1152 g_assert (return_reg
== DWARF_PC_REG
);
1154 buf_len
= (cie
+ cie_len
+ 4 - cie_cfi
) + (fde
+ fde_len
+ 4 - fde_cfi
);
1155 buf
= (guint8
*)g_malloc0 (buf_len
);
1159 while (p
< cie
+ cie_len
+ 4) {
1160 if (*p
== DW_CFA_nop
)
1162 decode_cie_op (p
, &p
);
1164 memcpy (buf
+ i
, cie_cfi
, p
- cie_cfi
);
1168 while (p
< fde
+ fde_len
+ 4) {
1169 if (*p
== DW_CFA_nop
)
1171 decode_cie_op (p
, &p
);
1173 memcpy (buf
+ i
, fde_cfi
, p
- fde_cfi
);
1175 g_assert (i
<= buf_len
);
1179 return (guint8
*)g_realloc (buf
, i
);
1183 * mono_unwind_decode_mono_fde:
1185 * Decode an FDE entry in the LLVM emitted mono EH frame.
1186 * If EI/TYPE_INFO/UNW_INFO are NULL, compute only the value of the scalar fields in INFO.
1188 * - Fill out EX_INFO with try_start, try_end and handler_start.
1189 * - Fill out TYPE_INFO with the ttype table from the LSDA.
1190 * - Fill out UNW_INFO with the unwind info.
1191 * This function is async safe.
1194 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
)
1196 guint8
*p
, *fde_aug
, *cie_cfi
, *fde_cfi
, *buf
;
1197 int has_aug
, aug_len
, cie_cfi_len
, fde_cfi_len
;
1198 gint32 code_align
, data_align
, return_reg
, pers_encoding
;
1200 memset (res
, 0, sizeof (*res
));
1202 res
->this_offset
= -1;
1204 /* fde points to data emitted by LLVM in DwarfMonoException::EmitMonoEHFrame () */
1209 aug_len
= read32 (p
);
1221 /* The LSDA is embedded directly into the FDE */
1224 /* Get the lengths first */
1225 decode_lsda (lsda
, code
, NULL
, NULL
, &res
->ex_info_len
, &res
->this_reg
, &res
->this_offset
);
1227 decode_lsda (lsda
, code
, ex_info
, type_info
, NULL
, &res
->this_reg
, &res
->this_offset
);
1232 code_align
= decode_uleb128 (p
, &p
);
1233 data_align
= decode_sleb128 (p
, &p
);
1234 return_reg
= decode_uleb128 (p
, &p
);
1237 if (pers_encoding
!= DW_EH_PE_omit
)
1238 read_encoded_val (pers_encoding
, p
, &p
);
1242 /* Make sure the FDE uses the same constants as we do */
1243 g_assert (code_align
== 1);
1244 g_assert (data_align
== DWARF_DATA_ALIGN
);
1245 g_assert (return_reg
== DWARF_PC_REG
);
1247 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1249 while (*p
!= DW_CFA_nop
) {
1250 decode_cie_op (p
, &p
);
1252 cie_cfi_len
= p
- cie_cfi
;
1253 fde_cfi_len
= (fde
+ fde_len
- fde_cfi
);
1257 memcpy (buf
, cie_cfi
, cie_cfi_len
);
1258 memcpy (buf
+ cie_cfi_len
, fde_cfi
, fde_cfi_len
);
1261 res
->unw_info_len
= cie_cfi_len
+ fde_cfi_len
;
1265 * mono_unwind_get_cie_program:
1267 * Get the unwind bytecode for the DWARF CIE.
1270 mono_unwind_get_cie_program (void)
1272 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC) || defined(TARGET_ARM)
1273 return mono_arch_get_cie_program ();