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)))
254 static inline guint32
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
));
587 hwreg
= mono_dwarf_reg_to_hw_reg (*p
& 0x3f);
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 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
610 offset
= decode_sleb128 (p
, &p
);
611 if (reg
>= NUM_DWARF_REGS
) {
612 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
615 reg_saved
[hwreg
] = TRUE
;
616 locations
[hwreg
].loc_type
= LOC_OFFSET
;
617 locations
[hwreg
].offset
= offset
* DWARF_DATA_ALIGN
;
619 case DW_CFA_offset_extended
:
620 reg
= decode_uleb128 (p
, &p
);
621 hwreg
= mono_dwarf_reg_to_hw_reg (reg
);
622 offset
= decode_uleb128 (p
, &p
);
623 if (reg
>= NUM_DWARF_REGS
) {
624 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
627 reg_saved
[hwreg
] = TRUE
;
628 locations
[hwreg
].loc_type
= LOC_OFFSET
;
629 locations
[hwreg
].offset
= offset
* DWARF_DATA_ALIGN
;
631 case DW_CFA_same_value
:
632 hwreg
= mono_dwarf_reg_to_hw_reg (decode_uleb128 (p
, &p
));
633 locations
[hwreg
].loc_type
= LOC_SAME
;
635 case DW_CFA_advance_loc1
:
639 case DW_CFA_advance_loc2
:
643 case DW_CFA_advance_loc4
:
647 case DW_CFA_remember_state
:
648 if (state_stack_pos
!= 0) {
649 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
652 memcpy (&state_stack
[0].locations
, &locations
, sizeof (locations
));
653 memcpy (&state_stack
[0].reg_saved
, ®_saved
, sizeof (reg_saved
));
654 state_stack
[0].cfa_reg
= cfa_reg
;
655 state_stack
[0].cfa_offset
= cfa_offset
;
658 case DW_CFA_restore_state
:
659 if (state_stack_pos
!= 1) {
660 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
664 memcpy (&locations
, &state_stack
[0].locations
, sizeof (locations
));
665 memcpy (®_saved
, &state_stack
[0].reg_saved
, sizeof (reg_saved
));
666 cfa_reg
= state_stack
[0].cfa_reg
;
667 cfa_offset
= state_stack
[0].cfa_offset
;
669 case DW_CFA_mono_advance_loc
:
670 if (!mark_locations
[0]) {
671 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
674 pos
= mark_locations
[0] - start_ip
;
677 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__
, __LINE__
);
683 mono_runtime_printf_err ("Unwind failure. Illegal value for switch statement, assertion at %s %d\n.", __FILE__
, __LINE__
);
689 memset (save_locations
, 0, save_locations_len
* sizeof (host_mgreg_t
*));
692 mono_runtime_printf_err ("Unset cfa_reg in method %s. Memory around ip (%p):", mono_get_method_from_ip (ip
), ip
);
693 mono_dump_mem (ip
- 0x10, 0x40);
696 cfa_val
= (guint8
*)regs
[mono_dwarf_reg_to_hw_reg (cfa_reg
)] + cfa_offset
;
697 for (hwreg
= 0; hwreg
< NUM_HW_REGS
; ++hwreg
) {
698 if (reg_saved
[hwreg
] && locations
[hwreg
].loc_type
== LOC_OFFSET
) {
699 int dwarfreg
= mono_hw_reg_to_dwarf_reg (hwreg
);
700 if (hwreg
>= nregs
) {
701 mono_runtime_printf_err ("Unwind failure. Assertion at %s %d\n.", __FILE__
, __LINE__
);
704 if (IS_DOUBLE_REG (dwarfreg
))
705 regs
[hwreg
] = *(guint64
*)(cfa_val
+ locations
[hwreg
].offset
);
707 regs
[hwreg
] = *(host_mgreg_t
*)(cfa_val
+ locations
[hwreg
].offset
);
708 if (save_locations
&& hwreg
< save_locations_len
)
709 save_locations
[hwreg
] = (host_mgreg_t
*)(cfa_val
+ locations
[hwreg
].offset
);
720 mono_unwind_init (void)
722 mono_os_mutex_init_recursive (&unwind_mutex
);
724 mono_counters_register ("Unwind info size", MONO_COUNTER_JIT
| MONO_COUNTER_INT
, &unwind_info_size
);
728 mono_unwind_cleanup (void)
732 mono_os_mutex_destroy (&unwind_mutex
);
737 for (i
= 0; i
< cached_info_next
; ++i
) {
738 MonoUnwindInfo
*cached
= cached_info
[i
];
742 g_free (cached_info
);
744 for (GSList
*cursor
= cached_info_list
; cursor
!= NULL
; cursor
= cursor
->next
)
745 g_free (cursor
->data
);
747 g_slist_free (cached_info_list
);
751 * mono_cache_unwind_info
753 * Save UNWIND_INFO in the unwind info cache and return an id which can be passed
754 * to mono_get_cached_unwind_info to get a cached copy of the info.
755 * A copy is made of the unwind info.
756 * This function is useful for two reasons:
757 * - many methods have the same unwind info
758 * - MonoJitInfo->unwind_info is an int so it can't store the pointer to the unwind info
761 mono_cache_unwind_info (guint8
*unwind_info
, guint32 unwind_info_len
)
764 MonoUnwindInfo
*info
;
768 if (cached_info
== NULL
) {
769 cached_info_size
= 16;
770 cached_info
= g_new0 (MonoUnwindInfo
*, cached_info_size
);
773 for (i
= 0; i
< cached_info_next
; ++i
) {
774 MonoUnwindInfo
*cached
= cached_info
[i
];
776 if (cached
->len
== unwind_info_len
&& memcmp (cached
->info
, unwind_info
, unwind_info_len
) == 0) {
782 info
= (MonoUnwindInfo
*)g_malloc (sizeof (MonoUnwindInfo
) + unwind_info_len
);
783 info
->len
= unwind_info_len
;
784 memcpy (&info
->info
, unwind_info
, unwind_info_len
);
786 i
= cached_info_next
;
788 if (cached_info_next
>= cached_info_size
) {
789 MonoUnwindInfo
**new_table
;
792 * Avoid freeing the old table so mono_get_cached_unwind_info ()
793 * doesn't need locks/hazard pointers.
796 new_table
= g_new0 (MonoUnwindInfo
*, cached_info_size
* 2);
798 memcpy (new_table
, cached_info
, cached_info_size
* sizeof (MonoUnwindInfo
*));
800 mono_memory_barrier ();
802 cached_info_list
= g_slist_prepend (cached_info_list
, cached_info
);
804 cached_info
= new_table
;
806 cached_info_size
*= 2;
809 cached_info
[cached_info_next
++] = info
;
811 unwind_info_size
+= sizeof (MonoUnwindInfo
) + unwind_info_len
;
818 * This function is signal safe.
821 mono_get_cached_unwind_info (guint32 index
, guint32
*unwind_info_len
)
823 MonoUnwindInfo
**table
;
824 MonoUnwindInfo
*info
;
828 * This doesn't need any locks/hazard pointers,
829 * since new tables are copies of the old ones.
833 info
= table
[index
];
835 *unwind_info_len
= info
->len
;
842 * mono_unwind_get_dwarf_data_align:
844 * Return the data alignment used by the encoded unwind information.
847 mono_unwind_get_dwarf_data_align (void)
849 return DWARF_DATA_ALIGN
;
853 * mono_unwind_get_dwarf_pc_reg:
855 * Return the dwarf register number of the register holding the ip of the
859 mono_unwind_get_dwarf_pc_reg (void)
865 decode_cie_op (guint8
*p
, guint8
**endp
)
870 case DW_CFA_advance_loc
:
875 decode_uleb128 (p
, &p
);
882 decode_uleb128 (p
, &p
);
883 decode_uleb128 (p
, &p
);
885 case DW_CFA_def_cfa_offset
:
886 decode_uleb128 (p
, &p
);
888 case DW_CFA_def_cfa_register
:
889 decode_uleb128 (p
, &p
);
891 case DW_CFA_advance_loc4
:
894 case DW_CFA_offset_extended_sf
:
895 decode_uleb128 (p
, &p
);
896 decode_uleb128 (p
, &p
);
899 g_assert_not_reached ();
904 g_assert_not_reached ();
911 read_encoded_val (guint32 encoding
, guint8
*p
, guint8
**endp
)
915 switch (encoding
& 0xf) {
916 case DW_EH_PE_sdata8
:
920 case DW_EH_PE_sdata4
:
925 g_assert_not_reached ();
935 * Decode the Mono specific Language Specific Data Area generated by LLVM.
936 * This function is async safe.
939 decode_lsda (guint8
*lsda
, guint8
*code
, MonoJitExceptionInfo
*ex_info
, gpointer
*type_info
, guint32
*ex_info_len
, int *this_reg
, int *this_offset
)
942 int i
, ncall_sites
, this_encoding
;
943 guint32 mono_magic
, version
;
947 /* This is the modified LSDA generated by the LLVM mono branch */
948 mono_magic
= decode_uleb128 (p
, &p
);
949 g_assert (mono_magic
== 0x4d4fef4f);
950 version
= decode_uleb128 (p
, &p
);
951 g_assert (version
== 1);
954 if (this_encoding
== DW_EH_PE_udata4
) {
955 gint32 op
, reg
, offset
;
957 /* 'this' location */
959 g_assert (op
== DW_OP_bregx
);
961 reg
= decode_uleb128 (p
, &p
);
962 offset
= decode_sleb128 (p
, &p
);
964 *this_reg
= mono_dwarf_reg_to_hw_reg (reg
);
965 *this_offset
= offset
;
967 g_assert (this_encoding
== DW_EH_PE_omit
);
972 ncall_sites
= decode_uleb128 (p
, &p
);
973 p
= (guint8
*)ALIGN_TO ((gsize
)p
, 4);
976 *ex_info_len
= ncall_sites
;
978 for (i
= 0; i
< ncall_sites
; ++i
) {
979 int block_start_offset
, block_size
, landing_pad
;
982 block_start_offset
= read32 (p
);
983 p
+= sizeof (gint32
);
984 block_size
= read32 (p
);
985 p
+= sizeof (gint32
);
986 landing_pad
= read32 (p
);
987 p
+= sizeof (gint32
);
989 p
+= sizeof (gint32
);
991 g_assert (landing_pad
);
992 g_assert (((size_t)tinfo
% 4) == 0);
993 //printf ("X: %p %d\n", landing_pad, *(int*)tinfo);
997 type_info
[i
] = tinfo
;
998 ex_info
[i
].try_start
= code
+ block_start_offset
;
999 ex_info
[i
].try_end
= code
+ block_start_offset
+ block_size
;
1000 ex_info
[i
].handler_start
= code
+ landing_pad
;
1006 * mono_unwind_decode_fde:
1008 * Decode a DWARF FDE entry, returning the unwind opcodes.
1009 * If not NULL, EX_INFO is set to a malloc-ed array of MonoJitExceptionInfo structures,
1010 * only try_start, try_end and handler_start is set.
1011 * If not NULL, TYPE_INFO is set to a malloc-ed array containing the ttype table from the
1015 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
)
1017 guint8
*p
, *cie
, *fde_current
, *fde_aug
= NULL
, *code
, *fde_cfi
, *cie_cfi
;
1018 gint32 fde_len
, cie_offset
, pc_begin
, pc_range
, aug_len
;
1019 gint32 cie_len
, cie_id
, cie_version
, code_align
, data_align
, return_reg
;
1020 gint32 i
, cie_aug_len
, buf_len
;
1023 gboolean has_fde_augmentation
= FALSE
;
1026 * http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
1029 /* This is generated by JITDwarfEmitter::EmitEHFrame () */
1038 // FIXME: Endianess ?
1039 fde_len
= *(guint32
*)p
;
1040 g_assert (fde_len
!= 0xffffffff && fde_len
!= 0);
1042 cie_offset
= *(guint32
*)p
;
1043 cie
= p
- cie_offset
;
1049 cie_len
= *(guint32
*)p
;
1051 cie_id
= *(guint32
*)p
;
1052 g_assert (cie_id
== 0);
1055 g_assert (cie_version
== 1);
1057 cie_aug_str
= (char*)p
;
1058 p
+= strlen (cie_aug_str
) + 1;
1059 code_align
= decode_uleb128 (p
, &p
);
1060 data_align
= decode_sleb128 (p
, &p
);
1061 return_reg
= decode_uleb128 (p
, &p
);
1062 if (strstr (cie_aug_str
, "z")) {
1066 cie_aug_len
= decode_uleb128 (p
, &p
);
1068 has_fde_augmentation
= TRUE
;
1071 for (i
= 0; cie_aug_str
[i
] != '\0'; ++i
) {
1072 switch (cie_aug_str
[i
]) {
1078 read_encoded_val (p_encoding
, p
, &p
);
1081 g_assert ((*p
== (DW_EH_PE_sdata4
|DW_EH_PE_pcrel
)) || (*p
== (DW_EH_PE_sdata8
|DW_EH_PE_pcrel
)));
1085 g_assert (*p
== (DW_EH_PE_sdata4
|DW_EH_PE_pcrel
));
1089 g_assert_not_reached ();
1099 /* Continue decoding FDE */
1101 /* DW_EH_PE_sdata4|DW_EH_PE_pcrel encoding */
1102 pc_begin
= *(gint32
*)p
;
1103 code
= p
+ pc_begin
;
1105 pc_range
= *(guint32
*)p
;
1107 if (has_fde_augmentation
) {
1108 aug_len
= decode_uleb128 (p
, &p
);
1117 *code_len
= pc_range
;
1124 /* Decode FDE augmention */
1129 /* sdata|pcrel encoding */
1131 lsda_offset
= read32 (fde_aug
);
1132 else if (aug_len
== 8)
1133 lsda_offset
= *(gint64
*)fde_aug
;
1135 g_assert_not_reached ();
1136 if (lsda_offset
!= 0) {
1137 lsda
= fde_aug
+ lsda_offset
;
1139 /* Get the lengths first */
1141 decode_lsda (lsda
, code
, NULL
, NULL
, &len
, this_reg
, this_offset
);
1144 *ex_info
= (MonoJitExceptionInfo
*)g_malloc0 (len
* sizeof (MonoJitExceptionInfo
));
1146 *type_info
= (gpointer
*)g_malloc0 (len
* sizeof (gpointer
));
1148 decode_lsda (lsda
, code
, ex_info
? *ex_info
: NULL
, type_info
? *type_info
: NULL
, ex_info_len
, this_reg
, this_offset
);
1152 /* Make sure the FDE uses the same constants as we do */
1153 g_assert (code_align
== 1);
1154 g_assert (data_align
== DWARF_DATA_ALIGN
);
1155 g_assert (return_reg
== DWARF_PC_REG
);
1157 buf_len
= (cie
+ cie_len
+ 4 - cie_cfi
) + (fde
+ fde_len
+ 4 - fde_cfi
);
1158 buf
= (guint8
*)g_malloc0 (buf_len
);
1162 while (p
< cie
+ cie_len
+ 4) {
1163 if (*p
== DW_CFA_nop
)
1166 decode_cie_op (p
, &p
);
1168 memcpy (buf
+ i
, cie_cfi
, p
- cie_cfi
);
1172 while (p
< fde
+ fde_len
+ 4) {
1173 if (*p
== DW_CFA_nop
)
1176 decode_cie_op (p
, &p
);
1178 memcpy (buf
+ i
, fde_cfi
, p
- fde_cfi
);
1180 g_assert (i
<= buf_len
);
1184 return (guint8
*)g_realloc (buf
, i
);
1188 * mono_unwind_decode_mono_fde:
1190 * Decode an FDE entry in the LLVM emitted mono EH frame.
1191 * If EI/TYPE_INFO/UNW_INFO are NULL, compute only the value of the scalar fields in INFO.
1193 * - Fill out EX_INFO with try_start, try_end and handler_start.
1194 * - Fill out TYPE_INFO with the ttype table from the LSDA.
1195 * - Fill out UNW_INFO with the unwind info.
1196 * This function is async safe.
1199 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
)
1201 guint8
*p
, *fde_aug
, *cie_cfi
, *fde_cfi
, *buf
;
1202 int has_aug
, aug_len
, cie_cfi_len
, fde_cfi_len
;
1203 gint32 code_align
, data_align
, return_reg
, pers_encoding
;
1205 memset (res
, 0, sizeof (*res
));
1207 res
->this_offset
= -1;
1209 /* fde points to data emitted by LLVM in DwarfMonoException::EmitMonoEHFrame () */
1214 aug_len
= read32 (p
);
1226 /* The LSDA is embedded directly into the FDE */
1229 /* Get the lengths first */
1230 decode_lsda (lsda
, code
, NULL
, NULL
, &res
->ex_info_len
, &res
->this_reg
, &res
->this_offset
);
1232 decode_lsda (lsda
, code
, ex_info
, type_info
, NULL
, &res
->this_reg
, &res
->this_offset
);
1237 code_align
= decode_uleb128 (p
, &p
);
1238 data_align
= decode_sleb128 (p
, &p
);
1239 return_reg
= decode_uleb128 (p
, &p
);
1242 if (pers_encoding
!= DW_EH_PE_omit
)
1243 read_encoded_val (pers_encoding
, p
, &p
);
1247 /* Make sure the FDE uses the same constants as we do */
1248 g_assert (code_align
== 1);
1249 g_assert (data_align
== DWARF_DATA_ALIGN
);
1250 g_assert (return_reg
== DWARF_PC_REG
);
1252 /* Compute size of CIE unwind info it is DW_CFA_nop terminated */
1255 if (*p
== DW_CFA_nop
)
1258 decode_cie_op (p
, &p
);
1260 cie_cfi_len
= p
- cie_cfi
;
1261 fde_cfi_len
= (fde
+ fde_len
- fde_cfi
);
1265 memcpy (buf
, cie_cfi
, cie_cfi_len
);
1266 memcpy (buf
+ cie_cfi_len
, fde_cfi
, fde_cfi_len
);
1269 res
->unw_info_len
= cie_cfi_len
+ fde_cfi_len
;
1273 * mono_unwind_get_cie_program:
1275 * Get the unwind bytecode for the DWARF CIE.
1278 mono_unwind_get_cie_program (void)
1280 #if defined(TARGET_AMD64) || defined(TARGET_X86) || defined(TARGET_POWERPC) || defined(TARGET_ARM)
1281 return mono_arch_get_cie_program ();