-/*
- * mini-unwind.h: Stack Unwinding Interface
+/**
+ * \file
+ * Stack Unwinding Interface
*
* Authors:
* Zoltan Varga (vargaz@gmail.com)
#include "mini.h"
+/* This is the same as mgreg_t, except on 32 bit bit platforms with callee saved fp regs */
+#ifndef mono_unwind_reg_t
+#define mono_unwind_reg_t mgreg_t
+#endif
+
/*
* This is a platform-independent interface for unwinding through stack frames
* based on the Dwarf unwinding interface.
*/
#define DW_CFA_mono_advance_loc DW_CFA_lo_user
+/*
+ * Mono extension, Windows x64 unwind ABI needs some more details around sp alloc size and fp offset.
+ */
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+#define DW_CFA_mono_sp_alloc_info_win64 (DW_CFA_lo_user + 1)
+#define DW_CFA_mono_fp_alloc_info_win64 (DW_CFA_lo_user + 2)
+#endif
+
/* Represents one unwind instruction */
typedef struct {
guint8 op; /* One of DW_CFA_... */
*/
/* Set cfa to reg+offset */
-#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)
+#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)
/* Set cfa to reg+existing offset */
-#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)
+#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)
/* Set cfa to existing reg+offset */
-#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)
+#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)
/* Reg is the same as it was on enter to the function */
#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)
/* Reg is saved at cfa+offset */
*/
#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))
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+#define mono_emit_unwind_op_sp_alloc(cfg,ip,size) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_mono_sp_alloc_info_win64, 0, (size))
+#define mono_emit_unwind_op_fp_alloc(cfg,ip,reg,size) mono_emit_unwind_op (cfg, (ip) - (cfg)->native_code, DW_CFA_mono_fp_alloc_info_win64, (reg), (size))
+#else
+#define mono_emit_unwind_op_sp_alloc(cfg,ip,size)
+#define mono_emit_unwind_op_fp_alloc(cfg,ip,reg,size)
+#endif
+
/* Similar macros usable when a cfg is not available, like for trampolines */
#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)
#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)
#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)
#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)
+#if defined(TARGET_WIN32) && defined(TARGET_AMD64)
+#define mono_add_unwind_op_sp_alloc(op_list,code,buf,size) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_mono_sp_alloc_info_win64, 0, (size))); } while (0)
+#define mono_add_unwind_op_fp_alloc(op_list,code,buf,reg,size) do { (op_list) = g_slist_append ((op_list), mono_create_unwind_op ((code) - (buf), DW_CFA_mono_fp_alloc_info_win64, (reg), (size))); } while (0)
+#else
+#define mono_add_unwind_op_sp_alloc(op_list,code,buf,size)
+#define mono_add_unwind_op_fp_alloc(op_list,code,buf,reg,size)
+#endif
+
+#define mono_free_unwind_info(op_list) do { GSList *l; for (l = op_list; l; l = l->next) g_free (l->data); g_slist_free (op_list); op_list = NULL; } while (0)
+
/* Pointer Encoding in the .eh_frame */
enum {
DW_EH_PE_absptr = 0x00,
};
int
-mono_hw_reg_to_dwarf_reg (int reg) MONO_INTERNAL;
+mono_hw_reg_to_dwarf_reg (int reg);
int
-mono_dwarf_reg_to_hw_reg (int reg) MONO_INTERNAL;
+mono_dwarf_reg_to_hw_reg (int reg);
int
-mono_unwind_get_dwarf_data_align (void) MONO_INTERNAL;
+mono_unwind_get_dwarf_data_align (void);
int
-mono_unwind_get_dwarf_pc_reg (void) MONO_INTERNAL;
+mono_unwind_get_dwarf_pc_reg (void);
+
+guint8*
+mono_unwind_ops_encode_full (GSList *unwind_ops, guint32 *out_len, gboolean enable_extensions);
guint8*
-mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len) MONO_INTERNAL;
+mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len);
void
mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
- mgreg_t *regs, int nregs,
+ mono_unwind_reg_t *regs, int nregs,
mgreg_t **save_locations, int save_locations_len,
- guint8 **out_cfa) MONO_INTERNAL;
+ guint8 **out_cfa);
-void mono_unwind_init (void) MONO_INTERNAL;
+void mono_unwind_init (void);
-void mono_unwind_cleanup (void) MONO_INTERNAL;
+void mono_unwind_cleanup (void);
-guint32 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len) MONO_INTERNAL;
+guint32 mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len);
-guint8* mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len) MONO_INTERNAL;
+guint8* mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len);
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;
/* Data retrieved from an LLVM Mono FDE entry */
typedef struct {
- /* Malloc'ed */
- guint8 *unw_info;
guint32 unw_info_len;
- MonoJitExceptionInfo *ex_info;
guint32 ex_info_len;
- gpointer *type_info;
+ int type_info_len;
int this_reg;
int this_offset;
} MonoLLVMFDEInfo;
void
-mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res) MONO_INTERNAL;
+mono_unwind_decode_llvm_mono_fde (guint8 *fde, int fde_len, guint8 *cie, guint8 *code, MonoLLVMFDEInfo *res, MonoJitExceptionInfo *ei, gpointer *type_info, guint8 *unw_info) MONO_LLVM_INTERNAL;
-GSList* mono_unwind_get_cie_program (void) MONO_INTERNAL;
+GSList* mono_unwind_get_cie_program (void);
void mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len) MONO_LLVM_INTERNAL;