LCOV - code coverage report
Current view: top level - tools/profiler/lul - LulDwarfSummariser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 94 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "LulDwarfSummariser.h"
       8             : 
       9             : #include "mozilla/Assertions.h"
      10             : 
      11             : // Set this to 1 for verbose logging
      12             : #define DEBUG_SUMMARISER 0
      13             : 
      14             : namespace lul {
      15             : 
      16             : // Do |s64|'s lowest 32 bits sign extend back to |s64| itself?
      17           0 : static inline bool fitsIn32Bits(int64 s64) {
      18           0 :   return s64 == ((s64 & 0xffffffff) ^ 0x80000000) - 0x80000000;
      19             : }
      20             : 
      21             : // Check a LExpr prefix expression, starting at pfxInstrs[start] up to
      22             : // the next PX_End instruction, to ensure that:
      23             : // * It only mentions registers that are tracked on this target
      24             : // * The start point is sane
      25             : // If the expression is ok, return NULL.  Else return a pointer
      26             : // a const char* holding a bit of text describing the problem.
      27             : static const char*
      28           0 : checkPfxExpr(const vector<PfxInstr>* pfxInstrs, int64_t start)
      29             : {
      30           0 :   size_t nInstrs = pfxInstrs->size();
      31           0 :   if (start < 0 || start >= (ssize_t)nInstrs) {
      32           0 :     return "bogus start point";
      33             :   }
      34             :   size_t i;
      35           0 :   for (i = start; i < nInstrs; i++) {
      36           0 :     PfxInstr pxi = (*pfxInstrs)[i];
      37           0 :     if (pxi.mOpcode == PX_End)
      38           0 :       break;
      39           0 :     if (pxi.mOpcode == PX_DwReg &&
      40           0 :         !registerIsTracked((DW_REG_NUMBER)pxi.mOperand)) {
      41           0 :       return "uses untracked reg";
      42             :     }
      43             :   }
      44           0 :   return nullptr; // success
      45             : }
      46             : 
      47             : 
      48           0 : Summariser::Summariser(SecMap* aSecMap, uintptr_t aTextBias,
      49           0 :                        void(*aLog)(const char*))
      50             :   : mSecMap(aSecMap)
      51             :   , mTextBias(aTextBias)
      52           0 :   , mLog(aLog)
      53             : {
      54           0 :   mCurrAddr = 0;
      55           0 :   mMax1Addr = 0; // Gives an empty range.
      56             : 
      57             :   // Initialise the running RuleSet to "haven't got a clue" status.
      58           0 :   new (&mCurrRules) RuleSet();
      59           0 : }
      60             : 
      61             : void
      62           0 : Summariser::Entry(uintptr_t aAddress, uintptr_t aLength)
      63             : {
      64           0 :   aAddress += mTextBias;
      65             :   if (DEBUG_SUMMARISER) {
      66             :     char buf[100];
      67             :     SprintfLiteral(buf,
      68             :                    "LUL Entry(%llx, %llu)\n",
      69             :                    (unsigned long long int)aAddress,
      70             :                    (unsigned long long int)aLength);
      71             :     mLog(buf);
      72             :   }
      73             :   // This throws away any previous summary, that is, assumes
      74             :   // that the previous summary, if any, has been properly finished
      75             :   // by a call to End().
      76           0 :   mCurrAddr = aAddress;
      77           0 :   mMax1Addr = aAddress + aLength;
      78           0 :   new (&mCurrRules) RuleSet();
      79           0 : }
      80             : 
      81             : void
      82           0 : Summariser::Rule(uintptr_t aAddress, int aNewReg,
      83             :                  LExprHow how, int16_t oldReg, int64_t offset)
      84             : {
      85           0 :   aAddress += mTextBias;
      86             :   if (DEBUG_SUMMARISER) {
      87             :     char buf[100];
      88             :     if (how == NODEREF || how == DEREF) {
      89             :       bool deref = how == DEREF;
      90             :       SprintfLiteral(buf,
      91             :                      "LUL  0x%llx  old-r%d = %sr%d + %lld%s\n",
      92             :                      (unsigned long long int)aAddress, aNewReg,
      93             :                      deref ? "*(" : "", (int)oldReg, (long long int)offset,
      94             :                      deref ? ")" : "");
      95             :     } else if (how == PFXEXPR) {
      96             :       SprintfLiteral(buf,
      97             :                      "LUL  0x%llx  old-r%d = pfx-expr-at %lld\n",
      98             :                      (unsigned long long int)aAddress, aNewReg,
      99             :                      (long long int)offset);
     100             :     } else {
     101             :       SprintfLiteral(buf,
     102             :                      "LUL  0x%llx  old-r%d = (invalid LExpr!)\n",
     103             :                      (unsigned long long int)aAddress, aNewReg);
     104             :     }
     105             :     mLog(buf);
     106             :   }
     107             : 
     108           0 :   if (mCurrAddr < aAddress) {
     109             :     // Flush the existing summary first.
     110           0 :     mCurrRules.mAddr = mCurrAddr;
     111           0 :     mCurrRules.mLen  = aAddress - mCurrAddr;
     112           0 :     mSecMap->AddRuleSet(&mCurrRules);
     113             :     if (DEBUG_SUMMARISER) {
     114             :       mLog("LUL  "); mCurrRules.Print(mLog);
     115             :       mLog("\n");
     116             :     }
     117           0 :     mCurrAddr = aAddress;
     118             :   }
     119             : 
     120             :   // If for some reason summarisation fails, either or both of these
     121             :   // become non-null and point at constant text describing the
     122             :   // problem.  Using two rather than just one avoids complications of
     123             :   // having to concatenate two strings to produce a complete error message.
     124           0 :   const char* reason1 = nullptr;
     125           0 :   const char* reason2 = nullptr;
     126             : 
     127             :   // |offset| needs to be a 32 bit value that sign extends to 64 bits
     128             :   // on a 64 bit target.  We will need to incorporate |offset| into
     129             :   // any LExpr made here.  So we may as well check it right now.
     130           0 :   if (!fitsIn32Bits(offset)) {
     131           0 :     reason1 = "offset not in signed 32-bit range";
     132           0 :     goto cant_summarise;
     133             :   }
     134             : 
     135             :   // FIXME: factor out common parts of the arch-dependent summarisers.
     136             : 
     137             : #if defined(GP_ARCH_arm)
     138             : 
     139             :   // ----------------- arm ----------------- //
     140             : 
     141             :   // Now, can we add the rule to our summary?  This depends on whether
     142             :   // the registers and the overall expression are representable.  This
     143             :   // is the heart of the summarisation process.
     144             :   switch (aNewReg) {
     145             : 
     146             :     case DW_REG_CFA:
     147             :       // This is a rule that defines the CFA.  The only forms we
     148             :       // choose to represent are: r7/11/12/13 + offset.  The offset
     149             :       // must fit into 32 bits since 'uintptr_t' is 32 bit on ARM,
     150             :       // hence there is no need to check it for overflow.
     151             :       if (how != NODEREF) {
     152             :         reason1 = "rule for DW_REG_CFA: invalid |how|";
     153             :         goto cant_summarise;
     154             :       }
     155             :       switch (oldReg) {
     156             :         case DW_REG_ARM_R7:  case DW_REG_ARM_R11:
     157             :         case DW_REG_ARM_R12: case DW_REG_ARM_R13:
     158             :           break;
     159             :         default:
     160             :           reason1 = "rule for DW_REG_CFA: invalid |oldReg|";
     161             :           goto cant_summarise;
     162             :       }
     163             :       mCurrRules.mCfaExpr = LExpr(how, oldReg, offset);
     164             :       break;
     165             : 
     166             :     case DW_REG_ARM_R7:  case DW_REG_ARM_R11: case DW_REG_ARM_R12:
     167             :     case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15: {
     168             :       // This is a new rule for R7, R11, R12, R13 (SP), R14 (LR) or
     169             :       // R15 (the return address).
     170             :       switch (how) {
     171             :         case NODEREF: case DEREF:
     172             :           // Check the old register is one we're tracking.
     173             :           if (!registerIsTracked((DW_REG_NUMBER)oldReg) &&
     174             :               oldReg != DW_REG_CFA) {
     175             :             reason1 = "rule for R7/11/12/13/14/15: uses untracked reg";
     176             :             goto cant_summarise;
     177             :           }
     178             :           break;
     179             :         case PFXEXPR: {
     180             :           // Check that the prefix expression only mentions tracked registers.
     181             :           const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs();
     182             :           reason2 = checkPfxExpr(pfxInstrs, offset);
     183             :           if (reason2) {
     184             :             reason1 = "rule for R7/11/12/13/14/15: ";
     185             :             goto cant_summarise;
     186             :           }
     187             :           break;
     188             :         }
     189             :         default:
     190             :           goto cant_summarise;
     191             :       }
     192             :       LExpr expr = LExpr(how, oldReg, offset);
     193             :       switch (aNewReg) {
     194             :         case DW_REG_ARM_R7:  mCurrRules.mR7expr  = expr; break;
     195             :         case DW_REG_ARM_R11: mCurrRules.mR11expr = expr; break;
     196             :         case DW_REG_ARM_R12: mCurrRules.mR12expr = expr; break;
     197             :         case DW_REG_ARM_R13: mCurrRules.mR13expr = expr; break;
     198             :         case DW_REG_ARM_R14: mCurrRules.mR14expr = expr; break;
     199             :         case DW_REG_ARM_R15: mCurrRules.mR15expr = expr; break;
     200             :         default: MOZ_ASSERT(0);
     201             :       }
     202             :       break;
     203             :     }
     204             : 
     205             :     default:
     206             :       // Leave |reason1| and |reason2| unset here.  This program point
     207             :       // is reached so often that it causes a flood of "Can't
     208             :       // summarise" messages.  In any case, we don't really care about
     209             :       // the fact that this summary would produce a new value for a
     210             :       // register that we're not tracking.  We do on the other hand
     211             :       // care if the summary's expression *uses* a register that we're
     212             :       // not tracking.  But in that case one of the above failures
     213             :       // should tell us which.
     214             :       goto cant_summarise;
     215             :   }
     216             : 
     217             :   // Mark callee-saved registers (r4 .. r11) as unchanged, if there is
     218             :   // no other information about them.  FIXME: do this just once, at
     219             :   // the point where the ruleset is committed.
     220             :   if (mCurrRules.mR7expr.mHow == UNKNOWN) {
     221             :     mCurrRules.mR7expr = LExpr(NODEREF, DW_REG_ARM_R7, 0);
     222             :   }
     223             :   if (mCurrRules.mR11expr.mHow == UNKNOWN) {
     224             :     mCurrRules.mR11expr = LExpr(NODEREF, DW_REG_ARM_R11, 0);
     225             :   }
     226             :   if (mCurrRules.mR12expr.mHow == UNKNOWN) {
     227             :     mCurrRules.mR12expr = LExpr(NODEREF, DW_REG_ARM_R12, 0);
     228             :   }
     229             : 
     230             :   // The old r13 (SP) value before the call is always the same as the
     231             :   // CFA.
     232             :   mCurrRules.mR13expr = LExpr(NODEREF, DW_REG_CFA, 0);
     233             : 
     234             :   // If there's no information about R15 (the return address), say
     235             :   // it's a copy of R14 (the link register).
     236             :   if (mCurrRules.mR15expr.mHow == UNKNOWN) {
     237             :     mCurrRules.mR15expr = LExpr(NODEREF, DW_REG_ARM_R14, 0);
     238             :   }
     239             : 
     240             : #elif defined(GP_ARCH_amd64) || defined(GP_ARCH_x86)
     241             : 
     242             :   // ---------------- x64/x86 ---------------- //
     243             : 
     244             :   // Now, can we add the rule to our summary?  This depends on whether
     245             :   // the registers and the overall expression are representable.  This
     246             :   // is the heart of the summarisation process.
     247           0 :   switch (aNewReg) {
     248             : 
     249             :     case DW_REG_CFA: {
     250             :       // This is a rule that defines the CFA.  The only forms we choose to
     251             :       // represent are: = SP+offset, = FP+offset, or =prefix-expr.
     252           0 :       switch (how) {
     253             :         case NODEREF:
     254           0 :           if (oldReg != DW_REG_INTEL_XSP && oldReg != DW_REG_INTEL_XBP) {
     255           0 :             reason1 = "rule for DW_REG_CFA: invalid |oldReg|";
     256           0 :             goto cant_summarise;
     257             :           }
     258           0 :           break;
     259             :         case DEREF:
     260           0 :           reason1 = "rule for DW_REG_CFA: invalid |how|";
     261           0 :           goto cant_summarise;
     262             :         case PFXEXPR: {
     263             :           // Check that the prefix expression only mentions tracked registers.
     264           0 :           const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs();
     265           0 :           reason2 = checkPfxExpr(pfxInstrs, offset);
     266           0 :           if (reason2) {
     267           0 :             reason1 = "rule for CFA: ";
     268           0 :             goto cant_summarise;
     269             :           }
     270           0 :           break;
     271             :         }
     272             :         default:
     273           0 :           goto cant_summarise;
     274             :       }
     275           0 :       mCurrRules.mCfaExpr = LExpr(how, oldReg, offset);
     276           0 :       break;
     277             :     }
     278             : 
     279             :     case DW_REG_INTEL_XSP: case DW_REG_INTEL_XBP: case DW_REG_INTEL_XIP: {
     280             :       // This is a new rule for XSP, XBP or XIP (the return address).
     281           0 :       switch (how) {
     282             :         case NODEREF: case DEREF:
     283             :           // Check the old register is one we're tracking.
     284           0 :           if (!registerIsTracked((DW_REG_NUMBER)oldReg) &&
     285             :               oldReg != DW_REG_CFA) {
     286           0 :             reason1 = "rule for XSP/XBP/XIP: uses untracked reg";
     287           0 :             goto cant_summarise;
     288             :           }
     289           0 :           break;
     290             :         case PFXEXPR: {
     291             :           // Check that the prefix expression only mentions tracked registers.
     292           0 :           const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs();
     293           0 :           reason2 = checkPfxExpr(pfxInstrs, offset);
     294           0 :           if (reason2) {
     295           0 :             reason1 = "rule for XSP/XBP/XIP: ";
     296           0 :             goto cant_summarise;
     297             :           }
     298           0 :           break;
     299             :         }
     300             :         default:
     301           0 :           goto cant_summarise;
     302             :       }
     303           0 :       LExpr expr = LExpr(how, oldReg, offset);
     304           0 :       switch (aNewReg) {
     305           0 :         case DW_REG_INTEL_XBP: mCurrRules.mXbpExpr = expr; break;
     306           0 :         case DW_REG_INTEL_XSP: mCurrRules.mXspExpr = expr; break;
     307           0 :         case DW_REG_INTEL_XIP: mCurrRules.mXipExpr = expr; break;
     308           0 :         default: MOZ_CRASH("impossible value for aNewReg");
     309             :       }
     310           0 :       break;
     311             :     }
     312             : 
     313             :     default:
     314             :       // Leave |reason1| and |reason2| unset here, for the reasons
     315             :       // explained in the analogous point in the ARM case just above.
     316           0 :       goto cant_summarise;
     317             : 
     318             :   }
     319             : 
     320             :   // On Intel, it seems the old SP value before the call is always the
     321             :   // same as the CFA.  Therefore, in the absence of any other way to
     322             :   // recover the SP, specify that the CFA should be copied.
     323           0 :   if (mCurrRules.mXspExpr.mHow == UNKNOWN) {
     324           0 :     mCurrRules.mXspExpr = LExpr(NODEREF, DW_REG_CFA, 0);
     325             :   }
     326             : 
     327             :   // Also, gcc says "Undef" for BP when it is unchanged.
     328           0 :   if (mCurrRules.mXbpExpr.mHow == UNKNOWN) {
     329           0 :     mCurrRules.mXbpExpr = LExpr(NODEREF, DW_REG_INTEL_XBP, 0);
     330             :   }
     331             : 
     332             : #else
     333             : 
     334             : # error "Unsupported arch"
     335             : #endif
     336             : 
     337           0 :   return;
     338             : 
     339             :  cant_summarise:
     340           0 :   if (reason1 || reason2) {
     341             :     char buf[200];
     342           0 :     SprintfLiteral(buf, "LUL  can't summarise: "
     343             :                         "SVMA=0x%llx: %s%s, expr=LExpr(%s,%u,%lld)\n",
     344           0 :                    (unsigned long long int)(aAddress - mTextBias),
     345             :                    reason1 ? reason1 : "", reason2 ? reason2 : "",
     346             :                    NameOf_LExprHow(how),
     347           0 :                    (unsigned int)oldReg, (long long int)offset);
     348           0 :     mLog(buf);
     349             :   }
     350             : }
     351             : 
     352             : uint32_t
     353           0 : Summariser::AddPfxInstr(PfxInstr pfxi)
     354             : {
     355           0 :   return mSecMap->AddPfxInstr(pfxi);
     356             : }
     357             : 
     358             : void
     359           0 : Summariser::End()
     360             : {
     361             :   if (DEBUG_SUMMARISER) {
     362             :     mLog("LUL End\n");
     363             :   }
     364           0 :   if (mCurrAddr < mMax1Addr) {
     365           0 :     mCurrRules.mAddr = mCurrAddr;
     366           0 :     mCurrRules.mLen  = mMax1Addr - mCurrAddr;
     367           0 :     mSecMap->AddRuleSet(&mCurrRules);
     368             :     if (DEBUG_SUMMARISER) {
     369             :       mLog("LUL  "); mCurrRules.Print(mLog);
     370             :       mLog("\n");
     371             :     }
     372             :   }
     373           0 : }
     374             : 
     375             : } // namespace lul

Generated by: LCOV version 1.13