]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Make the Dwarf3 CFI stack unwinding machinery work on arm-linux
authorJulian Seward <jseward@acm.org>
Fri, 1 Jan 2010 18:46:41 +0000 (18:46 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 1 Jan 2010 18:46:41 +0000 (18:46 +0000)
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
coregrind/m_debuginfo/debuginfo.c
coregrind/m_debuginfo/priv_storage.h
coregrind/m_debuginfo/readdwarf.c
coregrind/m_debuginfo/readelf.c
coregrind/m_debuginfo/storage.c
coregrind/m_stacktrace.c
coregrind/pub_core_debuginfo.h

index ce14f4904d44db86b5d2118cac649cbf4916bb02..4585894c945828099da6218e1779662963dc4642 100644 (file)
@@ -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");
index 106d3987daa76a6de57d392b0540a4ecbdfe33e6..3a8f2fe0a5d1229d5b242ff50a76654a29d6356c 100644 (file)
@@ -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;
 }
 
index b790001c38c06a23b39833b22822001718e9fb60..a0d4e6c936a546cb77494d5e7a2f9115f2d42835 100644 (file)
@@ -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;
 
index 98a72436b905071b62d212260d3296db05170411..560da28fa4e5ffd518b62d60cbe3899dec2917c4 100644 (file)
@@ -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:
index 52d1b698218902546e036cf965fc4ab81c9235c9..e6cb41a31dd2d0c4c7879bebfd346ab188fa448a 100644 (file)
@@ -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) {
index 935ee7989c283327c0f67946afc289da00fcfe50..cbb0f1067ba3aa1624ddb4bfebf31de43a73f204 100644 (file)
@@ -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);
    }
 }
index 0b738138efca4652438c6078b3b84af054c6e569..153f50c866020d0dba74c399429d1a7f12dfa151 100644 (file)
@@ -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. */
index b947af1e3d09439f271ce7d15f7f5f7f0486f289..f77bf02fb5ac882ff4468df62f5663c85195983c 100644 (file)
@@ -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,