Example #1
0
static void *
extract_cie_info (fde *f, struct cie_info *c)
{
  void *p;
  int i;

  c->augmentation = get_cie (f)->augmentation;

  if (strcmp (c->augmentation, "") != 0
      && strcmp (c->augmentation, "eh") != 0
      && c->augmentation[0] != 'z')
    return 0;

  p = c->augmentation + strlen (c->augmentation) + 1;

  if (strcmp (c->augmentation, "eh") == 0)
    {
      c->eh_ptr = read_pointer (p);
      p += sizeof (void *);
    }
  else
    c->eh_ptr = 0;

  p = decode_uleb128 (p, &c->code_align);
  p = decode_sleb128 (p, &c->data_align);
  c->ra_regno = *(unsigned char *)p++;

  /* If the augmentation starts with 'z', we now see the length of the
     augmentation fields.  */
  if (c->augmentation[0] == 'z')
    {
      p = decode_uleb128 (p, &i);
      p += i;
    }

  return p;
}
Example #2
0
/*
 * 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 
 * stored back into REGS. OUT_CFA will receive the value of the CFA.
 * 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.
 * 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,
				   mgreg_t **save_locations, int save_locations_len,
				   guint8 **out_cfa)
{
	Loc locations [NUM_REGS];
	int i, pos, reg, cfa_reg, cfa_offset;
	guint8 *p;
	guint8 *cfa_val;

	for (i = 0; i < NUM_REGS; ++i)
		locations [i].loc_type = LOC_SAME;

	p = unwind_info;
	pos = 0;
	cfa_reg = -1;
	cfa_offset = -1;
	while (pos <= ip - start_ip && p < unwind_info + unwind_info_len) {
		int op = *p & 0xc0;

		switch (op) {
		case DW_CFA_advance_loc:
			UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
			pos += *p & 0x3f;
			p ++;
			break;
		case DW_CFA_offset:
			reg = *p & 0x3f;
			p ++;
			locations [reg].loc_type = LOC_OFFSET;
			locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
			break;
		case 0: {
			int ext_op = *p;
			p ++;
			switch (ext_op) {
			case DW_CFA_def_cfa:
				cfa_reg = decode_uleb128 (p, &p);
				cfa_offset = decode_uleb128 (p, &p);
				break;
			case DW_CFA_def_cfa_offset:
				cfa_offset = decode_uleb128 (p, &p);
				break;
			case DW_CFA_def_cfa_register:
				cfa_reg = decode_uleb128 (p, &p);
				break;
			case DW_CFA_offset_extended_sf:
				reg = decode_uleb128 (p, &p);
				locations [reg].loc_type = LOC_OFFSET;
				locations [reg].offset = decode_sleb128 (p, &p) * DWARF_DATA_ALIGN;
				break;
			case DW_CFA_advance_loc4:
				pos += read32 (p);
				p += 4;
				break;
			default:
				g_assert_not_reached ();
			}
			break;
		}
		default:
			g_assert_not_reached ();
		}
	}

	if (save_locations)
		memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));

	cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
	for (i = 0; i < NUM_REGS; ++i) {
		if (locations [i].loc_type == LOC_OFFSET) {
			int hreg = mono_dwarf_reg_to_hw_reg (i);
			g_assert (hreg < nregs);
			regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
			if (save_locations && hreg < save_locations_len)
				save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
		}
	}

	*out_cfa = cfa_val;
}
Example #3
0
/*
 * 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 
 * stored back into REGS. OUT_CFA will receive the value of the CFA.
 * 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, guint8 **mark_locations,
				   mono_unwind_reg_t *regs, int nregs,
				   mgreg_t **save_locations, int save_locations_len,
				   guint8 **out_cfa)
{
	Loc locations [NUM_REGS];
	guint8 reg_saved [NUM_REGS];
	int i, pos, reg, cfa_reg = -1, cfa_offset = 0, offset;
	guint8 *p;
	guint8 *cfa_val;
	UnwindState state_stack [1];
	int state_stack_pos;

	memset (reg_saved, 0, sizeof (reg_saved));
	state_stack [0].cfa_reg = -1;
	state_stack [0].cfa_offset = 0;

	p = unwind_info;
	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;

		switch (op) {
		case DW_CFA_advance_loc:
			UNW_DEBUG (print_dwarf_state (cfa_reg, cfa_offset, pos, nregs, locations));
			pos += *p & 0x3f;
			p ++;
			break;
		case DW_CFA_offset:
			reg = *p & 0x3f;
			p ++;
			reg_saved [reg] = TRUE;
			locations [reg].loc_type = LOC_OFFSET;
			locations [reg].offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
			break;
		case 0: {
			int ext_op = *p;
			p ++;
			switch (ext_op) {
			case DW_CFA_def_cfa:
				cfa_reg = decode_uleb128 (p, &p);
				cfa_offset = decode_uleb128 (p, &p);
				break;
			case DW_CFA_def_cfa_offset:
				cfa_offset = decode_uleb128 (p, &p);
				break;
			case DW_CFA_def_cfa_register:
				cfa_reg = decode_uleb128 (p, &p);
				break;
			case DW_CFA_offset_extended_sf:
				reg = decode_uleb128 (p, &p);
				offset = decode_sleb128 (p, &p);
				g_assert (reg < NUM_REGS);
				reg_saved [reg] = TRUE;
				locations [reg].loc_type = LOC_OFFSET;
				locations [reg].offset = offset * DWARF_DATA_ALIGN;
				break;
			case DW_CFA_offset_extended:
				reg = decode_uleb128 (p, &p);
				offset = decode_uleb128 (p, &p);
				g_assert (reg < NUM_REGS);
				reg_saved [reg] = TRUE;
				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, &reg_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 (&reg_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 ();
			}
			break;
		}
		default:
			g_assert_not_reached ();
		}
	}

	if (save_locations)
		memset (save_locations, 0, save_locations_len * sizeof (mgreg_t*));

	g_assert (cfa_reg != -1);
	cfa_val = (guint8*)regs [mono_dwarf_reg_to_hw_reg (cfa_reg)] + cfa_offset;
	for (i = 0; i < NUM_REGS; ++i) {
		if (reg_saved [i] && locations [i].loc_type == LOC_OFFSET) {
			int hreg = mono_dwarf_reg_to_hw_reg (i);
			g_assert (hreg < nregs);
			if (IS_DOUBLE_REG (i))
				regs [hreg] = *(guint64*)(cfa_val + locations [i].offset);
			else
				regs [hreg] = *(mgreg_t*)(cfa_val + locations [i].offset);
			if (save_locations && hreg < save_locations_len)
				save_locations [hreg] = (mgreg_t*)(cfa_val + locations [i].offset);
		}
	}

	*out_cfa = cfa_val;
}
Example #4
0
void
mono_print_unwind_info (guint8 *unwind_info, int unwind_info_len)
{
	guint8 *p;
	int pos, reg, offset, cfa_reg, cfa_offset;

	p = unwind_info;
	pos = 0;
	while (p < unwind_info + unwind_info_len) {
		int op = *p & 0xc0;

		switch (op) {
		case DW_CFA_advance_loc:
			pos += *p & 0x3f;
			p ++;
			break;
		case DW_CFA_offset:
			reg = *p & 0x3f;
			p ++;
			offset = decode_uleb128 (p, &p) * DWARF_DATA_ALIGN;
			if (reg == DWARF_PC_REG)
				printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, "pc", -offset);
			else
				printf ("CFA: [%x] offset: %s at cfa-0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (reg)), -offset);
			break;
		case 0: {
			int ext_op = *p;
			p ++;
			switch (ext_op) {
			case DW_CFA_def_cfa:
				cfa_reg = decode_uleb128 (p, &p);
				cfa_offset = decode_uleb128 (p, &p);
				printf ("CFA: [%x] def_cfa: %s+0x%x\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)), cfa_offset);
				break;
			case DW_CFA_def_cfa_offset:
				cfa_offset = decode_uleb128 (p, &p);
				printf ("CFA: [%x] def_cfa_offset: 0x%x\n", pos, cfa_offset);
				break;
			case DW_CFA_def_cfa_register:
				cfa_reg = decode_uleb128 (p, &p);
				printf ("CFA: [%x] def_cfa_reg: %s\n", pos, mono_arch_regname (mono_dwarf_reg_to_hw_reg (cfa_reg)));
				break;
			case DW_CFA_offset_extended_sf:
				reg = decode_uleb128 (p, &p);
				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 ();
			}
			break;
		}
		default:
			g_assert_not_reached ();
		}
	}
}