|
From: <sv...@va...> - 2010-01-01 18:46:50
|
Author: sewardj
Date: 2010-01-01 18:46:41 +0000 (Fri, 01 Jan 2010)
New Revision: 10986
Log:
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.
Modified:
trunk/coregrind/m_debuginfo/d3basics.c
trunk/coregrind/m_debuginfo/debuginfo.c
trunk/coregrind/m_debuginfo/priv_storage.h
trunk/coregrind/m_debuginfo/readdwarf.c
trunk/coregrind/m_debuginfo/readelf.c
trunk/coregrind/m_debuginfo/storage.c
trunk/coregrind/m_stacktrace.c
trunk/coregrind/pub_core_debuginfo.h
Modified: trunk/coregrind/m_debuginfo/d3basics.c
===================================================================
--- trunk/coregrind/m_debuginfo/d3basics.c 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_debuginfo/d3basics.c 2010-01-01 18:46:41 UTC (rev 10986)
@@ -833,13 +833,16 @@
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");
Modified: trunk/coregrind/m_debuginfo/debuginfo.c
===================================================================
--- trunk/coregrind/m_debuginfo/debuginfo.c 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_debuginfo/debuginfo.c 2010-01-01 18:46:41 UTC (rev 10986)
@@ -708,7 +708,7 @@
# 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 @@
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 @@
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 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 @@
/*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 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 @@
/* 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_FPREL:
- cfa = fp + cfsi->cfa_off;
+ case CFIC_IA_BPREL:
+ cfa = cfsi->cfa_off + uregs->xbp;
break;
- case CFIC_EXPR:
+# elif defined(VGA_arm)
+ case CFIC_ARM_R13REL:
+ cfa = cfsi->cfa_off + uregs->r13;
+ break;
+ 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 @@
/* 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 @@
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 @@
ML_(ppDiCfSI)(di->cfsi_exprs, cfsi);
}
- ipPrev = spPrev = fpPrev = 0;
+ VG_(memset)(&uregsPrev, 0, sizeof(uregsPrev));
- ipHere = *ipP;
- spHere = *spP;
- fpHere = *fpP;
-
/* 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 @@
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 @@
} \
} 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;
}
Modified: trunk/coregrind/m_debuginfo/priv_storage.h
===================================================================
--- trunk/coregrind/m_debuginfo/priv_storage.h 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_debuginfo/priv_storage.h 2010-01-01 18:46:41 UTC (rev 10986)
@@ -97,55 +97,103 @@
/* --------------------- 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
+
+ On ARM it's pretty much the same, except we have more registers to
+ keep track of:
+
+ 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_SPREL ((UChar)1)
-#define CFIC_FPREL ((UChar)2)
-#define CFIC_EXPR ((UChar)3)
+#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)4)
-#define CFIR_SAME ((UChar)5)
-#define CFIR_CFAREL ((UChar)6)
-#define CFIR_MEMCFAREL ((UChar)7)
-#define CFIR_EXPR ((UChar)8)
+#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
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;
Modified: trunk/coregrind/m_debuginfo/readdwarf.c
===================================================================
--- trunk/coregrind/m_debuginfo/readdwarf.c 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_debuginfo/readdwarf.c 2010-01-01 18:46:41 UTC (rev 10986)
@@ -1783,6 +1783,10 @@
# 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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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:
Modified: trunk/coregrind/m_debuginfo/readelf.c
===================================================================
--- trunk/coregrind/m_debuginfo/readelf.c 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_debuginfo/readelf.c 2010-01-01 18:46:41 UTC (rev 10986)
@@ -1642,7 +1642,8 @@
}
/* 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) {
Modified: trunk/coregrind/m_debuginfo/storage.c
===================================================================
--- trunk/coregrind/m_debuginfo/storage.c 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_debuginfo/storage.c 2010-01-01 18:46:41 UTC (rev 10986)
@@ -126,12 +126,21 @@
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={");
ML_(ppCfiExpr)(exprs, si->cfa_off);
@@ -143,10 +152,24 @@
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 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);
}
}
Modified: trunk/coregrind/m_stacktrace.c
===================================================================
--- trunk/coregrind/m_stacktrace.c 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/m_stacktrace.c 2010-01-01 18:46:41 UTC (rev 10986)
@@ -574,12 +574,13 @@
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 @@
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 @@
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. */
Modified: trunk/coregrind/pub_core_debuginfo.h
===================================================================
--- trunk/coregrind/pub_core_debuginfo.h 2010-01-01 18:31:41 UTC (rev 10985)
+++ trunk/coregrind/pub_core_debuginfo.h 2010-01-01 18:46:41 UTC (rev 10986)
@@ -106,13 +106,32 @@
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,
|