emit_uleb128 (acfg, 0);
}
-#ifdef __x86_64__
-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 };
-#endif
-
-static int
-hw_reg_to_dwarf_reg (int reg)
-{
-#ifdef __x86_64__
- return map_hw_reg_to_dwarf_reg [reg];
-#else
- g_assert_not_reached ();
- return -1;
-#endif
-}
-
static void
emit_cie (MonoAotCompile *acfg)
{
#ifdef __x86_64__
emit_byte (acfg, DW_CFA_def_cfa);
- emit_uleb128 (acfg, hw_reg_to_dwarf_reg (AMD64_RSP));
+ emit_uleb128 (acfg, mono_hw_reg_to_dwarf_reg (AMD64_RSP));
emit_uleb128 (acfg, 8); /* offset=8 */
emit_byte (acfg, DW_CFA_offset | AMD64_RIP);
emit_uleb128 (acfg, 1); /* offset=-8 */
#if defined(__x86_64__)
char symbol [128];
GSList *l;
- MonoUnwindOp *op;
- int loc;
+ guint8 *uw_info;
+ guint32 uw_info_len;
emit_section_change (acfg, ".debug_frame", 0);
emit_int32 (acfg, 0);
}
- /* Convert the list of MonoUnwindOps to the format used by DWARF */
- loc = 0;
l = unwind_ops;
#ifdef __x86_64__
/* Skip the first two ops which are in the CIE */
l = l->next->next;
#endif
- for (; l; l = l->next) {
- int reg;
-
- op = l->data;
- /* Convert the register from the hw encoding to the dwarf encoding */
- reg = hw_reg_to_dwarf_reg (op->reg);
-
- /* Emit an advance_loc if neccesary */
- if (op->when > loc) {
- g_assert (op->when - loc < 32);
- emit_byte (acfg, DW_CFA_advance_loc | (op->when - loc));
- }
-
- switch (op->op) {
- case DW_CFA_def_cfa:
- emit_byte (acfg, op->op);
- emit_uleb128 (acfg, reg);
- emit_uleb128 (acfg, op->val);
- break;
- case DW_CFA_def_cfa_offset:
- emit_byte (acfg, op->op);
- emit_uleb128 (acfg, op->val);
- break;
- case DW_CFA_def_cfa_register:
- emit_byte (acfg, op->op);
- emit_uleb128 (acfg, reg);
- break;
- case DW_CFA_offset:
- emit_byte (acfg, DW_CFA_offset | reg);
- emit_uleb128 (acfg, op->val / - 8);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- loc = op->when;
- }
+ /* Convert the list of MonoUnwindOps to the format used by DWARF */
+ uw_info = mono_unwind_ops_encode (l, &uw_info_len);
+ emit_bytes (acfg, uw_info, uw_info_len);
+ g_free (uw_info);
emit_alignment (acfg, sizeof (gpointer));
sprintf (symbol, ".Lfde%d_end", fde_index);
emit_byte (acfg, 0);
} else if (arg->opcode == OP_REGVAR) {
emit_byte (acfg, 1);
- emit_byte (acfg, DW_OP_reg0 + hw_reg_to_dwarf_reg (arg->dreg));
+ emit_byte (acfg, DW_OP_reg0 + mono_hw_reg_to_dwarf_reg (arg->dreg));
} else if (arg->opcode == OP_REGOFFSET) {
guint8 buf [128];
guint8 *p;
p = buf;
- *p ++= DW_OP_breg0 + hw_reg_to_dwarf_reg (arg->inst_basereg);
+ *p ++= DW_OP_breg0 + mono_hw_reg_to_dwarf_reg (arg->inst_basereg);
encode_sleb128 (arg->inst_offset, p, &p);
emit_byte (acfg, p - buf);
emit_bytes (acfg, buf, p - buf);
--- /dev/null
+/*
+ * unwind.c: Stack Unwinding Interface
+ *
+ * Authors:
+ * Zoltan Varga (vargaz@gmail.com)
+ *
+ * (C) 2008 Novell, Inc.
+ */
+
+#include "mini.h"
+#include "unwind.h"
+
+#ifdef __x86_64__
+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 };
+#endif
+
+/*
+ * mono_hw_reg_to_dwarf_reg:
+ *
+ * Map the hardware register number REG to the register number used by DWARF.
+ */
+int
+mono_hw_reg_to_dwarf_reg (int reg)
+{
+#ifdef __x86_64__
+ return map_hw_reg_to_dwarf_reg [reg];
+#else
+ g_assert_not_reached ();
+ return -1;
+#endif
+}
+
+static G_GNUC_UNUSED void
+encode_uleb128 (guint32 value, guint8 *buf, guint8 **endbuf)
+{
+ guint8 *p = buf;
+
+ do {
+ guint8 b = value & 0x7f;
+ value >>= 7;
+ if (value != 0) /* more bytes to come */
+ b |= 0x80;
+ *p ++ = b;
+ } while (value);
+
+ *endbuf = p;
+}
+
+/*
+ * mono_unwind_ops_encode:
+ *
+ * Encode the unwind ops in UNWIND_OPS into the compact DWARF encoding.
+ * Return a pointer to malloc'ed memory.
+ */
+guint8*
+mono_unwind_ops_encode (GSList *unwind_ops, guint32 *out_len)
+{
+ GSList *l;
+ MonoUnwindOp *op;
+ int loc;
+ guint8 *buf, *p, *res;
+
+ p = buf = g_malloc0 (256);
+
+ loc = 0;
+ l = unwind_ops;
+ for (; l; l = l->next) {
+ int reg;
+
+ op = l->data;
+
+ /* Convert the register from the hw encoding to the dwarf encoding */
+ reg = mono_hw_reg_to_dwarf_reg (op->reg);
+
+ /* Emit an advance_loc if neccesary */
+ if (op->when > loc) {
+ g_assert (op->when - loc < 32);
+ *p ++ = DW_CFA_advance_loc | (op->when - loc);
+ }
+
+ switch (op->op) {
+ case DW_CFA_def_cfa:
+ *p ++ = op->op;
+ encode_uleb128 (reg, p, &p);
+ encode_uleb128 (op->val, p, &p);
+ break;
+ case DW_CFA_def_cfa_offset:
+ *p ++ = op->op;
+ encode_uleb128 (op->val, p, &p);
+ break;
+ case DW_CFA_def_cfa_register:
+ *p ++ = op->op;
+ encode_uleb128 (reg, p, &p);
+ break;
+ case DW_CFA_offset:
+ *p ++ = DW_CFA_offset | reg;
+ encode_uleb128 (op->val / - 8, p, &p);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ loc = op->when;
+ }
+
+ g_assert (p - buf < 256);
+ *out_len = p - buf;
+ res = g_malloc (p - buf);
+ memcpy (res, buf, p - buf);
+ g_free (buf);
+ return res;
+}