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; }
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; }
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; }
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; }
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; }
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; }