tools/profiler/LulDwarfSummariser.cpp

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

mercurial