/src/mozilla-central/tools/profiler/lul/LulDwarfSummariser.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | #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 | 0 | } |
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 | | checkPfxExpr(const vector<PfxInstr>* pfxInstrs, int64_t start) |
29 | 0 | { |
30 | 0 | size_t nInstrs = pfxInstrs->size(); |
31 | 0 | if (start < 0 || start >= (ssize_t)nInstrs) { |
32 | 0 | return "bogus start point"; |
33 | 0 | } |
34 | 0 | 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 | 0 | } |
43 | 0 | } |
44 | 0 | return nullptr; // success |
45 | 0 | } |
46 | | |
47 | | |
48 | | Summariser::Summariser(SecMap* aSecMap, uintptr_t aTextBias, |
49 | | void(*aLog)(const char*)) |
50 | | : mSecMap(aSecMap) |
51 | | , mTextBias(aTextBias) |
52 | | , mLog(aLog) |
53 | 0 | { |
54 | 0 | mCurrAddr = 0; |
55 | 0 | mMax1Addr = 0; // Gives an empty range. |
56 | 0 |
|
57 | 0 | // Initialise the running RuleSet to "haven't got a clue" status. |
58 | 0 | new (&mCurrRules) RuleSet(); |
59 | 0 | } |
60 | | |
61 | | void |
62 | | Summariser::Entry(uintptr_t aAddress, uintptr_t aLength) |
63 | 0 | { |
64 | 0 | aAddress += mTextBias; |
65 | 0 | if (DEBUG_SUMMARISER) { |
66 | 0 | char buf[100]; |
67 | 0 | SprintfLiteral(buf, |
68 | 0 | "LUL Entry(%llx, %llu)\n", |
69 | 0 | (unsigned long long int)aAddress, |
70 | 0 | (unsigned long long int)aLength); |
71 | 0 | mLog(buf); |
72 | 0 | } |
73 | 0 | // This throws away any previous summary, that is, assumes |
74 | 0 | // that the previous summary, if any, has been properly finished |
75 | 0 | // 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 | | Summariser::Rule(uintptr_t aAddress, int aNewReg, |
83 | | LExprHow how, int16_t oldReg, int64_t offset) |
84 | 0 | { |
85 | 0 | aAddress += mTextBias; |
86 | 0 | if (DEBUG_SUMMARISER) { |
87 | 0 | char buf[100]; |
88 | 0 | if (how == NODEREF || how == DEREF) { |
89 | 0 | bool deref = how == DEREF; |
90 | 0 | SprintfLiteral(buf, |
91 | 0 | "LUL 0x%llx old-r%d = %sr%d + %lld%s\n", |
92 | 0 | (unsigned long long int)aAddress, aNewReg, |
93 | 0 | deref ? "*(" : "", (int)oldReg, (long long int)offset, |
94 | 0 | deref ? ")" : ""); |
95 | 0 | } else if (how == PFXEXPR) { |
96 | 0 | SprintfLiteral(buf, |
97 | 0 | "LUL 0x%llx old-r%d = pfx-expr-at %lld\n", |
98 | 0 | (unsigned long long int)aAddress, aNewReg, |
99 | 0 | (long long int)offset); |
100 | 0 | } else { |
101 | 0 | SprintfLiteral(buf, |
102 | 0 | "LUL 0x%llx old-r%d = (invalid LExpr!)\n", |
103 | 0 | (unsigned long long int)aAddress, aNewReg); |
104 | 0 | } |
105 | 0 | mLog(buf); |
106 | 0 | } |
107 | 0 |
|
108 | 0 | if (mCurrAddr < aAddress) { |
109 | 0 | // Flush the existing summary first. |
110 | 0 | mCurrRules.mAddr = mCurrAddr; |
111 | 0 | mCurrRules.mLen = aAddress - mCurrAddr; |
112 | 0 | mSecMap->AddRuleSet(&mCurrRules); |
113 | 0 | if (DEBUG_SUMMARISER) { |
114 | 0 | mLog("LUL "); mCurrRules.Print(mLog); |
115 | 0 | mLog("\n"); |
116 | 0 | } |
117 | 0 | mCurrAddr = aAddress; |
118 | 0 | } |
119 | 0 |
|
120 | 0 | // If for some reason summarisation fails, either or both of these |
121 | 0 | // become non-null and point at constant text describing the |
122 | 0 | // problem. Using two rather than just one avoids complications of |
123 | 0 | // having to concatenate two strings to produce a complete error message. |
124 | 0 | const char* reason1 = nullptr; |
125 | 0 | const char* reason2 = nullptr; |
126 | 0 |
|
127 | 0 | // |offset| needs to be a 32 bit value that sign extends to 64 bits |
128 | 0 | // on a 64 bit target. We will need to incorporate |offset| into |
129 | 0 | // 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 | 0 | } |
134 | 0 | |
135 | 0 | // FIXME: factor out common parts of the arch-dependent summarisers. |
136 | 0 | |
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_arm64) |
241 | | |
242 | | // ----------------- arm64 ----------------- // |
243 | | |
244 | | switch (aNewReg) { |
245 | | case DW_REG_CFA: |
246 | | if (how != NODEREF) { |
247 | | reason1 = "rule for DW_REG_CFA: invalid |how|"; |
248 | | goto cant_summarise; |
249 | | } |
250 | | switch (oldReg) { |
251 | | case DW_REG_AARCH64_X29: |
252 | | case DW_REG_AARCH64_SP: |
253 | | break; |
254 | | default: |
255 | | reason1 = "rule for DW_REG_CFA: invalid |oldReg|"; |
256 | | goto cant_summarise; |
257 | | } |
258 | | mCurrRules.mCfaExpr = LExpr(how, oldReg, offset); |
259 | | break; |
260 | | |
261 | | case DW_REG_AARCH64_X29: |
262 | | case DW_REG_AARCH64_X30: |
263 | | case DW_REG_AARCH64_SP: { |
264 | | switch (how) { |
265 | | case NODEREF: |
266 | | case DEREF: |
267 | | // Check the old register is one we're tracking. |
268 | | if (!registerIsTracked((DW_REG_NUMBER)oldReg) && |
269 | | oldReg != DW_REG_CFA) { |
270 | | reason1 = "rule for X29/X30/SP: uses untracked reg"; |
271 | | goto cant_summarise; |
272 | | } |
273 | | break; |
274 | | case PFXEXPR: { |
275 | | // Check that the prefix expression only mentions tracked registers. |
276 | | const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs(); |
277 | | reason2 = checkPfxExpr(pfxInstrs, offset); |
278 | | if (reason2) { |
279 | | reason1 = "rule for X29/X30/SP: "; |
280 | | goto cant_summarise; |
281 | | } |
282 | | break; |
283 | | } |
284 | | default: |
285 | | goto cant_summarise; |
286 | | } |
287 | | LExpr expr = LExpr(how, oldReg, offset); |
288 | | switch (aNewReg) { |
289 | | case DW_REG_AARCH64_X29: mCurrRules.mX29expr = expr; break; |
290 | | case DW_REG_AARCH64_X30: mCurrRules.mX30expr = expr; break; |
291 | | case DW_REG_AARCH64_SP: mCurrRules.mSPexpr = expr; break; |
292 | | default: MOZ_ASSERT(0); |
293 | | } |
294 | | break; |
295 | | } |
296 | | default: |
297 | | // Leave |reason1| and |reason2| unset here, for the reasons explained |
298 | | // in the analogous point |
299 | | goto cant_summarise; |
300 | | } |
301 | | |
302 | | if (mCurrRules.mX29expr.mHow == UNKNOWN) { |
303 | | mCurrRules.mX29expr = LExpr(NODEREF, DW_REG_AARCH64_X29, 0); |
304 | | } |
305 | | if (mCurrRules.mX30expr.mHow == UNKNOWN) { |
306 | | mCurrRules.mX30expr = LExpr(NODEREF, DW_REG_AARCH64_X30, 0); |
307 | | } |
308 | | // On aarch64, it seems the old SP value before the call is always the |
309 | | // same as the CFA. Therefore, in the absence of any other way to |
310 | | // recover the SP, specify that the CFA should be copied. |
311 | | if (mCurrRules.mSPexpr.mHow == UNKNOWN) { |
312 | | mCurrRules.mSPexpr = LExpr(NODEREF, DW_REG_CFA, 0); |
313 | | } |
314 | | #elif defined(GP_ARCH_amd64) || defined(GP_ARCH_x86) |
315 | | |
316 | 0 | // ---------------- x64/x86 ---------------- // |
317 | 0 | |
318 | 0 | // Now, can we add the rule to our summary? This depends on whether |
319 | 0 | // the registers and the overall expression are representable. This |
320 | 0 | // is the heart of the summarisation process. |
321 | 0 | switch (aNewReg) { |
322 | 0 |
|
323 | 0 | case DW_REG_CFA: { |
324 | 0 | // This is a rule that defines the CFA. The only forms we choose to |
325 | 0 | // represent are: = SP+offset, = FP+offset, or =prefix-expr. |
326 | 0 | switch (how) { |
327 | 0 | case NODEREF: |
328 | 0 | if (oldReg != DW_REG_INTEL_XSP && oldReg != DW_REG_INTEL_XBP) { |
329 | 0 | reason1 = "rule for DW_REG_CFA: invalid |oldReg|"; |
330 | 0 | goto cant_summarise; |
331 | 0 | } |
332 | 0 | break; |
333 | 0 | case DEREF: |
334 | 0 | reason1 = "rule for DW_REG_CFA: invalid |how|"; |
335 | 0 | goto cant_summarise; |
336 | 0 | case PFXEXPR: { |
337 | 0 | // Check that the prefix expression only mentions tracked registers. |
338 | 0 | const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs(); |
339 | 0 | reason2 = checkPfxExpr(pfxInstrs, offset); |
340 | 0 | if (reason2) { |
341 | 0 | reason1 = "rule for CFA: "; |
342 | 0 | goto cant_summarise; |
343 | 0 | } |
344 | 0 | break; |
345 | 0 | } |
346 | 0 | default: |
347 | 0 | goto cant_summarise; |
348 | 0 | } |
349 | 0 | mCurrRules.mCfaExpr = LExpr(how, oldReg, offset); |
350 | 0 | break; |
351 | 0 | } |
352 | 0 |
|
353 | 0 | case DW_REG_INTEL_XSP: case DW_REG_INTEL_XBP: case DW_REG_INTEL_XIP: { |
354 | 0 | // This is a new rule for XSP, XBP or XIP (the return address). |
355 | 0 | switch (how) { |
356 | 0 | case NODEREF: case DEREF: |
357 | 0 | // Check the old register is one we're tracking. |
358 | 0 | if (!registerIsTracked((DW_REG_NUMBER)oldReg) && |
359 | 0 | oldReg != DW_REG_CFA) { |
360 | 0 | reason1 = "rule for XSP/XBP/XIP: uses untracked reg"; |
361 | 0 | goto cant_summarise; |
362 | 0 | } |
363 | 0 | break; |
364 | 0 | case PFXEXPR: { |
365 | 0 | // Check that the prefix expression only mentions tracked registers. |
366 | 0 | const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs(); |
367 | 0 | reason2 = checkPfxExpr(pfxInstrs, offset); |
368 | 0 | if (reason2) { |
369 | 0 | reason1 = "rule for XSP/XBP/XIP: "; |
370 | 0 | goto cant_summarise; |
371 | 0 | } |
372 | 0 | break; |
373 | 0 | } |
374 | 0 | default: |
375 | 0 | goto cant_summarise; |
376 | 0 | } |
377 | 0 | LExpr expr = LExpr(how, oldReg, offset); |
378 | 0 | switch (aNewReg) { |
379 | 0 | case DW_REG_INTEL_XBP: mCurrRules.mXbpExpr = expr; break; |
380 | 0 | case DW_REG_INTEL_XSP: mCurrRules.mXspExpr = expr; break; |
381 | 0 | case DW_REG_INTEL_XIP: mCurrRules.mXipExpr = expr; break; |
382 | 0 | default: MOZ_CRASH("impossible value for aNewReg"); |
383 | 0 | } |
384 | 0 | break; |
385 | 0 | } |
386 | 0 |
|
387 | 0 | default: |
388 | 0 | // Leave |reason1| and |reason2| unset here, for the reasons |
389 | 0 | // explained in the analogous point in the ARM case just above. |
390 | 0 | goto cant_summarise; |
391 | 0 | |
392 | 0 | } |
393 | 0 | |
394 | 0 | // On Intel, it seems the old SP value before the call is always the |
395 | 0 | // same as the CFA. Therefore, in the absence of any other way to |
396 | 0 | // recover the SP, specify that the CFA should be copied. |
397 | 0 | if (mCurrRules.mXspExpr.mHow == UNKNOWN) { |
398 | 0 | mCurrRules.mXspExpr = LExpr(NODEREF, DW_REG_CFA, 0); |
399 | 0 | } |
400 | 0 |
|
401 | 0 | // Also, gcc says "Undef" for BP when it is unchanged. |
402 | 0 | if (mCurrRules.mXbpExpr.mHow == UNKNOWN) { |
403 | 0 | mCurrRules.mXbpExpr = LExpr(NODEREF, DW_REG_INTEL_XBP, 0); |
404 | 0 | } |
405 | 0 |
|
406 | | #elif defined(GP_ARCH_mips64) |
407 | | // ---------------- mips ---------------- // |
408 | | // |
409 | | // Now, can we add the rule to our summary? This depends on whether |
410 | | // the registers and the overall expression are representable. This |
411 | | // is the heart of the summarisation process. |
412 | | switch (aNewReg) { |
413 | | |
414 | | case DW_REG_CFA: |
415 | | // This is a rule that defines the CFA. The only forms we can |
416 | | // represent are: = SP+offset or = FP+offset. |
417 | | if (how != NODEREF) { |
418 | | reason1 = "rule for DW_REG_CFA: invalid |how|"; |
419 | | goto cant_summarise; |
420 | | } |
421 | | if (oldReg != DW_REG_MIPS_SP && oldReg != DW_REG_MIPS_FP) { |
422 | | reason1 = "rule for DW_REG_CFA: invalid |oldReg|"; |
423 | | goto cant_summarise; |
424 | | } |
425 | | mCurrRules.mCfaExpr = LExpr(how, oldReg, offset); |
426 | | break; |
427 | | |
428 | | case DW_REG_MIPS_SP: case DW_REG_MIPS_FP: case DW_REG_MIPS_PC: { |
429 | | // This is a new rule for SP, FP or PC (the return address). |
430 | | switch (how) { |
431 | | case NODEREF: case DEREF: |
432 | | // Check the old register is one we're tracking. |
433 | | if (!registerIsTracked((DW_REG_NUMBER)oldReg) && |
434 | | oldReg != DW_REG_CFA) { |
435 | | reason1 = "rule for SP/FP/PC: uses untracked reg"; |
436 | | goto cant_summarise; |
437 | | } |
438 | | break; |
439 | | case PFXEXPR: { |
440 | | // Check that the prefix expression only mentions tracked registers. |
441 | | const vector<PfxInstr>* pfxInstrs = mSecMap->GetPfxInstrs(); |
442 | | reason2 = checkPfxExpr(pfxInstrs, offset); |
443 | | if (reason2) { |
444 | | reason1 = "rule for SP/FP/PC: "; |
445 | | goto cant_summarise; |
446 | | } |
447 | | break; |
448 | | } |
449 | | default: |
450 | | goto cant_summarise; |
451 | | } |
452 | | LExpr expr = LExpr(how, oldReg, offset); |
453 | | switch (aNewReg) { |
454 | | case DW_REG_MIPS_FP: mCurrRules.mFPexpr = expr; break; |
455 | | case DW_REG_MIPS_SP: mCurrRules.mSPexpr = expr; break; |
456 | | case DW_REG_MIPS_PC: mCurrRules.mPCexpr = expr; break; |
457 | | default: MOZ_CRASH("impossible value for aNewReg"); |
458 | | } |
459 | | break; |
460 | | } |
461 | | default: |
462 | | // Leave |reason1| and |reason2| unset here, for the reasons |
463 | | // explained in the analogous point in the ARM case just above. |
464 | | goto cant_summarise; |
465 | | } |
466 | | |
467 | | // On MIPS, it seems the old SP value before the call is always the |
468 | | // same as the CFA. Therefore, in the absence of any other way to |
469 | | // recover the SP, specify that the CFA should be copied. |
470 | | if (mCurrRules.mSPexpr.mHow == UNKNOWN) { |
471 | | mCurrRules.mSPexpr = LExpr(NODEREF, DW_REG_CFA, 0); |
472 | | } |
473 | | |
474 | | // Also, gcc says "Undef" for FP when it is unchanged. |
475 | | if (mCurrRules.mFPexpr.mHow == UNKNOWN) { |
476 | | mCurrRules.mFPexpr = LExpr(NODEREF, DW_REG_MIPS_FP, 0); |
477 | | } |
478 | | |
479 | | #else |
480 | | |
481 | | # error "Unsupported arch" |
482 | | #endif |
483 | |
|
484 | 0 | return; |
485 | 0 |
|
486 | 0 | cant_summarise: |
487 | 0 | if (reason1 || reason2) { |
488 | 0 | char buf[200]; |
489 | 0 | SprintfLiteral(buf, "LUL can't summarise: " |
490 | 0 | "SVMA=0x%llx: %s%s, expr=LExpr(%s,%u,%lld)\n", |
491 | 0 | (unsigned long long int)(aAddress - mTextBias), |
492 | 0 | reason1 ? reason1 : "", reason2 ? reason2 : "", |
493 | 0 | NameOf_LExprHow(how), |
494 | 0 | (unsigned int)oldReg, (long long int)offset); |
495 | 0 | mLog(buf); |
496 | 0 | } |
497 | 0 | } |
498 | | |
499 | | uint32_t |
500 | | Summariser::AddPfxInstr(PfxInstr pfxi) |
501 | 0 | { |
502 | 0 | return mSecMap->AddPfxInstr(pfxi); |
503 | 0 | } |
504 | | |
505 | | void |
506 | | Summariser::End() |
507 | 0 | { |
508 | 0 | if (DEBUG_SUMMARISER) { |
509 | 0 | mLog("LUL End\n"); |
510 | 0 | } |
511 | 0 | if (mCurrAddr < mMax1Addr) { |
512 | 0 | mCurrRules.mAddr = mCurrAddr; |
513 | 0 | mCurrRules.mLen = mMax1Addr - mCurrAddr; |
514 | 0 | mSecMap->AddRuleSet(&mCurrRules); |
515 | 0 | if (DEBUG_SUMMARISER) { |
516 | 0 | mLog("LUL "); mCurrRules.Print(mLog); |
517 | 0 | mLog("\n"); |
518 | 0 | } |
519 | 0 | } |
520 | 0 | } |
521 | | |
522 | | } // namespace lul |