break;
case DW_OP_call_frame_cfa:
if (!regs)
- FAIL("evaluate_Dwarf3_Expr: DW_OP_call_frame_cfa but no reg info");
+ FAIL("evaluate_Dwarf3_Expr: "
+ "DW_OP_call_frame_cfa but no reg info");
#if defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
- /* Valgrind on ppc32/ppc64 currently doesn't use unwind info. */
+ /* Valgrind on ppc32/ppc64 currently doesn't use unwind info. */
uw1 = *(Addr *)(regs->sp);
#else
uw1 = ML_(get_CFA)(regs->ip, regs->sp, regs->fp, 0, ~(UWord) 0);
#endif
+ /* we expect this to fail on arm-linux, since ML_(get_CFA)
+ always returns zero at present. */
if (!uw1)
FAIL("evaluate_Dwarf3_Expr: Could not resolve "
"DW_OP_call_frame_cfa");
# if defined(VGA_x86) || defined(VGA_ppc32)
is_rx_map = seg->hasR && seg->hasX;
is_rw_map = seg->hasR && seg->hasW;
-# elif defined(VGA_amd64) || defined(VGA_ppc64)
+# elif defined(VGA_amd64) || defined(VGA_ppc64) || defined(VGA_arm)
is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
is_rw_map = seg->hasR && seg->hasW && !seg->hasX;
# else
return Vg_FnNameMain;
} else if (
-#if defined(VGO_linux)
+# if defined(VGO_linux)
VG_STREQ("__libc_start_main", name) || // glibc glibness
VG_STREQ("generic_start_main", name) || // Yellow Dog doggedness
-#elif defined(VGO_aix5)
+# elif defined(VGO_aix5)
VG_STREQ("__start", name) || // AIX aches
-#elif defined(VGO_darwin)
+# elif defined(VGO_darwin)
// See readmacho.c for an explanation of this.
VG_STREQ("start_according_to_valgrind", name) || // Darwin, darling
-#else
-# error Unknown OS
-#endif
+# else
+# error "Unknown OS"
+# endif
0) {
return Vg_FnNameBelowMain;
a CfiExpr into one convenient struct. */
typedef
struct {
- Addr ipHere;
- Addr spHere;
- Addr fpHere;
- Addr min_accessible;
- Addr max_accessible;
+ D3UnwindRegs* uregs;
+ Addr min_accessible;
+ Addr max_accessible;
}
CfiExprEvalContext;
{
UWord wL, wR;
Addr a;
- CfiExpr* e = VG_(indexXA)( exprs, ix );
+ CfiExpr* e;
+ vg_assert(sizeof(Addr) == sizeof(UWord));
+ e = VG_(indexXA)( exprs, ix );
switch (e->tag) {
case Cex_Binop:
wL = evalCfiExpr( exprs, e->Cex.Binop.ixL, eec, ok );
/*NOTREACHED*/
case Cex_CfiReg:
switch (e->Cex.CfiReg.reg) {
- case Creg_IP: return (Addr)eec->ipHere;
- case Creg_SP: return (Addr)eec->spHere;
- case Creg_FP: return (Addr)eec->fpHere;
+# if defined(VGA_x86) || defined(VGA_amd64)
+ case Creg_IA_IP: return eec->uregs->xip;
+ case Creg_IA_SP: return eec->uregs->xsp;
+ case Creg_IA_BP: return eec->uregs->xbp;
+# elif defined(VGA_arm)
+ case Creg_ARM_R13: return eec->uregs->r13;
+ case Creg_ARM_R12: return eec->uregs->r12;
+ case Creg_ARM_R15: return eec->uregs->r15;
+ case Creg_ARM_R14: return eec->uregs->r14;
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unsupported arch"
+# endif
default: goto unhandled;
}
/*NOTREACHED*/
}
-static Addr compute_cfa ( Addr ip, Addr sp, Addr fp,
+static Addr compute_cfa ( D3UnwindRegs* uregs,
Addr min_accessible, Addr max_accessible,
DebugInfo* di, DiCfSI* cfsi )
{
/* Compute the CFA. */
cfa = 0;
switch (cfsi->cfa_how) {
- case CFIC_SPREL:
- cfa = sp + cfsi->cfa_off;
+# if defined(VGA_x86) || defined(VGA_amd64)
+ case CFIC_IA_SPREL:
+ cfa = cfsi->cfa_off + uregs->xsp;
+ break;
+ case CFIC_IA_BPREL:
+ cfa = cfsi->cfa_off + uregs->xbp;
break;
- case CFIC_FPREL:
- cfa = fp + cfsi->cfa_off;
+# elif defined(VGA_arm)
+ case CFIC_ARM_R13REL:
+ cfa = cfsi->cfa_off + uregs->r13;
break;
- case CFIC_EXPR:
+ case CFIC_ARM_R12REL:
+ cfa = cfsi->cfa_off + uregs->r12;
+ break;
+ case CFIC_ARM_R11REL:
+ cfa = cfsi->cfa_off + uregs->r11;
+ break;
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unsupported arch"
+# endif
+ case CFIC_EXPR: /* available on all archs */
if (0) {
VG_(printf)("CFIC_EXPR: ");
ML_(ppCfiExpr)(di->cfsi_exprs, cfsi->cfa_off);
VG_(printf)("\n");
}
- eec.ipHere = ip;
- eec.spHere = sp;
- eec.fpHere = fp;
+ eec.uregs = uregs;
eec.min_accessible = min_accessible;
eec.max_accessible = max_accessible;
ok = True;
/* Get the call frame address (CFA) given an IP/SP/FP triple. */
+/* NOTE: This function may rearrange the order of entries in the
+ DebugInfo list. */
Addr ML_(get_CFA) ( Addr ip, Addr sp, Addr fp,
Addr min_accessible, Addr max_accessible )
{
di = ce->di;
cfsi = &di->cfsi[ ce->ix ];
- return compute_cfa(ip, sp, fp, min_accessible, max_accessible, di, cfsi);
+ /* Temporary impedance-matching kludge so that this keeps working
+ on x86-linux and amd64-linux. */
+# if defined(VGA_x86) || defined(VGA_amd64)
+ { D3UnwindRegs uregs;
+ uregs.xip = ip;
+ uregs.xsp = sp;
+ uregs.xbp = fp;
+ return compute_cfa(&uregs,
+ min_accessible, max_accessible, di, cfsi);
+ }
+# else
+ return 0; /* indicates failure */
+# endif
}
-/* The main function for DWARF2/3 CFI-based stack unwinding.
- Given an IP/SP/FP triple, produce the IP/SP/FP values for the
- previous frame, if possible. */
-/* Returns True if OK. If not OK, *{ip,sp,fp}P are not changed. */
-/* NOTE: this function may rearrange the order of entries in the
- DebugInfo list. */
-Bool VG_(use_CF_info) ( /*MOD*/Addr* ipP,
- /*MOD*/Addr* spP,
- /*MOD*/Addr* fpP,
+/* The main function for DWARF2/3 CFI-based stack unwinding. Given a
+ set of registers in UREGS, modify it to hold the register values
+ for the previous frame, if possible. Returns True if successful.
+ If not successful, *UREGS is not changed.
+
+ For x86 and amd64, the unwound registers are: {E,R}IP,
+ {E,R}SP, {E,R}BP.
+
+ For arm, the unwound registers are: R11 R12 R13 R14 R15.
+*/
+Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere,
Addr min_accessible,
Addr max_accessible )
{
Bool ok;
DebugInfo* di;
DiCfSI* cfsi = NULL;
- Addr cfa, ipHere, spHere, fpHere, ipPrev, spPrev, fpPrev;
+ Addr cfa, ipHere = 0;
CFSICacheEnt* ce;
CfiExprEvalContext eec;
+ D3UnwindRegs uregsPrev;
- ce = cfsi_cache__find(*ipP);
+# if defined(VGA_x86) || defined(VGA_amd64)
+ ipHere = uregsHere->xip;
+# elif defined(VGA_arm)
+ ipHere = uregsHere->r15;
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unknown arch"
+# endif
+ ce = cfsi_cache__find(ipHere);
if (UNLIKELY(ce == NULL))
return False; /* no info. Nothing we can do. */
ML_(ppDiCfSI)(di->cfsi_exprs, cfsi);
}
- ipPrev = spPrev = fpPrev = 0;
-
- ipHere = *ipP;
- spHere = *spP;
- fpHere = *fpP;
+ VG_(memset)(&uregsPrev, 0, sizeof(uregsPrev));
/* First compute the CFA. */
- cfa = compute_cfa(ipHere, spHere, fpHere,
- min_accessible, max_accessible, di, cfsi);
+ cfa = compute_cfa(uregsHere,
+ min_accessible, max_accessible, di, cfsi);
if (UNLIKELY(cfa == 0))
return False;
case CFIR_EXPR: \
if (0) \
ML_(ppCfiExpr)(di->cfsi_exprs,_off); \
- eec.ipHere = ipHere; \
- eec.spHere = spHere; \
- eec.fpHere = fpHere; \
+ eec.uregs = uregsHere; \
eec.min_accessible = min_accessible; \
eec.max_accessible = max_accessible; \
ok = True; \
} \
} while (0)
- COMPUTE(ipPrev, ipHere, cfsi->ra_how, cfsi->ra_off);
- COMPUTE(spPrev, spHere, cfsi->sp_how, cfsi->sp_off);
- COMPUTE(fpPrev, fpHere, cfsi->fp_how, cfsi->fp_off);
+# if defined(VGA_x86) || defined(VGA_amd64)
+ COMPUTE(uregsPrev.xip, uregsHere->xip, cfsi->ra_how, cfsi->ra_off);
+ COMPUTE(uregsPrev.xsp, uregsPrev->xsp, cfsi->sp_how, cfsi->sp_off);
+ COMPUTE(uregsPrev.xbp, uregsPrev->xbp, cfsi->bp_how, cfsi->bp_off);
+# elif defined(VGA_arm)
+ COMPUTE(uregsPrev.r15, uregsHere->r15, cfsi->ra_how, cfsi->ra_off);
+ COMPUTE(uregsPrev.r14, uregsHere->r14, cfsi->r14_how, cfsi->r14_off);
+ COMPUTE(uregsPrev.r13, uregsHere->r13, cfsi->r13_how, cfsi->r13_off);
+ COMPUTE(uregsPrev.r12, uregsHere->r12, cfsi->r12_how, cfsi->r12_off);
+ COMPUTE(uregsPrev.r11, uregsHere->r11, cfsi->r11_how, cfsi->r11_off);
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unknown arch"
+# endif
# undef COMPUTE
- *ipP = ipPrev;
- *spP = spPrev;
- *fpP = fpPrev;
+ *uregsHere = uregsPrev;
return True;
}
/* --------------------- CF INFO --------------------- */
-/* A structure to summarise DWARF2/3 CFA info for the code address
- range [base .. base+len-1]. In short, if you know (sp,fp,ip) at
- some point and ip is in the range [base .. base+len-1], it tells
- you how to calculate (sp,fp) for the caller of the current frame
- and also ra, the return address of the current frame.
+/* DiCfSI: a structure to summarise DWARF2/3 CFA info for the code
+ address range [base .. base+len-1].
+
+ On x86 and amd64 ("IA"), if you know ({e,r}sp, {e,r}bp, {e,r}ip) at
+ some point and {e,r}ip is in the range [base .. base+len-1], it
+ tells you how to calculate ({e,r}sp, {e,r}bp) for the caller of the
+ current frame and also ra, the return address of the current frame.
First off, calculate CFA, the Canonical Frame Address, thusly:
cfa = case cfa_how of
- CFIC_SPREL -> sp + cfa_off
- CFIC_FPREL -> fp + cfa_off
- CFIR_EXPR -> expr whose index is in cfa_off
+ CFIC_IA_SPREL -> {e,r}sp + cfa_off
+ CFIC_IA_BPREL -> {e,r}bp + cfa_off
+ CFIR_IA_EXPR -> expr whose index is in cfa_off
- Once that is done, the previous frame's sp/fp values and this
- frame's ra value can be calculated like this:
+ Once that is done, the previous frame's {e,r}sp/{e,r}bp values and
+ this frame's {e,r}ra value can be calculated like this:
- old_sp/fp/ra
- = case sp/fp/ra_how of
+ old_{e,r}sp/{e,r}bp/ra
+ = case {e,r}sp/{e,r}bp/ra_how of
CFIR_UNKNOWN -> we don't know, sorry
CFIR_SAME -> same as it was before (sp/fp only)
- CFIR_CFAREL -> cfa + sp/fp/ra_off
- CFIR_MEMCFAREL -> *( cfa + sp/fp/ra_off )
- CFIR_EXPR -> expr whose index is in sp/fp/ra_off
-*/
+ CFIR_CFAREL -> cfa + sp/bp/ra_off
+ CFIR_MEMCFAREL -> *( cfa + sp/bp/ra_off )
+ CFIR_EXPR -> expr whose index is in sp/bp/ra_off
-#define CFIC_SPREL ((UChar)1)
-#define CFIC_FPREL ((UChar)2)
-#define CFIC_EXPR ((UChar)3)
+ On ARM it's pretty much the same, except we have more registers to
+ keep track of:
-#define CFIR_UNKNOWN ((UChar)4)
-#define CFIR_SAME ((UChar)5)
-#define CFIR_CFAREL ((UChar)6)
-#define CFIR_MEMCFAREL ((UChar)7)
-#define CFIR_EXPR ((UChar)8)
+ cfa = case cfa_how of
+ CFIC_R13REL -> r13 + cfa_off
+ CFIC_R12REL -> r12 + cfa_off
+ CFIC_R11REL -> r11 + cfa_off
+ CFIR_EXPR -> expr whose index is in cfa_off
+ old_r14/r13/r12/r11/ra
+ = case r14/r13/r12/r11/ra_how of
+ CFIR_UNKNOWN -> we don't know, sorry
+ CFIR_SAME -> same as it was before (r14/r13/r12/r11 only)
+ CFIR_CFAREL -> cfa + r14/r13/r12/r11/ra_off
+ CFIR_MEMCFAREL -> *( cfa + r14/r13/r12/r11/ra_off )
+ CFIR_EXPR -> expr whose index is in r14/r13/r12/r11/ra_off
+*/
+
+#define CFIC_IA_SPREL ((UChar)1)
+#define CFIC_IA_BPREL ((UChar)2)
+#define CFIC_IA_EXPR ((UChar)3)
+#define CFIC_ARM_R13REL ((UChar)4)
+#define CFIC_ARM_R12REL ((UChar)5)
+#define CFIC_ARM_R11REL ((UChar)6)
+#define CFIC_EXPR ((UChar)7) /* all targets */
+
+#define CFIR_UNKNOWN ((UChar)64)
+#define CFIR_SAME ((UChar)65)
+#define CFIR_CFAREL ((UChar)66)
+#define CFIR_MEMCFAREL ((UChar)67)
+#define CFIR_EXPR ((UChar)68)
+
+#if defined(VGA_x86) || defined(VGA_amd64)
typedef
struct {
Addr base;
UInt len;
- UChar cfa_how; /* a CFIC_ value */
+ UChar cfa_how; /* a CFIC_IA value */
UChar ra_how; /* a CFIR_ value */
UChar sp_how; /* a CFIR_ value */
- UChar fp_how; /* a CFIR_ value */
+ UChar bp_how; /* a CFIR_ value */
Int cfa_off;
Int ra_off;
Int sp_off;
- Int fp_off;
+ Int bp_off;
+ }
+ DiCfSI;
+#elif defined(VGA_arm)
+typedef
+ struct {
+ Addr base;
+ UInt len;
+ UChar cfa_how; /* a CFIC_ value */
+ UChar ra_how; /* a CFIR_ value */
+ UChar r14_how; /* a CFIR_ value */
+ UChar r13_how; /* a CFIR_ value */
+ UChar r12_how; /* a CFIR_ value */
+ UChar r11_how; /* a CFIR_ value */
+ Int cfa_off;
+ Int ra_off;
+ Int r14_off;
+ Int r13_off;
+ Int r12_off;
+ Int r11_off;
}
DiCfSI;
+#elif defined(VGA_ppc32) || defined(VGA_ppc64)
+typedef void DiCfSI;
+#else
+# error "Unknown arch"
+#endif
typedef
typedef
enum {
- Creg_SP=0x213,
- Creg_FP,
- Creg_IP
+ Creg_IA_SP=0x213,
+ Creg_IA_BP,
+ Creg_IA_IP,
+ Creg_ARM_R13,
+ Creg_ARM_R12,
+ Creg_ARM_R15,
+ Creg_ARM_R14
}
CfiReg;
# define FP_REG 1
# define SP_REG 1
# define RA_REG_DEFAULT 65
+#elif defined(VGP_arm_linux)
+# define FP_REG 12
+# define SP_REG 13
+# define RA_REG_DEFAULT 14 //???
#elif defined(VGP_x86_darwin)
# define FP_REG 5
# define SP_REG 4
/* ctx->state[j].reg[i].arg = 0; */
}
}
+# if defined(VGA_arm)
+ /* All callee-saved registers (or at least the ones we are
+ summarising for) should start out as RR_Same, on ARM. */
+ ctx->state[j].reg[11].tag = RR_Same;
+ /* ctx->state[j].reg[13].tag = RR_Same; */
+ ctx->state[j].reg[14].tag = RR_Same;
+ ctx->state[j].reg[12].tag = RR_Same;
+ /* this can't be right though: R12 (IP) isn't callee saved. */
+# endif
}
static void initCfiSI ( DiCfSI* si )
{
- si->base = 0;
- si->len = 0;
- si->cfa_how = 0;
- si->ra_how = 0;
- si->sp_how = 0;
- si->fp_how = 0;
- si->cfa_off = 0;
- si->ra_off = 0;
- si->sp_off = 0;
- si->fp_off = 0;
+ VG_(memset)(si, 0, sizeof(*si));
}
if (ctx->state_sp >= N_RR_STACK) { why = 9; goto failed; }
ctxs = &ctx->state[ctx->state_sp];
- /* How to generate the CFA */
+ /* First, summarise the method for generating the CFA */
if (!ctxs->cfa_is_regoff) {
/* it was set by DW_CFA_def_cfa_expression; try to convert */
XArray *src, *dst;
si->cfa_off = conv;
if (0 && debuginfo->ddump_frames)
ML_(ppCfiExpr)(dst, conv);
- } else
+ }
+ else
if (ctxs->cfa_is_regoff && ctxs->cfa_reg == SP_REG) {
- si->cfa_how = CFIC_SPREL;
si->cfa_off = ctxs->cfa_off;
- } else
+# if defined(VGA_x86) || defined(VGA_amd64)
+ si->cfa_how = CFIC_IA_SPREL;
+# elif defined(VGA_arm)
+ si->cfa_how = CFIC_ARM_R13REL;
+# else
+ si->cfa_how = 0; /* invalid */
+# endif
+ }
+ else
if (ctxs->cfa_is_regoff && ctxs->cfa_reg == FP_REG) {
- si->cfa_how = CFIC_FPREL;
si->cfa_off = ctxs->cfa_off;
- } else {
+# if defined(VGA_x86) || defined(VGA_amd64)
+ si->cfa_how = CFIC_IA_BPREL;
+# elif defined(VGA_arm)
+ si->cfa_how = CFIC_ARM_R12REL;
+# else
+ si->cfa_how = 0; /* invalid */
+# endif
+ }
+# if defined(VGA_arm)
+ else
+ if (ctxs->cfa_is_regoff && ctxs->cfa_reg == 11/*??_REG*/) {
+ si->cfa_how = CFIC_ARM_R11REL;
+ si->cfa_off = ctxs->cfa_off;
+ }
+# endif
+ else {
why = 1;
goto failed;
}
why = 2; goto failed; /* otherwise give up */ \
}
+# if defined(VGA_x86) || defined(VGA_amd64)
+
+ /* --- entire tail of this fn specialised for x86/amd64 --- */
+
SUMMARISE_HOW(si->ra_how, si->ra_off,
ctxs->reg[ctx->ra_reg] );
SUMMARISE_HOW(si->fp_how, si->fp_off,
ctxs->reg[FP_REG] );
-# undef SUMMARISE_HOW
/* on x86/amd64, it seems the old %{e,r}sp value before the call is
always the same as the CFA. Therefore ... */
return True;
+# elif defined(VGA_arm)
+
+ /* ---- entire tail of this fn specialised for arm ---- */
+
+ SUMMARISE_HOW(si->r14_how, si->r14_off,
+ ctxs->reg[14] );
+
+ //SUMMARISE_HOW(si->r13_how, si->r13_off,
+ // ctxs->reg[13] );
+
+ SUMMARISE_HOW(si->r12_how, si->r12_off,
+ ctxs->reg[FP_REG] );
+
+ SUMMARISE_HOW(si->r11_how, si->r11_off,
+ ctxs->reg[11/*FP_REG*/] );
+
+ if (ctxs->reg[14/*LR*/].tag == RR_Same
+ && ctx->ra_reg == 14/*as we expect it always to be*/) {
+ /* Generate a trivial CfiExpr, which merely says "r14". First
+ ensure this DebugInfo has a cfsi_expr array in which to park
+ it. */
+ if (!debuginfo->cfsi_exprs)
+ debuginfo->cfsi_exprs = VG_(newXA)( ML_(dinfo_zalloc),
+ "di.ccCt.2a",
+ ML_(dinfo_free),
+ sizeof(CfiExpr) );
+ si->ra_off = ML_(CfiExpr_CfiReg)( debuginfo->cfsi_exprs,
+ Creg_ARM_R14);
+ si->ra_how = CFIR_EXPR;
+ } else {
+ /* Just summarise it in the normal way */
+ SUMMARISE_HOW(si->ra_how, si->ra_off,
+ ctxs->reg[ctx->ra_reg] );
+ }
+
+ /* on arm, it seems the old r13 (SP) value before the call is
+ always the same as the CFA. Therefore ... */
+ si->r13_how = CFIR_CFAREL;
+ si->r13_off = 0;
+
+ /* bogus looking range? Note, we require that the difference is
+ representable in 32 bits. */
+ if (loc_start >= ctx->loc)
+ { why = 4; goto failed; }
+ if (ctx->loc - loc_start > 10000000 /* let's say */)
+ { why = 5; goto failed; }
+
+ si->base = loc_start + ctx->initloc;
+ si->len = (UInt)(ctx->loc - loc_start);
+
+ return True;
+
+
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unknown arch"
+# endif
+
+# undef SUMMARISE_HOW
+
failed:
if (VG_(clo_verbosity) > 2 || debuginfo->trace_cfi) {
VG_(message)(Vg_DebugMsg,
case Cex_DwReg:
/* This is the only place where the conversion can fail. */
dwreg = src->Cex.DwReg.reg;
+# if defined(VGA_x86) || defined(VGA_amd64)
if (dwreg == SP_REG)
return ML_(CfiExpr_CfiReg)( dstxa, Creg_SP );
if (dwreg == FP_REG)
return ML_(CfiExpr_CfiReg)( dstxa, Creg_FP );
if (dwreg == srcuc->ra_reg)
return ML_(CfiExpr_CfiReg)( dstxa, Creg_IP ); /* correct? */
+# elif defined(VGA_arm)
+ if (dwreg == SP_REG)
+ return ML_(CfiExpr_CfiReg)( dstxa, Creg_ARM_R13 );
+ if (dwreg == FP_REG)
+ return ML_(CfiExpr_CfiReg)( dstxa, Creg_ARM_R12 );
+ if (dwreg == srcuc->ra_reg)
+ return ML_(CfiExpr_CfiReg)( dstxa, Creg_ARM_R15 ); /* correct? */
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unknown arch"
+# endif
/* else we must fail - can't represent the reg */
return -1;
default:
}
/* PLT is different on different platforms, it seems. */
-# if defined(VGP_x86_linux) || defined(VGP_amd64_linux)
+# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
+ || defined(VGP_arm_linux)
/* Accept .plt where mapped as rx (code) */
if (0 == VG_(strcmp)(name, ".plt")) {
if (inrx && size > 0 && !di->plt_present) {
VG_(printf)("[%#lx .. %#lx]: ", si->base,
si->base + (UWord)si->len - 1);
switch (si->cfa_how) {
- case CFIC_SPREL:
+ case CFIC_IA_SPREL:
VG_(printf)("let cfa=oldSP+%d", si->cfa_off);
break;
- case CFIC_FPREL:
- VG_(printf)("let cfa=oldFP+%d", si->cfa_off);
+ case CFIC_IA_BPREL:
+ VG_(printf)("let cfa=oldBP+%d", si->cfa_off);
+ break;
+ case CFIC_ARM_R13REL:
+ VG_(printf)("let cfa=oldR13+%d", si->cfa_off);
+ break;
+ case CFIC_ARM_R12REL:
+ VG_(printf)("let cfa=oldR12+%d", si->cfa_off);
+ break;
+ case CFIC_ARM_R11REL:
+ VG_(printf)("let cfa=oldR11+%d", si->cfa_off);
break;
case CFIC_EXPR:
VG_(printf)("let cfa={");
VG_(printf)(" in RA=");
SHOW_HOW(si->ra_how, si->ra_off);
+# if defined(VGA_x86) || defined(VGA_amd64)
VG_(printf)(" SP=");
SHOW_HOW(si->sp_how, si->sp_off);
- VG_(printf)(" FP=");
- SHOW_HOW(si->fp_how, si->fp_off);
+ VG_(printf)(" BP=");
+ SHOW_HOW(si->bp_how, si->bp_off);
+# elif defined(VGA_arm)
+ VG_(printf)(" R14=");
+ SHOW_HOW(si->r14_how, si->r14_off);
+ VG_(printf)(" R13=");
+ SHOW_HOW(si->r13_how, si->r13_off);
+ VG_(printf)(" R12=");
+ SHOW_HOW(si->r12_how, si->r12_off);
+ VG_(printf)(" R11=");
+ SHOW_HOW(si->r11_how, si->r11_off);
+# elif defined(VGA_ppc32) || defined(VGA_ppc64)
+# else
+# error "Unknown arch"
+# endif
VG_(printf)("\n");
# undef SHOW_HOW
}
static void ppCfiReg ( CfiReg reg )
{
switch (reg) {
- case Creg_SP: VG_(printf)("SP"); break;
- case Creg_FP: VG_(printf)("FP"); break;
- case Creg_IP: VG_(printf)("IP"); break;
+ case Creg_IA_SP: VG_(printf)("xSP"); break;
+ case Creg_IA_BP: VG_(printf)("xBP"); break;
+ case Creg_IA_IP: VG_(printf)("xIP"); break;
+ case Creg_ARM_R13: VG_(printf)("R13"); break;
+ case Creg_ARM_R12: VG_(printf)("R12"); break;
+ case Creg_ARM_R15: VG_(printf)("R15"); break;
+ case Creg_ARM_R14: VG_(printf)("R14"); break;
default: vg_assert(0);
}
}
vg_assert(sizeof(Addr) == sizeof(UWord));
vg_assert(sizeof(Addr) == sizeof(void*));
- Addr r15 = startRegs->r_pc;
- Addr r13 = startRegs->r_sp;
- Addr r14 = startRegs->misc.ARM.r14;
- Addr r12 = startRegs->misc.ARM.r12;
- Addr r11 = startRegs->misc.ARM.r11;
- Addr fp_min = r13;
+ D3UnwindRegs uregs;
+ uregs.r15 = startRegs->r_pc;
+ uregs.r14 = startRegs->misc.ARM.r14;
+ uregs.r13 = startRegs->r_sp;
+ uregs.r12 = startRegs->misc.ARM.r12;
+ uregs.r11 = startRegs->misc.ARM.r11;
+ Addr fp_min = uregs.r13;
/* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1],
stopping when the trail goes cold, which we guess to be
if (debug)
VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, "
"fp_max=0x%lx r15=0x%lx r13=0x%lx\n",
- max_n_ips, fp_min, fp_max_orig, fp_max, r15, r13);
+ max_n_ips, fp_min, fp_max_orig, fp_max,
+ uregs.r15, uregs.r13);
/* Assertion broken before main() is reached in pthreaded programs; the
* offending stack traces only have one item. --njn, 2002-aug-16 */
if (fp_min + 512 >= fp_max) {
/* If the stack limits look bogus, don't poke around ... but
don't bomb out either. */
- if (sps) sps[0] = r13;
+ if (sps) sps[0] = uregs.r13;
if (fps) fps[0] = 0;
- ips[0] = r15;
+ ips[0] = uregs.r15;
return 1;
}
/* */
- if (sps) sps[0] = r13;
+ if (sps) sps[0] = uregs.r13;
if (fps) fps[0] = 0;
- ips[0] = r15;
+ ips[0] = uregs.r15;
i = 1;
/* Loop unwinding the stack. */
while (True) {
if (debug) {
- VG_(printf)("i: %d, r15: 0x%lx, r13: 0x%lx\n",i, r15, r13);
+ VG_(printf)("i: %d, r15: 0x%lx, r13: 0x%lx\n",
+ i, uregs.r15, uregs.r13);
}
if (i >= max_n_ips)
break;
- if (VG_(use_CF_info)( &r15, &r14, &r13, &r12, &r11, fp_min, fp_max )) {
- if (sps) sps[i] = r13;
+ if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) {
+ if (sps) sps[i] = uregs.r13;
if (fps) fps[i] = 0;
- ips[i++] = r15 -1;
+ ips[i++] = uregs.r15 -1;
if (debug)
- VG_(printf)("USING CFI: r15: 0x%lx, r13: 0x%lx\n", r15, r13);
- r15 = r15 - 1;
+ VG_(printf)("USING CFI: r15: 0x%lx, r13: 0x%lx\n",
+ uregs.r15, uregs.r13);
+ uregs.r15 = uregs.r15 - 1;
continue;
}
/* No luck. We have to give up. */
extern
Bool VG_(get_fnname_no_cxx_demangle) ( Addr a, Char* buf, Int nbuf );
-/* Use DWARF2/3 CFA information to do one step of stack unwinding. */
-extern Bool VG_(use_CF_info) ( /*MOD*/Addr* ipP,
- /*MOD*/Addr* spP,
- /*MOD*/Addr* fpP,
+
+/* Use DWARF2/3 CFA information to do one step of stack unwinding.
+ D3UnwindRegs holds the current register values, and is
+ arch-specific. Note that the x86 and amd64 definitions are shared
+ and so the regs are named 'xip' etc rather than 'eip' and 'rip'. */
+#if defined(VGA_amd64) || defined(VGA_x86)
+typedef
+ struct { Addr xip; Addr xsp; Addr xbp; }
+ D3UnwindRegs;
+#elif defined(VGA_arm)
+typedef
+ struct { Addr r15; Addr r14; Addr r13; Addr r12; Addr r11; }
+ D3UnwindRegs;
+#elif defined(VGA_ppc32) || defined(VGA_ppc64)
+typedef
+ void
+ D3UnwindRegs;
+#else
+# error "Unsupported arch"
+#endif
+
+extern Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregs,
Addr min_accessible,
Addr max_accessible );
+
/* Use MSVC FPO data to do one step of stack unwinding. */
extern Bool VG_(use_FPO_info) ( /*MOD*/Addr* ipP,
/*MOD*/Addr* spP,