tools/profiler/LulDwarfSummariser.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "LulDwarfSummariser.h"
michael@0 8
michael@0 9 #include "mozilla/Assertions.h"
michael@0 10
michael@0 11 // Set this to 1 for verbose logging
michael@0 12 #define DEBUG_SUMMARISER 0
michael@0 13
michael@0 14 namespace lul {
michael@0 15
michael@0 16 Summariser::Summariser(SecMap* aSecMap, uintptr_t aTextBias,
michael@0 17 void(*aLog)(const char*))
michael@0 18 : mSecMap(aSecMap)
michael@0 19 , mTextBias(aTextBias)
michael@0 20 , mLog(aLog)
michael@0 21 {
michael@0 22 mCurrAddr = 0;
michael@0 23 mMax1Addr = 0; // Gives an empty range.
michael@0 24
michael@0 25 // Initialise the running RuleSet to "haven't got a clue" status.
michael@0 26 new (&mCurrRules) RuleSet();
michael@0 27 }
michael@0 28
michael@0 29 void
michael@0 30 Summariser::Entry(uintptr_t aAddress, uintptr_t aLength)
michael@0 31 {
michael@0 32 aAddress += mTextBias;
michael@0 33 if (DEBUG_SUMMARISER) {
michael@0 34 char buf[100];
michael@0 35 snprintf(buf, sizeof(buf), "LUL Entry(%llx, %llu)\n",
michael@0 36 (unsigned long long int)aAddress,
michael@0 37 (unsigned long long int)aLength);
michael@0 38 buf[sizeof(buf)-1] = 0;
michael@0 39 mLog(buf);
michael@0 40 }
michael@0 41 // This throws away any previous summary, that is, assumes
michael@0 42 // that the previous summary, if any, has been properly finished
michael@0 43 // by a call to End().
michael@0 44 mCurrAddr = aAddress;
michael@0 45 mMax1Addr = aAddress + aLength;
michael@0 46 new (&mCurrRules) RuleSet();
michael@0 47 }
michael@0 48
michael@0 49 void
michael@0 50 Summariser::Rule(uintptr_t aAddress,
michael@0 51 int aNewReg, int aOldReg, intptr_t aOffset, bool aDeref)
michael@0 52 {
michael@0 53 aAddress += mTextBias;
michael@0 54 if (DEBUG_SUMMARISER) {
michael@0 55 char buf[100];
michael@0 56 snprintf(buf, sizeof(buf),
michael@0 57 "LUL 0x%llx old-r%d = %sr%d + %ld%s\n",
michael@0 58 (unsigned long long int)aAddress, aNewReg,
michael@0 59 aDeref ? "*(" : "", aOldReg, (long)aOffset, aDeref ? ")" : "");
michael@0 60 buf[sizeof(buf)-1] = 0;
michael@0 61 mLog(buf);
michael@0 62 }
michael@0 63 if (mCurrAddr < aAddress) {
michael@0 64 // Flush the existing summary first.
michael@0 65 mCurrRules.mAddr = mCurrAddr;
michael@0 66 mCurrRules.mLen = aAddress - mCurrAddr;
michael@0 67 mSecMap->AddRuleSet(&mCurrRules);
michael@0 68 if (DEBUG_SUMMARISER) {
michael@0 69 mLog("LUL "); mCurrRules.Print(mLog);
michael@0 70 mLog("\n");
michael@0 71 }
michael@0 72 mCurrAddr = aAddress;
michael@0 73 }
michael@0 74
michael@0 75 // FIXME: factor out common parts of the arch-dependent summarisers.
michael@0 76
michael@0 77 #if defined(LUL_ARCH_arm)
michael@0 78
michael@0 79 // ----------------- arm ----------------- //
michael@0 80
michael@0 81 // Now, can we add the rule to our summary? This depends on whether
michael@0 82 // the registers and the overall expression are representable. This
michael@0 83 // is the heart of the summarisation process.
michael@0 84 switch (aNewReg) {
michael@0 85
michael@0 86 case DW_REG_CFA:
michael@0 87 // This is a rule that defines the CFA. The only forms we
michael@0 88 // choose to represent are: r7/11/12/13 + offset. The offset
michael@0 89 // must fit into 32 bits since 'uintptr_t' is 32 bit on ARM,
michael@0 90 // hence there is no need to check it for overflow.
michael@0 91 if (aDeref) {
michael@0 92 goto cant_summarise;
michael@0 93 }
michael@0 94 switch (aOldReg) {
michael@0 95 case DW_REG_ARM_R7: case DW_REG_ARM_R11:
michael@0 96 case DW_REG_ARM_R12: case DW_REG_ARM_R13:
michael@0 97 break;
michael@0 98 default:
michael@0 99 goto cant_summarise;
michael@0 100 }
michael@0 101 mCurrRules.mCfaExpr = LExpr(LExpr::NODEREF, aOldReg, aOffset);
michael@0 102 break;
michael@0 103
michael@0 104 case DW_REG_ARM_R7: case DW_REG_ARM_R11: case DW_REG_ARM_R12:
michael@0 105 case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15: {
michael@0 106 // Check the aOldReg is valid.
michael@0 107 switch (aOldReg) {
michael@0 108 case DW_REG_CFA:
michael@0 109 case DW_REG_ARM_R7: case DW_REG_ARM_R11: case DW_REG_ARM_R12:
michael@0 110 case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15:
michael@0 111 break;
michael@0 112 default:
michael@0 113 goto cant_summarise;
michael@0 114 }
michael@0 115 // This is a new rule for one of r{7,11,12,13,14,15} and has a
michael@0 116 // representable offset. In particular the new value of r15 is
michael@0 117 // going to be the return address.
michael@0 118 LExpr expr = LExpr(aDeref ? LExpr::DEREF : LExpr::NODEREF,
michael@0 119 aOldReg, aOffset);
michael@0 120 switch (aNewReg) {
michael@0 121 case DW_REG_ARM_R7: mCurrRules.mR7expr = expr; break;
michael@0 122 case DW_REG_ARM_R11: mCurrRules.mR11expr = expr; break;
michael@0 123 case DW_REG_ARM_R12: mCurrRules.mR12expr = expr; break;
michael@0 124 case DW_REG_ARM_R13: mCurrRules.mR13expr = expr; break;
michael@0 125 case DW_REG_ARM_R14: mCurrRules.mR14expr = expr; break;
michael@0 126 case DW_REG_ARM_R15: mCurrRules.mR15expr = expr; break;
michael@0 127 default: MOZ_ASSERT(0);
michael@0 128 }
michael@0 129 break;
michael@0 130 }
michael@0 131
michael@0 132 default:
michael@0 133 goto cant_summarise;
michael@0 134 }
michael@0 135
michael@0 136 // Mark callee-saved registers (r4 .. r11) as unchanged, if there is
michael@0 137 // no other information about them. FIXME: do this just once, at
michael@0 138 // the point where the ruleset is committed.
michael@0 139 if (mCurrRules.mR7expr.mHow == LExpr::UNKNOWN) {
michael@0 140 mCurrRules.mR7expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R7, 0);
michael@0 141 }
michael@0 142 if (mCurrRules.mR11expr.mHow == LExpr::UNKNOWN) {
michael@0 143 mCurrRules.mR11expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R11, 0);
michael@0 144 }
michael@0 145 if (mCurrRules.mR12expr.mHow == LExpr::UNKNOWN) {
michael@0 146 mCurrRules.mR12expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R12, 0);
michael@0 147 }
michael@0 148
michael@0 149 // The old r13 (SP) value before the call is always the same as the
michael@0 150 // CFA.
michael@0 151 mCurrRules.mR13expr = LExpr(LExpr::NODEREF, DW_REG_CFA, 0);
michael@0 152
michael@0 153 // If there's no information about R15 (the return address), say
michael@0 154 // it's a copy of R14 (the link register).
michael@0 155 if (mCurrRules.mR15expr.mHow == LExpr::UNKNOWN) {
michael@0 156 mCurrRules.mR15expr = LExpr(LExpr::NODEREF, DW_REG_ARM_R14, 0);
michael@0 157 }
michael@0 158
michael@0 159 #elif defined(LUL_ARCH_x64) || defined(LUL_ARCH_x86)
michael@0 160
michael@0 161 // ---------------- x64/x86 ---------------- //
michael@0 162
michael@0 163 // Now, can we add the rule to our summary? This depends on whether
michael@0 164 // the registers and the overall expression are representable. This
michael@0 165 // is the heart of the summarisation process. In the 64 bit case
michael@0 166 // we need to check that aOffset will fit into an int32_t. In the
michael@0 167 // 32 bit case it is expected that the compiler will fold out the
michael@0 168 // test since it always succeeds.
michael@0 169 if (aNewReg == DW_REG_CFA) {
michael@0 170 // This is a rule that defines the CFA. The only forms we can
michael@0 171 // represent are: = SP+offset or = FP+offset.
michael@0 172 if (!aDeref && aOffset == (intptr_t)(int32_t)aOffset &&
michael@0 173 (aOldReg == DW_REG_INTEL_XSP || aOldReg == DW_REG_INTEL_XBP)) {
michael@0 174 mCurrRules.mCfaExpr = LExpr(LExpr::NODEREF, aOldReg, aOffset);
michael@0 175 } else {
michael@0 176 goto cant_summarise;
michael@0 177 }
michael@0 178 }
michael@0 179 else
michael@0 180 if ((aNewReg == DW_REG_INTEL_XSP ||
michael@0 181 aNewReg == DW_REG_INTEL_XBP || aNewReg == DW_REG_INTEL_XIP) &&
michael@0 182 (aOldReg == DW_REG_CFA ||
michael@0 183 aOldReg == DW_REG_INTEL_XSP ||
michael@0 184 aOldReg == DW_REG_INTEL_XBP || aOldReg == DW_REG_INTEL_XIP) &&
michael@0 185 aOffset == (intptr_t)(int32_t)aOffset) {
michael@0 186 // This is a new rule for SP, BP or the return address
michael@0 187 // respectively, and has a representable offset.
michael@0 188 LExpr expr = LExpr(aDeref ? LExpr::DEREF : LExpr::NODEREF,
michael@0 189 aOldReg, aOffset);
michael@0 190 switch (aNewReg) {
michael@0 191 case DW_REG_INTEL_XBP: mCurrRules.mXbpExpr = expr; break;
michael@0 192 case DW_REG_INTEL_XSP: mCurrRules.mXspExpr = expr; break;
michael@0 193 case DW_REG_INTEL_XIP: mCurrRules.mXipExpr = expr; break;
michael@0 194 default: MOZ_CRASH("impossible value for aNewReg");
michael@0 195 }
michael@0 196 }
michael@0 197 else {
michael@0 198 goto cant_summarise;
michael@0 199 }
michael@0 200
michael@0 201 // On Intel, it seems the old SP value before the call is always the
michael@0 202 // same as the CFA. Therefore, in the absence of any other way to
michael@0 203 // recover the SP, specify that the CFA should be copied.
michael@0 204 if (mCurrRules.mXspExpr.mHow == LExpr::UNKNOWN) {
michael@0 205 mCurrRules.mXspExpr = LExpr(LExpr::NODEREF, DW_REG_CFA, 0);
michael@0 206 }
michael@0 207
michael@0 208 // Also, gcc says "Undef" for BP when it is unchanged.
michael@0 209 if (mCurrRules.mXbpExpr.mHow == LExpr::UNKNOWN) {
michael@0 210 mCurrRules.mXbpExpr = LExpr(LExpr::NODEREF, DW_REG_INTEL_XBP, 0);
michael@0 211 }
michael@0 212
michael@0 213 #else
michael@0 214
michael@0 215 # error "Unsupported arch"
michael@0 216 #endif
michael@0 217
michael@0 218 return;
michael@0 219 cant_summarise:
michael@0 220 if (0) {
michael@0 221 mLog("LUL can't summarise\n");
michael@0 222 }
michael@0 223 }
michael@0 224
michael@0 225 void
michael@0 226 Summariser::End()
michael@0 227 {
michael@0 228 if (DEBUG_SUMMARISER) {
michael@0 229 mLog("LUL End\n");
michael@0 230 }
michael@0 231 if (mCurrAddr < mMax1Addr) {
michael@0 232 mCurrRules.mAddr = mCurrAddr;
michael@0 233 mCurrRules.mLen = mMax1Addr - mCurrAddr;
michael@0 234 mSecMap->AddRuleSet(&mCurrRules);
michael@0 235 if (DEBUG_SUMMARISER) {
michael@0 236 mLog("LUL "); mCurrRules.Print(mLog);
michael@0 237 mLog("\n");
michael@0 238 }
michael@0 239 }
michael@0 240 }
michael@0 241
michael@0 242 } // namespace lul

mercurial