Пример #1
0
PROTECTED int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
  struct cursor *c = (struct cursor *) cursor;
  dwarf_loc_t loc;

  loc = DWARF_NULL_LOC;		/* default to "not saved" */

#warning FIX ME!

  memset (sloc, 0, sizeof (sloc));

  if (DWARF_IS_NULL_LOC (loc))
    {
      sloc->type = UNW_SLT_NONE;
      return 0;
    }

#if !defined(UNW_LOCAL_ONLY)
  if (DWARF_IS_REG_LOC (loc))
    {
      sloc->type = UNW_SLT_REG;
      sloc->u.regnum = DWARF_GET_LOC (loc);
    }
  else
#endif
    {
      sloc->type = UNW_SLT_MEMORY;
      sloc->u.addr = DWARF_GET_LOC (loc);
    }
  return 0;
}
Пример #2
0
PROTECTED int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
  struct cursor *c = (struct cursor *) cursor;
  dwarf_loc_t loc;

  switch (reg)
    {
    case UNW_SH_R0:
    case UNW_SH_R1:
    case UNW_SH_R2:
    case UNW_SH_R3:
    case UNW_SH_R4:
    case UNW_SH_R5:
    case UNW_SH_R6:
    case UNW_SH_R7:
    case UNW_SH_R8:
    case UNW_SH_R9:
    case UNW_SH_R10:
    case UNW_SH_R11:
    case UNW_SH_R12:
    case UNW_SH_R13:
    case UNW_SH_R14:
    case UNW_SH_R15:
    case UNW_SH_PC:
    case UNW_SH_PR:
      loc = c->dwarf.loc[reg];
      break;

    default:
      loc = DWARF_NULL_LOC;     /* default to "not saved" */
      break;
    }

  memset (sloc, 0, sizeof (*sloc));

  if (DWARF_IS_NULL_LOC (loc))
    {
      sloc->type = UNW_SLT_NONE;
      return 0;
    }

#if !defined(UNW_LOCAL_ONLY)
  if (DWARF_IS_REG_LOC (loc))
    {
      sloc->type = UNW_SLT_REG;
      sloc->u.regnum = DWARF_GET_LOC (loc);
    }
  else
#endif
    {
      sloc->type = UNW_SLT_MEMORY;
      sloc->u.addr = DWARF_GET_LOC (loc);
    }
  return 0;
}
Пример #3
0
PROTECTED int
unw_get_save_loc (unw_cursor_t *cursor, int reg, unw_save_loc_t *sloc)
{
  struct cursor *c = (struct cursor *) cursor;
  dwarf_loc_t loc;

  loc = DWARF_NULL_LOC;		/* default to "not saved" */

  switch (reg)
    {
    case UNW_X86_64_RBX: loc = c->dwarf.loc[RBX]; break;
    case UNW_X86_64_RSP: loc = c->dwarf.loc[RSP]; break;
    case UNW_X86_64_RBP: loc = c->dwarf.loc[RBP]; break;
    case UNW_X86_64_R12: loc = c->dwarf.loc[R12]; break;
    case UNW_X86_64_R13: loc = c->dwarf.loc[R13]; break;
    case UNW_X86_64_R14: loc = c->dwarf.loc[R14]; break;
    case UNW_X86_64_R15: loc = c->dwarf.loc[R15]; break;

    default:
      break;
    }

  memset (sloc, 0, sizeof (unw_save_loc_t));

  if (DWARF_IS_NULL_LOC (loc))
    {
      sloc->type = UNW_SLT_NONE;
      return 0;
    }

#if !defined(UNW_LOCAL_ONLY)
  if (DWARF_IS_REG_LOC (loc))
    {
      sloc->type = UNW_SLT_REG;
      sloc->u.regnum = DWARF_GET_LOC (loc);
    }
  else
#endif
    {
      sloc->type = UNW_SLT_MEMORY;
      sloc->u.addr = DWARF_GET_LOC (loc);
    }
  return 0;
}
Пример #4
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;
}
Пример #5
0
HIDDEN void
tdep_stash_frame (struct dwarf_cursor *d, struct dwarf_reg_state *rs)
{
  struct cursor *c = (struct cursor *) dwarf_to_cursor (d);
  unw_tdep_frame_t *f = &c->frame_info;

  Debug (4, "ip=0x%lx cfa=0x%lx type %d cfa [where=%d val=%ld] cfaoff=%ld"
         " ra=0x%lx fp [where=%d val=%ld @0x%lx] lr [where=%d val=%ld @0x%lx] "
         "sp [where=%d val=%ld @0x%lx]\n",
         d->ip, d->cfa, f->frame_type,
         rs->reg.where[DWARF_CFA_REG_COLUMN],
         rs->reg.val[DWARF_CFA_REG_COLUMN],
         rs->reg.val[DWARF_CFA_OFF_COLUMN],
         DWARF_GET_LOC(d->loc[rs->ret_addr_column]),
         rs->reg.where[FP], rs->reg.val[FP], DWARF_GET_LOC(d->loc[FP]),
         rs->reg.where[LR], rs->reg.val[LR], DWARF_GET_LOC(d->loc[LR]),
         rs->reg.where[SP], rs->reg.val[SP], DWARF_GET_LOC(d->loc[SP]));

  /* A standard frame is defined as:
      - CFA is register-relative offset off FP or SP;
      - Return address is saved in LR;
      - FP is unsaved or saved at CFA+offset, offset != -1;
      - LR is unsaved or saved at CFA+offset, offset != -1;
      - SP is unsaved or saved at CFA+offset, offset != -1.  */
  if (f->frame_type == UNW_AARCH64_FRAME_OTHER
      && (rs->reg.where[DWARF_CFA_REG_COLUMN] == DWARF_WHERE_REG)
      && (rs->reg.val[DWARF_CFA_REG_COLUMN] == FP
          || rs->reg.val[DWARF_CFA_REG_COLUMN] == SP)
      && labs(rs->reg.val[DWARF_CFA_OFF_COLUMN]) < (1 << 29)
      && rs->ret_addr_column == LR
      && (rs->reg.where[FP] == DWARF_WHERE_UNDEF
          || rs->reg.where[FP] == DWARF_WHERE_SAME
          || (rs->reg.where[FP] == DWARF_WHERE_CFAREL
              && labs(rs->reg.val[FP]) < (1 << 29)
              && rs->reg.val[FP]+1 != 0))
      && (rs->reg.where[LR] == DWARF_WHERE_UNDEF
          || rs->reg.where[LR] == DWARF_WHERE_SAME
          || (rs->reg.where[LR] == DWARF_WHERE_CFAREL
              && labs(rs->reg.val[LR]) < (1 << 29)
              && rs->reg.val[LR]+1 != 0))
      && (rs->reg.where[SP] == DWARF_WHERE_UNDEF
          || rs->reg.where[SP] == DWARF_WHERE_SAME
          || (rs->reg.where[SP] == DWARF_WHERE_CFAREL
              && labs(rs->reg.val[SP]) < (1 << 29)
              && rs->reg.val[SP]+1 != 0)))
  {
    /* Save information for a standard frame. */
    f->frame_type = UNW_AARCH64_FRAME_STANDARD;
    f->cfa_reg_sp = (rs->reg.val[DWARF_CFA_REG_COLUMN] == SP);
    f->cfa_reg_offset = rs->reg.val[DWARF_CFA_OFF_COLUMN];
    if (rs->reg.where[FP] == DWARF_WHERE_CFAREL)
      f->fp_cfa_offset = rs->reg.val[FP];
    if (rs->reg.where[LR] == DWARF_WHERE_CFAREL)
      f->lr_cfa_offset = rs->reg.val[LR];
    if (rs->reg.where[SP] == DWARF_WHERE_CFAREL)
      f->sp_cfa_offset = rs->reg.val[SP];
    Debug (4, " standard frame\n");
  }
  else
    Debug (4, " unusual frame\n");
}
Пример #6
0
HIDDEN void
tdep_stash_frame (struct dwarf_cursor *d, struct dwarf_reg_state *rs)
{
  struct cursor *c = (struct cursor *) dwarf_to_cursor (d);
  unw_tdep_frame_t *f = &c->frame_info;

  Debug (4, "ip=0x%lx cfa=0x%lx type %d cfa [where=%d val=%ld] cfaoff=%ld"
         " ra=0x%lx rbp [where=%d val=%ld @0x%lx] rsp [where=%d val=%ld @0x%lx]\n",
         d->ip, d->cfa, f->frame_type,
         rs->reg[DWARF_CFA_REG_COLUMN].where,
         rs->reg[DWARF_CFA_REG_COLUMN].val,
         rs->reg[DWARF_CFA_OFF_COLUMN].val,
         DWARF_GET_LOC(d->loc[d->ret_addr_column]),
         rs->reg[RBP].where, rs->reg[RBP].val, DWARF_GET_LOC(d->loc[RBP]),
         rs->reg[RSP].where, rs->reg[RSP].val, DWARF_GET_LOC(d->loc[RSP]));

  /* A standard frame is defined as:
      - CFA is register-relative offset off RBP or RSP;
      - Return address is saved at CFA-8;
      - RBP is unsaved or saved at CFA+offset, offset != -1;
      - RSP is unsaved or saved at CFA+offset, offset != -1.  */
  if (f->frame_type == UNW_X86_64_FRAME_OTHER
      && (rs->reg[DWARF_CFA_REG_COLUMN].where == DWARF_WHERE_REG)
      && (rs->reg[DWARF_CFA_REG_COLUMN].val == RBP
          || rs->reg[DWARF_CFA_REG_COLUMN].val == RSP)
      && labs((long) rs->reg[DWARF_CFA_OFF_COLUMN].val) < (1 << 29)
      && DWARF_GET_LOC(d->loc[d->ret_addr_column]) == d->cfa-8
      && (rs->reg[RBP].where == DWARF_WHERE_UNDEF
          || rs->reg[RBP].where == DWARF_WHERE_SAME
          || (rs->reg[RBP].where == DWARF_WHERE_CFAREL
              && labs((long) rs->reg[RBP].val) < (1 << 14)
              && rs->reg[RBP].val+1 != 0))
      && (rs->reg[RSP].where == DWARF_WHERE_UNDEF
          || rs->reg[RSP].where == DWARF_WHERE_SAME
          || (rs->reg[RSP].where == DWARF_WHERE_CFAREL
              && labs((long) rs->reg[RSP].val) < (1 << 14)
              && rs->reg[RSP].val+1 != 0)))
  {
    /* Save information for a standard frame. */
    f->frame_type = UNW_X86_64_FRAME_STANDARD;
    f->cfa_reg_rsp = (rs->reg[DWARF_CFA_REG_COLUMN].val == RSP);
    f->cfa_reg_offset = rs->reg[DWARF_CFA_OFF_COLUMN].val;
    if (rs->reg[RBP].where == DWARF_WHERE_CFAREL)
      f->rbp_cfa_offset = rs->reg[RBP].val;
    if (rs->reg[RSP].where == DWARF_WHERE_CFAREL)
      f->rsp_cfa_offset = rs->reg[RSP].val;
    Debug (4, " standard frame\n");
  }

  /* Signal frame was detected via augmentation in tdep_fetch_frame()  */
  else if (f->frame_type == UNW_X86_64_FRAME_SIGRETURN)
  {
    /* Later we are going to fish out {RBP,RSP,RIP} from sigcontext via
       their ucontext_t offsets.  Confirm DWARF info agrees with the
       offsets we expect.  */

#ifndef NDEBUG
    const unw_word_t uc = c->sigcontext_addr;

    assert (DWARF_GET_LOC(d->loc[RIP]) - uc == UC_MCONTEXT_GREGS_RIP);
    assert (DWARF_GET_LOC(d->loc[RBP]) - uc == UC_MCONTEXT_GREGS_RBP);
    assert (DWARF_GET_LOC(d->loc[RSP]) - uc == UC_MCONTEXT_GREGS_RSP);
#endif

    Debug (4, " sigreturn frame\n");
  }

  /* PLT and guessed RBP-walked frames are handled in unw_step(). */
  else
    Debug (4, " unusual frame\n");
}
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
  struct cursor *c = (struct cursor *) cursor;
  int ret, i;

  Debug (1, "(cursor=%p, ip=0x%08x)\n", c, (unsigned) c->dwarf.ip);

  /* ANDROID support update. */
  /* Save the current ip/cfa to prevent looping if the decode yields
     the same ip/cfa as before. */
  unw_word_t old_ip = c->dwarf.ip;
  unw_word_t old_cfa = c->dwarf.cfa;
  /* End of ANDROID update. */

  /* Try DWARF-based unwinding... */
  ret = dwarf_step (&c->dwarf);

#if !defined(UNW_LOCAL_ONLY)
  /* Do not use this method on a local unwind. There is a very high
   * probability this method will try to access unmapped memory, which
   * will crash the process. Since this almost never actually works,
   * it should be okay to skip.
   */
  if (ret < 0)
    {
      /* DWARF failed, let's see if we can follow the frame-chain
	 or skip over the signal trampoline.  */
      struct dwarf_loc ebp_loc, eip_loc;

      /* We could get here because of missing/bad unwind information.
         Validate all addresses before dereferencing. */
      c->validate = 1;

      Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);

      if (unw_is_signal_frame (cursor))
        {
          ret = unw_handle_signal_frame(cursor);
	  if (ret < 0)
	    {
	      Debug (2, "returning 0\n");
	      return 0;
	    }
        }
      else
	{
	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa);
	  if (ret < 0)
	    {
	      Debug (2, "returning %d\n", ret);
	      return ret;
	    }

	  Debug (13, "[EBP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EBP]),
		 c->dwarf.cfa);

	  ebp_loc = DWARF_LOC (c->dwarf.cfa, 0);
	  eip_loc = DWARF_LOC (c->dwarf.cfa + 4, 0);
	  c->dwarf.cfa += 8;

	  /* Mark all registers unsaved, since we don't know where
	     they are saved (if at all), except for the EBP and
	     EIP.  */
	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
	    c->dwarf.loc[i] = DWARF_NULL_LOC;

          c->dwarf.loc[EBP] = ebp_loc;
          c->dwarf.loc[EIP] = eip_loc;
	}
      c->dwarf.ret_addr_column = EIP;

      if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP]))
	{
	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip);
	  if (ret < 0)
	    {
	      Debug (13, "dwarf_get([EIP=0x%x]) failed\n", DWARF_GET_LOC (c->dwarf.loc[EIP]));
	      Debug (2, "returning %d\n", ret);
	      return ret;
	    }
	  else
	    {
	      Debug (13, "[EIP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EIP]),
		c->dwarf.ip);
	    }
	}
      else
	c->dwarf.ip = 0;
    }
#endif

  /* ANDROID support update. */
  if (ret >= 0)
    {
      if (c->dwarf.ip)
        {
          /* Adjust the pc to the instruction before. */
          c->dwarf.ip--;
        }
      /* If the decode yields the exact same ip/cfa as before, then indicate
         the unwind is complete. */
      if (old_ip == c->dwarf.ip && old_cfa == c->dwarf.cfa)
        {
          Dprintf ("%s: ip and cfa unchanged; stopping here (ip=0x%lx)\n",
                   __FUNCTION__, (long) c->dwarf.ip);
          return -UNW_EBADFRAME;
        }
      c->dwarf.frame++;
    }
  /* End of ANDROID update. */
  if (unlikely (ret <= 0))
    return 0;

  return (c->dwarf.ip == 0) ? 0 : 1;
}
Пример #8
0
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
  struct cursor *c = (struct cursor *) cursor;
  int ret, i;

  Debug (1, "(cursor=%p, ip=0x%08x)\n", c, (unsigned) c->dwarf.ip);

  /* Try DWARF-based unwinding... */
  ret = dwarf_step (&c->dwarf);

  if (ret < 0 && ret != -UNW_ENOINFO)
    {
      Debug (2, "returning %d\n", ret);
      return ret;
    }

  if (unlikely (ret < 0))
    {
      /* DWARF failed, let's see if we can follow the frame-chain
	 or skip over the signal trampoline.  */
      struct dwarf_loc ebp_loc, eip_loc;

      /* We could get here because of missing/bad unwind information.
         Validate all addresses before dereferencing. */
      c->validate = 1;

      Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);

      if (unw_is_signal_frame (cursor))
        {
          ret = unw_handle_signal_frame(cursor);
	  if (ret < 0)
	    {
	      Debug (2, "returning 0\n");
	      return 0;
	    }
        }
      else
	{
	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa);
	  if (ret < 0)
	    {
	      Debug (2, "returning %d\n", ret);
	      return ret;
	    }

	  Debug (13, "[EBP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EBP]),
		 c->dwarf.cfa);

	  ebp_loc = DWARF_LOC (c->dwarf.cfa, 0);
	  eip_loc = DWARF_LOC (c->dwarf.cfa + 4, 0);
	  c->dwarf.cfa += 8;

	  /* Mark all registers unsaved, since we don't know where
	     they are saved (if at all), except for the EBP and
	     EIP.  */
	  for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
	    c->dwarf.loc[i] = DWARF_NULL_LOC;

          c->dwarf.loc[EBP] = ebp_loc;
          c->dwarf.loc[EIP] = eip_loc;
	}
      c->dwarf.ret_addr_column = EIP;

      if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP]))
	{
	  ret = dwarf_get (&c->dwarf, c->dwarf.loc[EIP], &c->dwarf.ip);
	  if (ret < 0)
	    {
	      Debug (13, "dwarf_get([EIP=0x%x]) failed\n", DWARF_GET_LOC (c->dwarf.loc[EIP]));
	      Debug (2, "returning %d\n", ret);
	      return ret;
	    }
	  else
	    {
	      Debug (13, "[EIP=0x%x] = 0x%x\n", DWARF_GET_LOC (c->dwarf.loc[EIP]),
		c->dwarf.ip);
	    }
	}
      else
	c->dwarf.ip = 0;
    }
  ret = (c->dwarf.ip == 0) ? 0 : 1;
  Debug (2, "returning %d\n", ret);
  return ret;
}