offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
printf ("CFA: [%x] offset_extended_sf: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
break;
+ case DW_CFA_same_value:
+ reg = decode_uleb128 (p, &p);
+ printf ("CFA: [%x] same_value: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)));
+ break;
case DW_CFA_advance_loc4:
pos += read32 (p);
p += 4;
break;
+ case DW_CFA_remember_state:
+ printf ("CFA: [%x] remember_state\n", pos);
+ break;
+ case DW_CFA_restore_state:
+ printf ("CFA: [%x] restore_state\n", pos);
+ break;
+ case DW_CFA_mono_advance_loc:
+ printf ("CFA: [%x] mono_advance_loc\n", pos);
+ break;
default:
g_assert_not_reached ();
}
/* 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 < 32) {
+ 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 ++ = 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 (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;
printf ("\n");
}
+typedef struct {
+ Loc locations [NUM_REGS];
+ guint8 reg_saved [NUM_REGS];
+ int cfa_reg, cfa_offset;
+} UnwindState;
+
/*
* Given the state of the current frame as stored in REGS, execute the unwind
* operations in unwind_info until the location counter reaches POS. The result is
* If SAVE_LOCATIONS is non-NULL, it should point to an array of size SAVE_LOCATIONS_LEN.
* On return, the nth entry will point to the address of the stack slot where register
* N was saved, or NULL, if it was not saved by this frame.
+ * MARK_LOCATIONS should contain the locations marked by mono_emit_unwind_op_mark_loc (), if any.
* This function is signal safe.
*/
void
mono_unwind_frame (guint8 *unwind_info, guint32 unwind_info_len,
- guint8 *start_ip, guint8 *end_ip, guint8 *ip, mgreg_t *regs, int nregs,
+ guint8 *start_ip, guint8 *end_ip, guint8 *ip, guint8 **mark_locations,
+ mgreg_t *regs, int nregs,
mgreg_t **save_locations, int save_locations_len,
guint8 **out_cfa)
{
int i, pos, reg, cfa_reg, cfa_offset, offset;
guint8 *p;
guint8 *cfa_val;
+ UnwindState state_stack [1];
+ int state_stack_pos;
memset (reg_saved, 0, sizeof (reg_saved));
pos = 0;
cfa_reg = -1;
cfa_offset = -1;
+ state_stack_pos = 0;
while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
int op = *p & 0xc0;
locations [reg].loc_type = LOC_OFFSET;
locations [reg].offset = offset * DWARF_DATA_ALIGN;
break;
+ case DW_CFA_same_value:
+ reg = decode_uleb128 (p, &p);
+ locations [reg].loc_type = LOC_SAME;
+ break;
+ case DW_CFA_advance_loc1:
+ pos += *p;
+ p += 1;
+ break;
+ case DW_CFA_advance_loc2:
+ pos += read16 (p);
+ p += 2;
+ break;
case DW_CFA_advance_loc4:
pos += read32 (p);
p += 4;
break;
+ case DW_CFA_remember_state:
+ g_assert (state_stack_pos == 0);
+ memcpy (&state_stack [0].locations, &locations, sizeof (locations));
+ memcpy (&state_stack [0].reg_saved, ®_saved, sizeof (reg_saved));
+ state_stack [0].cfa_reg = cfa_reg;
+ state_stack [0].cfa_offset = cfa_offset;
+ state_stack_pos ++;
+ break;
+ case DW_CFA_restore_state:
+ g_assert (state_stack_pos == 1);
+ state_stack_pos --;
+ memcpy (&locations, &state_stack [0].locations, sizeof (locations));
+ memcpy (®_saved, &state_stack [0].reg_saved, sizeof (reg_saved));
+ cfa_reg = state_stack [0].cfa_reg;
+ cfa_offset = state_stack [0].cfa_offset;
+ break;
+ case DW_CFA_mono_advance_loc:
+ g_assert (mark_locations [0]);
+ pos = mark_locations [0] - start_ip;
+ break;
default:
g_assert_not_reached ();
}