/* * 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 (4096); 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 */ while (op->when > loc) { if (op->when - loc < 32) { *p ++ = DW_CFA_advance_loc | (op->when - loc); loc = op->when; } else { *p ++ = DW_CFA_advance_loc | (30); loc += 30; } } 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: if (reg > 63) { *p ++ = DW_CFA_offset_extended_sf; encode_uleb128 (reg, p, &p); encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p); } else { *p ++ = DW_CFA_offset | reg; encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p); } break; default: g_assert_not_reached (); break; } } g_assert (p - buf < 4096); *out_len = p - buf; res = g_malloc (p - buf); memcpy (res, buf, p - buf); g_free (buf); return res; }
/* * 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 [4096]; guint8 *p, *res; p = buf; 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); if (op->op == DW_CFA_mono_advance_loc) { /* This advances loc to its location */ loc = op->when; } /* Emit an advance_loc if neccesary */ while (op->when > loc) { if (op->when - loc > 65536) { *p ++ = DW_CFA_advance_loc4; *(guint32*)p = (guint32)(op->when - loc); g_assert (read32 (p) == (guint32)(op->when - loc)); p += 4; loc = op->when; } else if (op->when - loc > 256) { *p ++ = DW_CFA_advance_loc2; *(guint16*)p = (guint16)(op->when - loc); g_assert (read16 (p) == (guint32)(op->when - loc)); p += 2; loc = op->when; } else if (op->when - loc >= 32) { *p ++ = DW_CFA_advance_loc1; *(guint8*)p = (guint8)(op->when - loc); p += 1; loc = op->when; } else if (op->when - loc < 32) { *p ++ = DW_CFA_advance_loc | (op->when - loc); loc = op->when; } else { *p ++ = DW_CFA_advance_loc | (30); loc += 30; } } 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_same_value: *p ++ = op->op; encode_uleb128 (reg, p, &p); break; case DW_CFA_offset: if (reg > 63) { *p ++ = DW_CFA_offset_extended_sf; encode_uleb128 (reg, p, &p); encode_sleb128 (op->val / DWARF_DATA_ALIGN, p, &p); } else { *p ++ = DW_CFA_offset | reg; encode_uleb128 (op->val / DWARF_DATA_ALIGN, p, &p); } break; case DW_CFA_remember_state: case DW_CFA_restore_state: *p ++ = op->op; break; case DW_CFA_mono_advance_loc: /* Only one location is supported */ g_assert (op->val == 0); *p ++ = op->op; break; default: g_assert_not_reached (); break; } } g_assert (p - buf < 4096); *out_len = p - buf; res = g_malloc (p - buf); memcpy (res, buf, p - buf); return res; }