1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/profiler/LulDwarfSummariser.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,242 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "LulDwarfSummariser.h" 1.11 + 1.12 +#include "mozilla/Assertions.h" 1.13 + 1.14 +// Set this to 1 for verbose logging 1.15 +#define DEBUG_SUMMARISER 0 1.16 + 1.17 +namespace lul { 1.18 + 1.19 +Summariser::Summariser(SecMap* aSecMap, uintptr_t aTextBias, 1.20 + void(*aLog)(const char*)) 1.21 + : mSecMap(aSecMap) 1.22 + , mTextBias(aTextBias) 1.23 + , mLog(aLog) 1.24 +{ 1.25 + mCurrAddr = 0; 1.26 + mMax1Addr = 0; // Gives an empty range. 1.27 + 1.28 + // Initialise the running RuleSet to "haven't got a clue" status. 1.29 + new (&mCurrRules) RuleSet(); 1.30 +} 1.31 + 1.32 +void 1.33 +Summariser::Entry(uintptr_t aAddress, uintptr_t aLength) 1.34 +{ 1.35 + aAddress += mTextBias; 1.36 + if (DEBUG_SUMMARISER) { 1.37 + char buf[100]; 1.38 + snprintf(buf, sizeof(buf), "LUL Entry(%llx, %llu)\n", 1.39 + (unsigned long long int)aAddress, 1.40 + (unsigned long long int)aLength); 1.41 + buf[sizeof(buf)-1] = 0; 1.42 + mLog(buf); 1.43 + } 1.44 + // This throws away any previous summary, that is, assumes 1.45 + // that the previous summary, if any, has been properly finished 1.46 + // by a call to End(). 1.47 + mCurrAddr = aAddress; 1.48 + mMax1Addr = aAddress + aLength; 1.49 + new (&mCurrRules) RuleSet(); 1.50 +} 1.51 + 1.52 +void 1.53 +Summariser::Rule(uintptr_t aAddress, 1.54 + int aNewReg, int aOldReg, intptr_t aOffset, bool aDeref) 1.55 +{ 1.56 + aAddress += mTextBias; 1.57 + if (DEBUG_SUMMARISER) { 1.58 + char buf[100]; 1.59 + snprintf(buf, sizeof(buf), 1.60 + "LUL 0x%llx old-r%d = %sr%d + %ld%s\n", 1.61 + (unsigned long long int)aAddress, aNewReg, 1.62 + aDeref ? "*(" : "", aOldReg, (long)aOffset, aDeref ? ")" : ""); 1.63 + buf[sizeof(buf)-1] = 0; 1.64 + mLog(buf); 1.65 + } 1.66 + if (mCurrAddr < aAddress) { 1.67 + // Flush the existing summary first. 1.68 + mCurrRules.mAddr = mCurrAddr; 1.69 + mCurrRules.mLen = aAddress - mCurrAddr; 1.70 + mSecMap->AddRuleSet(&mCurrRules); 1.71 + if (DEBUG_SUMMARISER) { 1.72 + mLog("LUL "); mCurrRules.Print(mLog); 1.73 + mLog("\n"); 1.74 + } 1.75 + mCurrAddr = aAddress; 1.76 + } 1.77 + 1.78 + // FIXME: factor out common parts of the arch-dependent summarisers. 1.79 + 1.80 +#if defined(LUL_ARCH_arm) 1.81 + 1.82 + // ----------------- arm ----------------- // 1.83 + 1.84 + // Now, can we add the rule to our summary? This depends on whether 1.85 + // the registers and the overall expression are representable. This 1.86 + // is the heart of the summarisation process. 1.87 + switch (aNewReg) { 1.88 + 1.89 + case DW_REG_CFA: 1.90 + // This is a rule that defines the CFA. The only forms we 1.91 + // choose to represent are: r7/11/12/13 + offset. The offset 1.92 + // must fit into 32 bits since 'uintptr_t' is 32 bit on ARM, 1.93 + // hence there is no need to check it for overflow. 1.94 + if (aDeref) { 1.95 + goto cant_summarise; 1.96 + } 1.97 + switch (aOldReg) { 1.98 + case DW_REG_ARM_R7: case DW_REG_ARM_R11: 1.99 + case DW_REG_ARM_R12: case DW_REG_ARM_R13: 1.100 + break; 1.101 + default: 1.102 + goto cant_summarise; 1.103 + } 1.104 + mCurrRules.mCfaExpr = LExpr(LExpr::NODEREF, aOldReg, aOffset); 1.105 + break; 1.106 + 1.107 + case DW_REG_ARM_R7: case DW_REG_ARM_R11: case DW_REG_ARM_R12: 1.108 + case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15: { 1.109 + // Check the aOldReg is valid. 1.110 + switch (aOldReg) { 1.111 + case DW_REG_CFA: 1.112 + case DW_REG_ARM_R7: case DW_REG_ARM_R11: case DW_REG_ARM_R12: 1.113 + case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15: 1.114 + break; 1.115 + default: 1.116 + goto cant_summarise; 1.117 + } 1.118 + // This is a new rule for one of r{7,11,12,13,14,15} and has a 1.119 + // representable offset. In particular the new value of r15 is 1.120 + // going to be the return address. 1.121 + LExpr expr = LExpr(aDeref ? LExpr::DEREF : LExpr::NODEREF, 1.122 + aOldReg, aOffset); 1.123 + switch (aNewReg) { 1.124 + case DW_REG_ARM_R7: mCurrRules.mR7expr = expr; break; 1.125 + case DW_REG_ARM_R11: mCurrRules.mR11expr = expr; break; 1.126 + case DW_REG_ARM_R12: mCurrRules.mR12expr = expr; break; 1.127 + case DW_REG_ARM_R13: mCurrRules.mR13expr = expr; break; 1.128 + case DW_REG_ARM_R14: mCurrRules.mR14expr = expr; break; 1.129 + case DW_REG_ARM_R15: mCurrRules.mR15expr = expr; break; 1.130 + default: MOZ_ASSERT(0); 1.131 + } 1.132 + break; 1.133 + } 1.134 + 1.135 + default: 1.136 + goto cant_summarise; 1.137 + } 1.138 + 1.139 + // Mark callee-saved registers (r4 .. r11) as unchanged, if there is 1.140 + // no other information about them. FIXME: do this just once, at 1.141 + // the point where the ruleset is committed. 1.142 + if (mCurrRules.mR7expr.mHow == LExpr::UNKNOWN) { 1.143 + mCurrRules.mR7expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R7, 0); 1.144 + } 1.145 + if (mCurrRules.mR11expr.mHow == LExpr::UNKNOWN) { 1.146 + mCurrRules.mR11expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R11, 0); 1.147 + } 1.148 + if (mCurrRules.mR12expr.mHow == LExpr::UNKNOWN) { 1.149 + mCurrRules.mR12expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R12, 0); 1.150 + } 1.151 + 1.152 + // The old r13 (SP) value before the call is always the same as the 1.153 + // CFA. 1.154 + mCurrRules.mR13expr = LExpr(LExpr::NODEREF, DW_REG_CFA, 0); 1.155 + 1.156 + // If there's no information about R15 (the return address), say 1.157 + // it's a copy of R14 (the link register). 1.158 + if (mCurrRules.mR15expr.mHow == LExpr::UNKNOWN) { 1.159 + mCurrRules.mR15expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R14, 0); 1.160 + } 1.161 + 1.162 +#elif defined(LUL_ARCH_x64) || defined(LUL_ARCH_x86) 1.163 + 1.164 + // ---------------- x64/x86 ---------------- // 1.165 + 1.166 + // Now, can we add the rule to our summary? This depends on whether 1.167 + // the registers and the overall expression are representable. This 1.168 + // is the heart of the summarisation process. In the 64 bit case 1.169 + // we need to check that aOffset will fit into an int32_t. In the 1.170 + // 32 bit case it is expected that the compiler will fold out the 1.171 + // test since it always succeeds. 1.172 + if (aNewReg == DW_REG_CFA) { 1.173 + // This is a rule that defines the CFA. The only forms we can 1.174 + // represent are: = SP+offset or = FP+offset. 1.175 + if (!aDeref && aOffset == (intptr_t)(int32_t)aOffset && 1.176 + (aOldReg == DW_REG_INTEL_XSP || aOldReg == DW_REG_INTEL_XBP)) { 1.177 + mCurrRules.mCfaExpr = LExpr(LExpr::NODEREF, aOldReg, aOffset); 1.178 + } else { 1.179 + goto cant_summarise; 1.180 + } 1.181 + } 1.182 + else 1.183 + if ((aNewReg == DW_REG_INTEL_XSP || 1.184 + aNewReg == DW_REG_INTEL_XBP || aNewReg == DW_REG_INTEL_XIP) && 1.185 + (aOldReg == DW_REG_CFA || 1.186 + aOldReg == DW_REG_INTEL_XSP || 1.187 + aOldReg == DW_REG_INTEL_XBP || aOldReg == DW_REG_INTEL_XIP) && 1.188 + aOffset == (intptr_t)(int32_t)aOffset) { 1.189 + // This is a new rule for SP, BP or the return address 1.190 + // respectively, and has a representable offset. 1.191 + LExpr expr = LExpr(aDeref ? LExpr::DEREF : LExpr::NODEREF, 1.192 + aOldReg, aOffset); 1.193 + switch (aNewReg) { 1.194 + case DW_REG_INTEL_XBP: mCurrRules.mXbpExpr = expr; break; 1.195 + case DW_REG_INTEL_XSP: mCurrRules.mXspExpr = expr; break; 1.196 + case DW_REG_INTEL_XIP: mCurrRules.mXipExpr = expr; break; 1.197 + default: MOZ_CRASH("impossible value for aNewReg"); 1.198 + } 1.199 + } 1.200 + else { 1.201 + goto cant_summarise; 1.202 + } 1.203 + 1.204 + // On Intel, it seems the old SP value before the call is always the 1.205 + // same as the CFA. Therefore, in the absence of any other way to 1.206 + // recover the SP, specify that the CFA should be copied. 1.207 + if (mCurrRules.mXspExpr.mHow == LExpr::UNKNOWN) { 1.208 + mCurrRules.mXspExpr = LExpr(LExpr::NODEREF, DW_REG_CFA, 0); 1.209 + } 1.210 + 1.211 + // Also, gcc says "Undef" for BP when it is unchanged. 1.212 + if (mCurrRules.mXbpExpr.mHow == LExpr::UNKNOWN) { 1.213 + mCurrRules.mXbpExpr = LExpr(LExpr::NODEREF, DW_REG_INTEL_XBP, 0); 1.214 + } 1.215 + 1.216 +#else 1.217 + 1.218 +# error "Unsupported arch" 1.219 +#endif 1.220 + 1.221 + return; 1.222 + cant_summarise: 1.223 + if (0) { 1.224 + mLog("LUL can't summarise\n"); 1.225 + } 1.226 +} 1.227 + 1.228 +void 1.229 +Summariser::End() 1.230 +{ 1.231 + if (DEBUG_SUMMARISER) { 1.232 + mLog("LUL End\n"); 1.233 + } 1.234 + if (mCurrAddr < mMax1Addr) { 1.235 + mCurrRules.mAddr = mCurrAddr; 1.236 + mCurrRules.mLen = mMax1Addr - mCurrAddr; 1.237 + mSecMap->AddRuleSet(&mCurrRules); 1.238 + if (DEBUG_SUMMARISER) { 1.239 + mLog("LUL "); mCurrRules.Print(mLog); 1.240 + mLog("\n"); 1.241 + } 1.242 + } 1.243 +} 1.244 + 1.245 +} // namespace lul