Merge pull request #1861 from saper/home-override
[mono-project.git] / mono / mini / mini-unwind.h
blob657cc7708733634fb42208d8378dda25d6af5e53
1 /*
2 * mini-unwind.h: Stack Unwinding Interface
4 * Authors:
5 * Zoltan Varga (vargaz@gmail.com)
7 * (C) 2007 Novell, Inc.
8 */
10 #ifndef __MONO_UNWIND_H__
11 #define __MONO_UNWIND_H__
13 #include "mini.h"
15 /* This is the same as mgreg_t, except on 32 bit bit platforms with callee saved fp regs */
16 #ifndef mono_unwind_reg_t
17 #define mono_unwind_reg_t mgreg_t
18 #endif
21 * This is a platform-independent interface for unwinding through stack frames
22 * based on the Dwarf unwinding interface.
23 * See http://dwarfstd.org/Dwarf3.pdf, section "Call Frame Information".
27 * CFA = Canonical Frame Address. By convention, this is the value of the stack pointer
28 * prior to the execution of the call instruction in the caller. I.e. on x86, it is
29 * esp + 4 on entry to a function. The value of the CFA does not change during execution
30 * of a function. There are two kinds of unwind directives:
31 * - those that describe how to compute the CFA at a given pc offset inside a function
32 * - those that describe where a given register is saved relative to the CFA.
35 /* Unwind ops */
37 /* The low 6 bits contain additional information */
38 #define DW_CFA_advance_loc 0x40
39 #define DW_CFA_offset 0x80
40 #define DW_CFA_restore 0xc0
42 #define DW_CFA_nop 0x00
43 #define DW_CFA_set_loc 0x01
44 #define DW_CFA_advance_loc1 0x02
45 #define DW_CFA_advance_loc2 0x03
46 #define DW_CFA_advance_loc4 0x04
47 #define DW_CFA_offset_extended 0x05
48 #define DW_CFA_restore_extended 0x06
49 #define DW_CFA_undefined 0x07
50 #define DW_CFA_same_value 0x08
51 #define DW_CFA_register 0x09
52 #define DW_CFA_remember_state 0x0a
53 #define DW_CFA_restore_state 0x0b
54 #define DW_CFA_def_cfa 0x0c
55 #define DW_CFA_def_cfa_register 0x0d
56 #define DW_CFA_def_cfa_offset 0x0e
57 #define DW_CFA_def_cfa_expression 0x0f
58 #define DW_CFA_expression 0x10
59 #define DW_CFA_offset_extended_sf 0x11
60 #define DW_CFA_def_cfa_sf 0x12
61 #define DW_CFA_def_cfa_offset_sf 0x13
62 #define DW_CFA_val_offset 0x14
63 #define DW_CFA_val_offset_sf 0x15
64 #define DW_CFA_val_expression 0x16
65 #define DW_CFA_lo_user 0x1c
66 #define DW_CFA_hi_user 0x3f
69 * Mono extension, advance loc to a location stored outside the unwind info.
70 * This is required to make the unwind descriptors sharable, since otherwise each one would contain
71 * an advance_loc with a different offset just before the unwind ops for the epilog.
73 #define DW_CFA_mono_advance_loc DW_CFA_lo_user
75 /* Represents one unwind instruction */
76 typedef struct {
77 guint8 op; /* One of DW_CFA_... */
78 guint16 reg; /* register number in the hardware encoding */
79 gint32 val; /* arbitrary value */
80 guint32 when; /* The offset _after_ the cpu instruction this unwind op belongs to */
81 } MonoUnwindOp;
83 /*
84 * Macros for emitting MonoUnwindOp structures.
85 * These should be called _after_ emitting the cpu instruction the unwind op
86 * belongs to.
89 /* Set cfa to reg+offset */
90 #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)->cur_cfa_reg = (reg); (cfg)->cur_cfa_offset = (offset); } while (0)
91 /* Set cfa to reg+existing offset */
92 #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)->cur_cfa_reg = (reg); } while (0)
93 /* Set cfa to existing reg+offset */
94 #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)->cur_cfa_offset = (offset); } while (0)
95 /* Reg is the same as it was on enter to the function */
96 #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)
97 /* Reg is saved at cfa+offset */
98 #define mono_emit_unwind_op_offset(cfg,ip,reg,offset) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_offset, (reg), (offset))
99 /* Save the unwind state into an implicit stack */
100 #define mono_emit_unwind_op_remember_state(cfg,ip) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_remember_state, 0, 0)
101 /* Restore the unwind state from the state stack */
102 #define mono_emit_unwind_op_restore_state(cfg,ip) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_restore_state, 0, 0)
104 * Mark the current location as a location stored outside the unwind info, which will be passed
105 * explicitly to mono_unwind_frame () in the MARK_LOCATIONS argument. This allows the unwind info
106 * to be shared among multiple methods.
108 #define mono_emit_unwind_op_mark_loc(cfg,ip,n) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_mono_advance_loc, 0, (n))
110 /* Similar macros usable when a cfg is not available, like for trampolines */
111 #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)
112 #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)
113 #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)
114 #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)
115 #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)
117 /* Pointer Encoding in the .eh_frame */
118 enum {
119 DW_EH_PE_absptr = 0x00,
120 DW_EH_PE_omit = 0xff,
122 DW_EH_PE_udata4 = 0x03,
123 DW_EH_PE_sdata4 = 0x0b,
124 DW_EH_PE_sdata8 = 0x0c,
126 DW_EH_PE_pcrel = 0x10,
127 DW_EH_PE_textrel = 0x20,
128 DW_EH_PE_datarel = 0x30,
129 DW_EH_PE_funcrel = 0x40,
130 DW_EH_PE_aligned = 0x50,
132 DW_EH_PE_indirect = 0x80
136 mono_hw_reg_to_dwarf_reg (int reg);
139 mono_dwarf_reg_to_hw_reg (int reg);
142 mono_unwind_get_dwarf_data_align (void);
145 mono_unwind_get_dwarf_pc_reg (void);
147 guint8*
148 mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len);
150 void
151 mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
152 guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
153 mono_unwind_reg_t *regs, int nregs,
154 mgreg_t **save_locations, int save_locations_len,
155 guint8 **out_cfa);
157 void mono_unwind_init (void);
159 void mono_unwind_cleanup (void);
161 guint32 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len);
163 guint8* mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len);
165 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;
167 /* Data retrieved from an LLVM Mono FDE entry */
168 typedef struct {
169 /* Malloc'ed */
170 guint8 *unw_info;
171 guint32 unw_info_len;
172 MonoJitExceptionInfo *ex_info;
173 guint32 ex_info_len;
174 gpointer *type_info;
175 int this_reg;
176 int this_offset;
177 } MonoLLVMFDEInfo;
179 void
180 mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res);
182 GSList* mono_unwind_get_cie_program (void);
184 void mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len) MONO_LLVM_INTERNAL;
186 #endif