Example #1
0
static inline int
eval_location_expr (struct dwarf_cursor *c, unw_addr_space_t as,
                    unw_accessors_t *a, unw_word_t addr,
                    dwarf_loc_t *locp, void *arg)
{
    int ret, is_register;
    unw_word_t len, val;

    /* read the length of the expression: */
    if ((ret = dwarf_read_uleb128 (as, a, &addr, &len, arg)) < 0)
        return ret;

    /* evaluate the expression: */
    if ((ret = dwarf_eval_expr (c, &addr, len, &val, &is_register)) < 0)
        return ret;

    if (is_register)
        *locp = DWARF_REG_LOC (c, dwarf_to_unw_regnum (val));
    else
        *locp = DWARF_MEM_LOC (c, val);

    return 0;
}
Example #2
0
static int
apply_reg_state (struct dwarf_cursor *c, struct dwarf_reg_state *rs)
{
    unw_word_t regnum, addr, cfa, ip;
    unw_word_t prev_ip, prev_cfa;
    unw_addr_space_t as;
    dwarf_loc_t cfa_loc;
    unw_accessors_t *a;
    int i, ret;
    void *arg;

    prev_ip = c->ip;
    prev_cfa = c->cfa;

    as = c->as;
    arg = c->as_arg;
    a = unw_get_accessors (as);

    /* Evaluate the CFA first, because it may be referred to by other
       expressions.  */

    if (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
    {
        /* CFA is equal to [reg] + offset: */

        /* As a special-case, if the stack-pointer is the CFA and the
           stack-pointer wasn't saved, popping the CFA implicitly pops
           the stack-pointer as well.  */
        if ((rs->reg[DWARF_CFA_REG_COLUMN].val == UNW_TDEP_SP)
                && (UNW_TDEP_SP < ARRAY_SIZE(rs->reg))
                && (rs->reg[UNW_TDEP_SP].where == DWARF_WHERE_SAME))
            cfa = c->cfa;
        else
        {
            regnum = dwarf_to_unw_regnum (rs->reg[DWARF_CFA_REG_COLUMN].val);
            if ((ret = unw_get_reg ((unw_cursor_t *) c, regnum, &cfa)) < 0)
                return ret;
        }
        cfa += rs->reg[DWARF_CFA_OFF_COLUMN].val;
    }
    else
    {
        /* CFA is equal to EXPR: */

        assert (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_EXPR);

        addr = rs->reg[DWARF_CFA_REG_COLUMN].val;
        if ((ret = eval_location_expr (c, as, a, addr, &cfa_loc, arg)) < 0)
            return ret;
        /* the returned location better be a memory location... */
        if (DWARF_IS_REG_LOC (cfa_loc))
            return -UNW_EBADFRAME;
        cfa = DWARF_GET_LOC (cfa_loc);
    }

    for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
    {
        switch ((dwarf_where_t) rs->reg[i].where)
        {
        case DWARF_WHERE_UNDEF:
            c->loc[i] = DWARF_NULL_LOC;
            break;

        case DWARF_WHERE_SAME:
            break;

        case DWARF_WHERE_CFAREL:
            c->loc[i] = DWARF_MEM_LOC (c, cfa + rs->reg[i].val);
            break;

        case DWARF_WHERE_REG:
            c->loc[i] = DWARF_REG_LOC (c, dwarf_to_unw_regnum (rs->reg[i].val));
            break;

        case DWARF_WHERE_EXPR:
            addr = rs->reg[i].val;
            if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
                return ret;
            break;

        case DWARF_WHERE_VAL_EXPR:
            addr = rs->reg[i].val;
            if ((ret = eval_location_expr (c, as, a, addr, c->loc + i, arg)) < 0)
                return ret;
            c->loc[i] = DWARF_VAL_LOC (c, DWARF_GET_LOC (c->loc[i]));
            break;
        }
    }

    c->cfa = cfa;
    /* DWARF spec says undefined return address location means end of stack. */
    if (DWARF_IS_NULL_LOC (c->loc[c->ret_addr_column]))
        c->ip = 0;
    else
    {
        ret = dwarf_get (c, c->loc[c->ret_addr_column], &ip);
        if (ret < 0)
            return ret;
        c->ip = ip;
    }

    /* XXX: check for ip to be code_aligned */
    if (c->ip == prev_ip && c->cfa == prev_cfa)
    {
        Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
                 __FUNCTION__, (long) c->ip);
        return -UNW_EBADFRAME;
    }

    if (c->stash_frames)
        tdep_stash_frame (c, rs);

    return 0;
}
Example #3
0
static inline dwarf_loc_t
linux_scratch_loc (struct cursor *c, unw_regnum_t reg)
{
  unw_word_t addr = c->sigcontext_addr, fpstate_addr, off;
  int ret, is_fpstate = 0;

  switch (c->sigcontext_format)
    {
    case X86_SCF_NONE:
      return DWARF_REG_LOC (&c->dwarf, reg);

    case X86_SCF_LINUX_SIGFRAME:
      break;

    case X86_SCF_LINUX_RT_SIGFRAME:
      addr += LINUX_UC_MCONTEXT_OFF;
      break;
    }

  switch (reg)
    {
    case UNW_X86_GS: off = LINUX_SC_GS_OFF; break;
    case UNW_X86_FS: off = LINUX_SC_FS_OFF; break;
    case UNW_X86_ES: off = LINUX_SC_ES_OFF; break;
    case UNW_X86_DS: off = LINUX_SC_DS_OFF; break;
    case UNW_X86_EDI: off = LINUX_SC_EDI_OFF; break;
    case UNW_X86_ESI: off = LINUX_SC_ESI_OFF; break;
    case UNW_X86_EBP: off = LINUX_SC_EBP_OFF; break;
    case UNW_X86_ESP: off = LINUX_SC_ESP_OFF; break;
    case UNW_X86_EBX: off = LINUX_SC_EBX_OFF; break;
    case UNW_X86_EDX: off = LINUX_SC_EDX_OFF; break;
    case UNW_X86_ECX: off = LINUX_SC_ECX_OFF; break;
    case UNW_X86_EAX: off = LINUX_SC_EAX_OFF; break;
    case UNW_X86_TRAPNO: off = LINUX_SC_TRAPNO_OFF; break;
    case UNW_X86_EIP: off = LINUX_SC_EIP_OFF; break;
    case UNW_X86_CS: off = LINUX_SC_CS_OFF; break;
    case UNW_X86_EFLAGS: off = LINUX_SC_EFLAGS_OFF; break;
    case UNW_X86_SS: off = LINUX_SC_SS_OFF; break;

      /* The following is probably not correct for all possible cases.
	 Somebody who understands this better should review this for
	 correctness.  */

    case UNW_X86_FCW: is_fpstate = 1; off = LINUX_FPSTATE_CW_OFF; break;
    case UNW_X86_FSW: is_fpstate = 1; off = LINUX_FPSTATE_SW_OFF; break;
    case UNW_X86_FTW: is_fpstate = 1; off = LINUX_FPSTATE_TAG_OFF; break;
    case UNW_X86_FCS: is_fpstate = 1; off = LINUX_FPSTATE_CSSEL_OFF; break;
    case UNW_X86_FIP: is_fpstate = 1; off = LINUX_FPSTATE_IPOFF_OFF; break;
    case UNW_X86_FEA: is_fpstate = 1; off = LINUX_FPSTATE_DATAOFF_OFF; break;
    case UNW_X86_FDS: is_fpstate = 1; off = LINUX_FPSTATE_DATASEL_OFF; break;
    case UNW_X86_MXCSR: is_fpstate = 1; off = LINUX_FPSTATE_MXCSR_OFF; break;

      /* stacked fp registers */
    case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
    case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
      is_fpstate = 1;
      off = LINUX_FPSTATE_ST0_OFF + 10*(reg - UNW_X86_ST0);
      break;

     /* SSE fp registers */
    case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
    case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
    case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
    case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
    case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
    case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
    case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
    case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
      is_fpstate = 1;
      off = LINUX_FPSTATE_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
      break;
    case UNW_X86_XMM0:
    case UNW_X86_XMM1:
    case UNW_X86_XMM2:
    case UNW_X86_XMM3:
    case UNW_X86_XMM4:
    case UNW_X86_XMM5:
    case UNW_X86_XMM6:
    case UNW_X86_XMM7:
      is_fpstate = 1;
      off = LINUX_FPSTATE_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
      break;

    case UNW_X86_FOP:
    case UNW_X86_TSS:
    case UNW_X86_LDT:
    default:
      return DWARF_REG_LOC (&c->dwarf, reg);
    }

  if (is_fpstate)
    {
      if ((ret = dwarf_get (&c->dwarf,
			    DWARF_MEM_LOC (&c->dwarf,
					   addr + LINUX_SC_FPSTATE_OFF),
			    &fpstate_addr)) < 0)
	return DWARF_NULL_LOC;

      if (!fpstate_addr)
	return DWARF_NULL_LOC;

      return DWARF_MEM_LOC (c, fpstate_addr + off);
    }
  else
    return DWARF_MEM_LOC (c, addr + off);
}
Example #4
0
HIDDEN dwarf_loc_t
x86_get_scratch_loc (struct cursor *c, unw_regnum_t reg)
{
  unw_word_t addr = c->sigcontext_addr, off, xmm_off;
  unw_word_t fpstate, fpformat;
  int ret, is_fpstate = 0, is_xmmstate = 0;

  switch (c->sigcontext_format)
    {
    case X86_SCF_NONE:
      return DWARF_REG_LOC (&c->dwarf, reg);

    case X86_SCF_FREEBSD_SIGFRAME:
      addr += offsetof(struct sigframe, sf_uc) + FREEBSD_UC_MCONTEXT_OFF;
      break;

    case X86_SCF_FREEBSD_SIGFRAME4:
      abort();
      break;

    case X86_SCF_FREEBSD_OSIGFRAME:
      /* XXXKIB */
      abort();
      break;

    case X86_SCF_FREEBSD_SYSCALL:
      /* XXXKIB */
      abort();
      break;

    default:
      /* XXXKIB */
      abort();
      break;
    }

  off = 0; /* shut gcc warning */
  switch (reg)
    {
    case UNW_X86_GS: off = FREEBSD_UC_MCONTEXT_GS_OFF; break;
    case UNW_X86_FS: off = FREEBSD_UC_MCONTEXT_FS_OFF; break;
    case UNW_X86_ES: off = FREEBSD_UC_MCONTEXT_ES_OFF; break;
    case UNW_X86_DS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break;
    case UNW_X86_EDI: off = FREEBSD_UC_MCONTEXT_EDI_OFF; break;
    case UNW_X86_ESI: off = FREEBSD_UC_MCONTEXT_ESI_OFF; break;
    case UNW_X86_EBP: off = FREEBSD_UC_MCONTEXT_EBP_OFF; break;
    case UNW_X86_ESP: off = FREEBSD_UC_MCONTEXT_ESP_OFF; break;
    case UNW_X86_EBX: off = FREEBSD_UC_MCONTEXT_EBX_OFF; break;
    case UNW_X86_EDX: off = FREEBSD_UC_MCONTEXT_EDX_OFF; break;
    case UNW_X86_ECX: off = FREEBSD_UC_MCONTEXT_ECX_OFF; break;
    case UNW_X86_EAX: off = FREEBSD_UC_MCONTEXT_EAX_OFF; break;
    case UNW_X86_TRAPNO: off = FREEBSD_UC_MCONTEXT_TRAPNO_OFF; break;
    case UNW_X86_EIP: off = FREEBSD_UC_MCONTEXT_EIP_OFF; break;
    case UNW_X86_CS: off = FREEBSD_UC_MCONTEXT_CS_OFF; break;
    case UNW_X86_EFLAGS: off = FREEBSD_UC_MCONTEXT_EFLAGS_OFF; break;
    case UNW_X86_SS: off = FREEBSD_UC_MCONTEXT_SS_OFF; break;

    case UNW_X86_FCW:
      is_fpstate = 1;
      off = FREEBSD_UC_MCONTEXT_CW_OFF;
      xmm_off = FREEBSD_UC_MCONTEXT_CW_XMM_OFF;
      break;
    case UNW_X86_FSW:
      is_fpstate = 1;
      off = FREEBSD_UC_MCONTEXT_SW_OFF;
      xmm_off = FREEBSD_UC_MCONTEXT_SW_XMM_OFF;
      break;
    case UNW_X86_FTW:
      is_fpstate = 1;
      xmm_off = FREEBSD_UC_MCONTEXT_TAG_XMM_OFF;
      off = FREEBSD_UC_MCONTEXT_TAG_OFF;
      break;
    case UNW_X86_FCS:
      is_fpstate = 1;
      off = FREEBSD_UC_MCONTEXT_CSSEL_OFF;
      xmm_off = FREEBSD_UC_MCONTEXT_CSSEL_XMM_OFF;
      break;
    case UNW_X86_FIP:
      is_fpstate = 1;
      off = FREEBSD_UC_MCONTEXT_IPOFF_OFF;
      xmm_off = FREEBSD_UC_MCONTEXT_IPOFF_XMM_OFF;
      break;
    case UNW_X86_FEA:
      is_fpstate = 1;
      off = FREEBSD_UC_MCONTEXT_DATAOFF_OFF;
      xmm_off = FREEBSD_UC_MCONTEXT_DATAOFF_XMM_OFF;
      break;
    case UNW_X86_FDS:
      is_fpstate = 1;
      off = FREEBSD_US_MCONTEXT_DATASEL_OFF;
      xmm_off = FREEBSD_US_MCONTEXT_DATASEL_XMM_OFF;
      break;
    case UNW_X86_MXCSR:
      is_fpstate = 1;
      is_xmmstate = 1;
      xmm_off = FREEBSD_UC_MCONTEXT_MXCSR_XMM_OFF;
      break;

      /* stacked fp registers */
    case UNW_X86_ST0: case UNW_X86_ST1: case UNW_X86_ST2: case UNW_X86_ST3:
    case UNW_X86_ST4: case UNW_X86_ST5: case UNW_X86_ST6: case UNW_X86_ST7:
      is_fpstate = 1;
      off = FREEBSD_UC_MCONTEXT_ST0_OFF + 10*(reg - UNW_X86_ST0);
      xmm_off = FREEBSD_UC_MCONTEXT_ST0_XMM_OFF + 10*(reg - UNW_X86_ST0);
      break;

     /* SSE fp registers */
    case UNW_X86_XMM0_lo: case UNW_X86_XMM0_hi:
    case UNW_X86_XMM1_lo: case UNW_X86_XMM1_hi:
    case UNW_X86_XMM2_lo: case UNW_X86_XMM2_hi:
    case UNW_X86_XMM3_lo: case UNW_X86_XMM3_hi:
    case UNW_X86_XMM4_lo: case UNW_X86_XMM4_hi:
    case UNW_X86_XMM5_lo: case UNW_X86_XMM5_hi:
    case UNW_X86_XMM6_lo: case UNW_X86_XMM6_hi:
    case UNW_X86_XMM7_lo: case UNW_X86_XMM7_hi:
      is_fpstate = 1;
      is_xmmstate = 1;
      xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 8*(reg - UNW_X86_XMM0_lo);
      break;
    case UNW_X86_XMM0:
    case UNW_X86_XMM1:
    case UNW_X86_XMM2:
    case UNW_X86_XMM3:
    case UNW_X86_XMM4:
    case UNW_X86_XMM5:
    case UNW_X86_XMM6:
    case UNW_X86_XMM7:
      is_fpstate = 1;
      is_xmmstate = 1;
      xmm_off = FREEBSD_UC_MCONTEXT_XMM0_OFF + 16*(reg - UNW_X86_XMM0);
      break;

    case UNW_X86_FOP:
    case UNW_X86_TSS:
    case UNW_X86_LDT:
    default:
      return DWARF_REG_LOC (&c->dwarf, reg);
    }

  if (is_fpstate)
    {
      if ((ret = dwarf_get (&c->dwarf,
           DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPSTATE_OFF),
           &fpstate)) < 0)
        return DWARF_NULL_LOC;
      if (fpstate == FREEBSD_UC_MCONTEXT_FPOWNED_NONE)
        return DWARF_NULL_LOC;
      if ((ret = dwarf_get (&c->dwarf,
           DWARF_MEM_LOC (&c->dwarf, addr + FREEBSD_UC_MCONTEXT_FPFORMAT_OFF),
           &fpformat)) < 0)
        return DWARF_NULL_LOC;
      if (fpformat == FREEBSD_UC_MCONTEXT_FPFMT_NODEV ||
          (is_xmmstate && fpformat != FREEBSD_UC_MCONTEXT_FPFMT_XMM))
        return DWARF_NULL_LOC;
      if (is_xmmstate)
        off = xmm_off;
    }

    return DWARF_MEM_LOC (c, addr + off);
}