From 6bc7295264ed200ea6532c51832cf96e9a86f13f Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 1 Jan 2010 18:46:41 +0000 Subject: [PATCH] Make the Dwarf3 CFI stack unwinding machinery work on arm-linux too. This is a first step towards making not be completely x86/amd64-linux specific, and so replaces some x86/amd64-specific stuff with more general constructions: * structure 'DiCfSI', into which the info is summarised, has been made target-specific (ugh), since the sets of registers to be unwound differ on different targets. * enum CfiReg and the CFIC_ constants have been expanded accordingly, to handle both arm and x86/amd64 registers. The abbreviation "IA" (Intel Architecture) has been used in a few places where the x86 and amd64 definitions are shared. * the CFI reader/summariser in readdwarf.c has been expanded & generalised appropriately. * the DiCfSI evaluator in debuginfo.c, VG_(use_CFI_info), has also been generalised appropriately. The main change is that instead of passing around triples of (IP, SP, BP) values, a new structure 'D3UnwindRegs' is passed around instead. This is defined differently for IA and ARM and succeeds in hiding at least some of the differences where we don't care about them. Note also, D3UnwindRegs duplicates, in purpose and structure, structure 'RegSummary' in priv_d3basics.h. This will be tidied up in due course. This commit almost certainly breaks stack unwinding on amd64-linux. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10986 --- coregrind/m_debuginfo/d3basics.c | 7 +- coregrind/m_debuginfo/debuginfo.c | 157 ++++++++++++++++++--------- coregrind/m_debuginfo/priv_storage.h | 112 ++++++++++++++----- coregrind/m_debuginfo/readdwarf.c | 135 ++++++++++++++++++++--- coregrind/m_debuginfo/readelf.c | 3 +- coregrind/m_debuginfo/storage.c | 43 ++++++-- coregrind/m_stacktrace.c | 38 ++++--- coregrind/pub_core_debuginfo.h | 27 ++++- 8 files changed, 390 insertions(+), 132 deletions(-) diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c index ce14f4904d..4585894c94 100644 --- a/coregrind/m_debuginfo/d3basics.c +++ b/coregrind/m_debuginfo/d3basics.c @@ -833,13 +833,16 @@ GXResult ML_(evaluate_Dwarf3_Expr) ( UChar* expr, UWord exprszB, 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"); diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index 106d3987da..3a8f2fe0a5 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -708,7 +708,7 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV ) # 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 @@ -1395,17 +1395,17 @@ Vg_FnNameKind VG_(get_fnname_kind) ( Char* name ) 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; @@ -1821,11 +1821,9 @@ Char* VG_(describe_IP)(Addr eip, Char* buf, Int n_buf) 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; @@ -1838,7 +1836,9 @@ UWord evalCfiExpr ( XArray* exprs, Int ix, { 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 ); @@ -1855,9 +1855,19 @@ UWord evalCfiExpr ( XArray* exprs, Int ix, /*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*/ @@ -2032,7 +2042,7 @@ static CFSICacheEnt* cfsi_cache__find ( Addr ip ) } -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 ) { @@ -2043,21 +2053,34 @@ static Addr compute_cfa ( Addr ip, Addr sp, Addr fp, /* 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; @@ -2072,6 +2095,8 @@ static Addr compute_cfa ( Addr ip, Addr sp, Addr fp, /* 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 ) { @@ -2087,30 +2112,53 @@ Addr ML_(get_CFA) ( Addr ip, Addr sp, Addr fp, 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. */ @@ -2123,15 +2171,11 @@ Bool VG_(use_CF_info) ( /*MOD*/Addr* ipP, 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; @@ -2159,9 +2203,7 @@ Bool VG_(use_CF_info) ( /*MOD*/Addr* ipP, 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; \ @@ -2173,15 +2215,24 @@ Bool VG_(use_CF_info) ( /*MOD*/Addr* ipP, } \ } 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; } diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h index b790001c38..a0d4e6c936 100644 --- a/coregrind/m_debuginfo/priv_storage.h +++ b/coregrind/m_debuginfo/priv_storage.h @@ -97,55 +97,103 @@ typedef /* --------------------- 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 @@ -159,9 +207,13 @@ 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; diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index 98a72436b9..560da28fa4 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -1783,6 +1783,10 @@ void ML_(read_debuginfo_dwarf1) ( # 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 @@ -2012,6 +2016,15 @@ static void initUnwindContext ( /*OUT*/UnwindContext* ctx ) /* 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 } @@ -2031,16 +2044,7 @@ typedef 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)); } @@ -2072,7 +2076,7 @@ static Bool summarise_context( /*OUT*/DiCfSI* 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; @@ -2093,15 +2097,37 @@ static Bool summarise_context( /*OUT*/DiCfSI* si, 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; } @@ -2143,12 +2169,15 @@ static Bool summarise_context( /*OUT*/DiCfSI* si, 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 ... */ @@ -2176,6 +2205,66 @@ static Bool summarise_context( /*OUT*/DiCfSI* si, 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, @@ -2228,12 +2317,24 @@ static Int copy_convert_CfiExpr_tree ( XArray* dstxa, 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: diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c index 52d1b69821..e6cb41a31d 100644 --- a/coregrind/m_debuginfo/readelf.c +++ b/coregrind/m_debuginfo/readelf.c @@ -1642,7 +1642,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) } /* 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) { diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c index 935ee7989c..cbb0f1067b 100644 --- a/coregrind/m_debuginfo/storage.c +++ b/coregrind/m_debuginfo/storage.c @@ -126,11 +126,20 @@ void ML_(ppDiCfSI) ( XArray* /* of CfiExpr */ exprs, DiCfSI* si ) 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={"); @@ -143,10 +152,24 @@ void ML_(ppDiCfSI) ( XArray* /* of CfiExpr */ exprs, DiCfSI* si ) 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 } @@ -574,9 +597,13 @@ static void ppCfiOp ( CfiOp op ) 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); } } diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index 0b738138ef..153f50c866 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -574,12 +574,13 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 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 @@ -595,7 +596,8 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 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 */ @@ -605,36 +607,38 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, 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. */ diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h index b947af1e3d..f77bf02fb5 100644 --- a/coregrind/pub_core_debuginfo.h +++ b/coregrind/pub_core_debuginfo.h @@ -106,13 +106,32 @@ Bool VG_(get_fnname_raw) ( Addr a, Char* buf, Int nbuf ); 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, -- 2.47.2