From 0bb6f49531d6bd46abc0a2c1a7e1689ae186456f Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Thu, 23 Sep 2010 22:05:59 +0000 Subject: [PATCH] On arm-linux, add r7 to the set of registers that the CFI unwinder knows how to unwind. This is important when unwinding Thumb code the CFA is often stated as being at some offset from r7. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11377 --- coregrind/m_debuginfo/debuginfo.c | 10 +++++++--- coregrind/m_debuginfo/priv_storage.h | 18 +++++++++++------- coregrind/m_debuginfo/readdwarf.c | 9 +++++++++ coregrind/m_debuginfo/storage.c | 5 +++++ coregrind/m_libcassert.c | 4 +++- coregrind/m_machine.c | 2 ++ coregrind/m_signals.c | 1 + coregrind/m_stacktrace.c | 9 +++++---- coregrind/pub_core_basics.h | 1 + coregrind/pub_core_debuginfo.h | 2 +- 10 files changed, 45 insertions(+), 16 deletions(-) diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c index 25f5615e7..6133fea1f 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -1944,10 +1944,10 @@ UWord evalCfiExpr ( XArray* exprs, Int ix, 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; + case Creg_ARM_R13: return eec->uregs->r13; + case Creg_ARM_R12: return eec->uregs->r12; # elif defined(VGA_ppc32) || defined(VGA_ppc64) # else # error "Unsupported arch" @@ -2155,6 +2155,9 @@ static Addr compute_cfa ( D3UnwindRegs* uregs, case CFIC_ARM_R11REL: cfa = cfsi->cfa_off + uregs->r11; break; + case CFIC_ARM_R7REL: + cfa = cfsi->cfa_off + uregs->r7; + break; # elif defined(VGA_ppc32) || defined(VGA_ppc64) # else # error "Unsupported arch" @@ -2221,7 +2224,7 @@ Addr ML_(get_CFA) ( Addr ip, Addr sp, Addr fp, 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. + For arm, the unwound registers are: R7 R11 R12 R13 R14 R15. */ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere, Addr min_accessible, @@ -2310,6 +2313,7 @@ Bool VG_(use_CF_info) ( /*MOD*/D3UnwindRegs* uregsHere, 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); + COMPUTE(uregsPrev.r7, uregsHere->r7, cfsi->r7_how, cfsi->r7_off); # elif defined(VGA_ppc32) || defined(VGA_ppc64) # else # error "Unknown arch" diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h index b26982516..e27252960 100644 --- a/coregrind/m_debuginfo/priv_storage.h +++ b/coregrind/m_debuginfo/priv_storage.h @@ -130,15 +130,16 @@ typedef CFIC_R13REL -> r13 + cfa_off CFIC_R12REL -> r12 + cfa_off CFIC_R11REL -> r11 + cfa_off + CFIC_R7REL -> r7 + 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 + old_r14/r13/r12/r11/r7/ra + = case r14/r13/r12/r11/r7/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 + CFIR_SAME -> same as it was before (r14/r13/r12/r11/r7 only) + CFIR_CFAREL -> cfa + r14/r13/r12/r11/r7/ra_off + CFIR_MEMCFAREL -> *( cfa + r14/r13/r12/r11/r7/ra_off ) + CFIR_EXPR -> expr whose index is in r14/r13/r12/r11/r7/ra_off */ #define CFIC_IA_SPREL ((UChar)1) @@ -147,7 +148,8 @@ typedef #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 CFIC_ARM_R7REL ((UChar)7) +#define CFIC_EXPR ((UChar)8) /* all targets */ #define CFIR_UNKNOWN ((UChar)64) #define CFIR_SAME ((UChar)65) @@ -181,12 +183,14 @@ typedef UChar r13_how; /* a CFIR_ value */ UChar r12_how; /* a CFIR_ value */ UChar r11_how; /* a CFIR_ value */ + UChar r7_how; /* a CFIR_ value */ Int cfa_off; Int ra_off; Int r14_off; Int r13_off; Int r12_off; Int r11_off; + Int r7_off; } DiCfSI; #elif defined(VGA_ppc32) || defined(VGA_ppc64) diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index 3d16d5e37..d637a759f 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -2059,6 +2059,7 @@ static void initUnwindContext ( /*OUT*/UnwindContext* ctx ) /* ctx->state[j].reg[13].tag = RR_Same; */ ctx->state[j].reg[14].tag = RR_Same; ctx->state[j].reg[12].tag = RR_Same; + ctx->state[j].reg[7].tag = RR_Same; /* this can't be right though: R12 (IP) isn't callee saved. */ # endif } @@ -2163,6 +2164,11 @@ static Bool summarise_context( /*OUT*/DiCfSI* si, si->cfa_how = CFIC_ARM_R11REL; si->cfa_off = ctxs->cfa_off; } + else + if (ctxs->cfa_is_regoff && ctxs->cfa_reg == 7/*??_REG*/) { + si->cfa_how = CFIC_ARM_R7REL; + si->cfa_off = ctxs->cfa_off; + } # endif else { why = 1; @@ -2257,6 +2263,9 @@ static Bool summarise_context( /*OUT*/DiCfSI* si, SUMMARISE_HOW(si->r11_how, si->r11_off, ctxs->reg[11/*FP_REG*/] ); + SUMMARISE_HOW(si->r7_how, si->r7_off, + ctxs->reg[7] ); + 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 diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c index 8046f1eac..52aec7937 100644 --- a/coregrind/m_debuginfo/storage.c +++ b/coregrind/m_debuginfo/storage.c @@ -141,6 +141,9 @@ void ML_(ppDiCfSI) ( XArray* /* of CfiExpr */ exprs, DiCfSI* si ) case CFIC_ARM_R11REL: VG_(printf)("let cfa=oldR11+%d", si->cfa_off); break; + case CFIC_ARM_R7REL: + VG_(printf)("let cfa=oldR7+%d", si->cfa_off); + break; case CFIC_EXPR: VG_(printf)("let cfa={"); ML_(ppCfiExpr)(exprs, si->cfa_off); @@ -166,6 +169,8 @@ void ML_(ppDiCfSI) ( XArray* /* of CfiExpr */ exprs, DiCfSI* si ) SHOW_HOW(si->r12_how, si->r12_off); VG_(printf)(" R11="); SHOW_HOW(si->r11_how, si->r11_off); + VG_(printf)(" R7="); + SHOW_HOW(si->r7_how, si->r7_off); # elif defined(VGA_ppc32) || defined(VGA_ppc64) # else # error "Unknown arch" diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c index 4a1b76584..731864ff2 100644 --- a/coregrind/m_libcassert.c +++ b/coregrind/m_libcassert.c @@ -116,13 +116,14 @@ } #elif defined(VGP_arm_linux) # define GET_STARTREGS(srP) \ - { UInt block[5]; \ + { UInt block[6]; \ __asm__ __volatile__( \ "str r15, [%0, #+0];" \ "str r14, [%0, #+4];" \ "str r13, [%0, #+8];" \ "str r12, [%0, #+12];" \ "str r11, [%0, #+16];" \ + "str r7, [%0, #+20];" \ : /* out */ \ : /* in */ "r"(&block[0]) \ : /* trash */ "memory" \ @@ -132,6 +133,7 @@ (srP)->misc.ARM.r14 = block[2]; \ (srP)->misc.ARM.r12 = block[3]; \ (srP)->misc.ARM.r11 = block[4]; \ + (srP)->misc.ARM.r7 = block[5]; \ } #else # error Unknown platform diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index 5f3bc927b..8dc3e17db 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -92,6 +92,8 @@ void VG_(get_UnwindStartRegs) ( /*OUT*/UnwindStartRegs* regs, = VG_(threads)[tid].arch.vex.guest_R12; regs->misc.ARM.r11 = VG_(threads)[tid].arch.vex.guest_R11; + regs->misc.ARM.r7 + = VG_(threads)[tid].arch.vex.guest_R7; # else # error "Unknown arch" # endif diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index 76c05df2c..a3b7690a5 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -378,6 +378,7 @@ typedef struct SigQueue { (srP)->misc.ARM.r14 = (uc)->uc_mcontext.arm_lr; \ (srP)->misc.ARM.r12 = (uc)->uc_mcontext.arm_ip; \ (srP)->misc.ARM.r11 = (uc)->uc_mcontext.arm_fp; \ + (srP)->misc.ARM.r7 = (uc)->uc_mcontext.arm_r7; \ } #elif defined(VGP_ppc32_aix5) diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index ad86b79d9..4896a9a1e 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -593,11 +593,12 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, vg_assert(sizeof(Addr) == sizeof(void*)); D3UnwindRegs uregs; - uregs.r15 = startRegs->r_pc; + uregs.r15 = startRegs->r_pc & 0xFFFFFFFE; uregs.r14 = startRegs->misc.ARM.r14; uregs.r13 = startRegs->r_sp; uregs.r12 = startRegs->misc.ARM.r12; uregs.r11 = startRegs->misc.ARM.r11; + uregs.r7 = startRegs->misc.ARM.r7; Addr fp_min = uregs.r13; /* Snaffle IPs from the client's stack into ips[0 .. max_n_ips-1], @@ -612,7 +613,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, fp_max -= sizeof(Addr); if (debug) - VG_(printf)("max_n_ips=%d fp_min=0x%lx fp_max_orig=0x%lx, " + VG_(printf)("\nmax_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, uregs.r15, uregs.r13); @@ -652,11 +653,11 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, if (VG_(use_CF_info)( &uregs, fp_min, fp_max )) { if (sps) sps[i] = uregs.r13; if (fps) fps[i] = 0; - ips[i++] = uregs.r15 -1; + ips[i++] = (uregs.r15 & 0xFFFFFFFE) - 1; if (debug) VG_(printf)("USING CFI: r15: 0x%lx, r13: 0x%lx\n", uregs.r15, uregs.r13); - uregs.r15 = uregs.r15 - 1; + uregs.r15 = (uregs.r15 & 0xFFFFFFFE) - 1; continue; } /* No luck. We have to give up. */ diff --git a/coregrind/pub_core_basics.h b/coregrind/pub_core_basics.h index fdfd733f6..35aba2f2b 100644 --- a/coregrind/pub_core_basics.h +++ b/coregrind/pub_core_basics.h @@ -103,6 +103,7 @@ typedef UInt r14; UInt r12; UInt r11; + UInt r7; } ARM; } misc; } diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h index 48ac9aa9c..facca244d 100644 --- a/coregrind/pub_core_debuginfo.h +++ b/coregrind/pub_core_debuginfo.h @@ -117,7 +117,7 @@ typedef D3UnwindRegs; #elif defined(VGA_arm) typedef - struct { Addr r15; Addr r14; Addr r13; Addr r12; Addr r11; } + struct { Addr r15; Addr r14; Addr r13; Addr r12; Addr r11; Addr r7; } D3UnwindRegs; #elif defined(VGA_ppc32) || defined(VGA_ppc64) typedef