2 * mini-unwind.h: Stack Unwinding Interface
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2007 Novell, Inc.
10 #ifndef __MONO_UNWIND_H__
11 #define __MONO_UNWIND_H__
16 * This is a platform-independent interface for unwinding through stack frames
17 * based on the Dwarf unwinding interface.
18 * See http://dwarfstd.org/Dwarf3.pdf, section "Call Frame Information".
22 * CFA = Canonical Frame Address. By convention, this is the value of the stack pointer
23 * prior to the execution of the call instruction in the caller. I.e. on x86, it is
24 * esp + 4 on entry to a function. The value of the CFA does not change during execution
25 * of a function. There are two kinds of unwind directives:
26 * - those that describe how to compute the CFA at a given pc offset inside a function
27 * - those that describe where a given register is saved relative to the CFA.
32 /* The low 6 bits contain additional information */
33 #define DW_CFA_advance_loc 0x40
34 #define DW_CFA_offset 0x80
35 #define DW_CFA_restore 0xc0
37 #define DW_CFA_nop 0x00
38 #define DW_CFA_set_loc 0x01
39 #define DW_CFA_advance_loc1 0x02
40 #define DW_CFA_advance_loc2 0x03
41 #define DW_CFA_advance_loc4 0x04
42 #define DW_CFA_offset_extended 0x05
43 #define DW_CFA_restore_extended 0x06
44 #define DW_CFA_undefined 0x07
45 #define DW_CFA_same_value 0x08
46 #define DW_CFA_register 0x09
47 #define DW_CFA_remember_state 0x0a
48 #define DW_CFA_restore_state 0x0b
49 #define DW_CFA_def_cfa 0x0c
50 #define DW_CFA_def_cfa_register 0x0d
51 #define DW_CFA_def_cfa_offset 0x0e
52 #define DW_CFA_def_cfa_expression 0x0f
53 #define DW_CFA_expression 0x10
54 #define DW_CFA_offset_extended_sf 0x11
55 #define DW_CFA_def_cfa_sf 0x12
56 #define DW_CFA_def_cfa_offset_sf 0x13
57 #define DW_CFA_val_offset 0x14
58 #define DW_CFA_val_offset_sf 0x15
59 #define DW_CFA_val_expression 0x16
60 #define DW_CFA_lo_user 0x1c
61 #define DW_CFA_hi_user 0x3f
63 /* Represents one unwind instruction */
65 guint8 op
; /* One of DW_CFA_... */
66 guint16 reg
; /* register number in the hardware encoding */
67 gint32 val
; /* arbitrary value */
68 guint32 when
; /* The offset _after_ the cpu instruction this unwind op belongs to */
72 * Macros for emitting MonoUnwindOp structures.
73 * These should be called _after_ emitting the cpu instruction the unwind op
77 /* Set cfa to reg+offset */
78 #define mono_emit_unwind_op_def_cfa(cfg,ip,reg,offset) do { mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_def_cfa, (reg), (offset)); (cfg)->cfa_reg = (reg); (cfg)->cfa_offset = (offset); } while (0)
79 /* Set cfa to reg+existing offset */
80 #define mono_emit_unwind_op_def_cfa_reg(cfg,ip,reg) do { mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_def_cfa_register, (reg), (0)); (cfg)->cfa_reg = (reg); } while (0)
81 /* Set cfa to existing reg+offset */
82 #define mono_emit_unwind_op_def_cfa_offset(cfg,ip,offset) do { mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_def_cfa_offset, (0), (offset)); (cfg)->cfa_offset = (offset); } while (0)
83 /* Reg is the same as it was on enter to the function */
84 #define mono_emit_unwind_op_same_value(cfg,ip,reg) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_same_value, (reg), 0)
85 /* Reg is saved at cfa+offset */
86 #define mono_emit_unwind_op_offset(cfg,ip,reg,offset) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_offset, (reg), (offset))
88 /* Similar macros usable when a cfg is not available, like for trampolines */
89 #define mono_add_unwind_op_def_cfa(op_list,code,buf,reg,offset) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_def_cfa, (reg), (offset))); } while (0)
90 #define mono_add_unwind_op_def_cfa_reg(op_list,code,buf,reg) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_def_cfa_register, (reg), (0))); } while (0)
91 #define mono_add_unwind_op_def_cfa_offset(op_list,code,buf,offset) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_def_cfa_offset, 0, (offset))); } while (0)
92 #define mono_add_unwind_op_same_value(op_list,code,buf,reg) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_same_value, (reg), 0)); } while (0)
93 #define mono_add_unwind_op_offset(op_list,code,buf,reg,offset) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_offset, (reg), (offset))); } while (0)
95 /* Pointer Encoding in the .eh_frame */
97 DW_EH_PE_absptr
= 0x00,
100 DW_EH_PE_udata4
= 0x03,
101 DW_EH_PE_sdata4
= 0x0b,
102 DW_EH_PE_sdata8
= 0x0c,
104 DW_EH_PE_pcrel
= 0x10,
105 DW_EH_PE_textrel
= 0x20,
106 DW_EH_PE_datarel
= 0x30,
107 DW_EH_PE_funcrel
= 0x40,
108 DW_EH_PE_aligned
= 0x50,
110 DW_EH_PE_indirect
= 0x80
114 mono_hw_reg_to_dwarf_reg (int reg
) MONO_INTERNAL
;
117 mono_dwarf_reg_to_hw_reg (int reg
) MONO_INTERNAL
;
120 mono_unwind_get_dwarf_data_align (void) MONO_INTERNAL
;
123 mono_unwind_get_dwarf_pc_reg (void) MONO_INTERNAL
;
126 mono_unwind_ops_encode (GSList
*unwind_ops
, guint32
*out_len
) MONO_INTERNAL
;
129 mono_unwind_frame (guint8
*unwind_info
, guint32 unwind_info_len
,
130 guint8
*start_ip
, guint8
*end_ip
, guint8
*ip
, mgreg_t
*regs
, int nregs
,
131 mgreg_t
**save_locations
, int save_locations_len
,
132 guint8
**out_cfa
) MONO_INTERNAL
;
134 void mono_unwind_init (void) MONO_INTERNAL
;
136 void mono_unwind_cleanup (void) MONO_INTERNAL
;
138 guint32
mono_cache_unwind_info (guint8
*unwind_info
, guint32 unwind_info_len
) MONO_INTERNAL
;
140 guint8
* mono_get_cached_unwind_info (guint32 index
, guint32
*unwind_info_len
) MONO_INTERNAL
;
142 guint8
* 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
) MONO_LLVM_INTERNAL
;
144 /* Data retrieved from an LLVM Mono FDE entry */
148 guint32 unw_info_len
;
149 MonoJitExceptionInfo
*ex_info
;
157 mono_unwind_decode_llvm_mono_fde (guint8
*fde
, int fde_len
, guint8
*cie
, guint8
*code
, MonoLLVMFDEInfo
*res
) MONO_INTERNAL
;
159 GSList
* mono_unwind_get_cie_program (void) MONO_INTERNAL
;