Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/tools/profiler/lul/LulMainInt.h
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
#ifndef LulMainInt_h
8
#define LulMainInt_h
9
10
#include "PlatformMacros.h"
11
#include "LulMain.h" // for TaggedUWord
12
13
#include <vector>
14
15
#include "mozilla/Assertions.h"
16
17
// This file is provides internal interface inside LUL.  If you are an
18
// end-user of LUL, do not include it in your code.  The end-user
19
// interface is in LulMain.h.
20
21
22
namespace lul {
23
24
using std::vector;
25
26
////////////////////////////////////////////////////////////////
27
// DW_REG_ constants                                          //
28
////////////////////////////////////////////////////////////////
29
30
// These are the Dwarf CFI register numbers, as (presumably) defined
31
// in the ELF ABI supplements for each architecture.
32
33
enum DW_REG_NUMBER {
34
  // No real register has this number.  It's convenient to be able to
35
  // treat the CFA (Canonical Frame Address) as "just another
36
  // register", though.
37
  DW_REG_CFA = -1,
38
#if defined(GP_ARCH_arm)
39
  // ARM registers
40
  DW_REG_ARM_R7  = 7,
41
  DW_REG_ARM_R11 = 11,
42
  DW_REG_ARM_R12 = 12,
43
  DW_REG_ARM_R13 = 13,
44
  DW_REG_ARM_R14 = 14,
45
  DW_REG_ARM_R15 = 15,
46
#elif defined(GP_ARCH_arm64)
47
  // aarch64 registers
48
  DW_REG_AARCH64_X29 = 29,
49
  DW_REG_AARCH64_X30 = 30,
50
  DW_REG_AARCH64_SP  = 31,
51
#elif defined(GP_ARCH_amd64)
52
  // Because the X86 (32 bit) and AMD64 (64 bit) summarisers are
53
  // combined, a merged set of register constants is needed.
54
  DW_REG_INTEL_XBP = 6,
55
  DW_REG_INTEL_XSP = 7,
56
  DW_REG_INTEL_XIP = 16,
57
#elif defined(GP_ARCH_x86)
58
  DW_REG_INTEL_XBP = 5,
59
  DW_REG_INTEL_XSP = 4,
60
  DW_REG_INTEL_XIP = 8,
61
#elif defined(GP_ARCH_mips64)
62
  DW_REG_MIPS_SP = 29,
63
  DW_REG_MIPS_FP = 30,
64
  DW_REG_MIPS_PC = 34,
65
#else
66
# error "Unknown arch"
67
#endif
68
};
69
70
71
////////////////////////////////////////////////////////////////
72
// PfxExpr                                                    //
73
////////////////////////////////////////////////////////////////
74
75
enum PfxExprOp {
76
  //             meaning of mOperand     effect on stack
77
  PX_Start,   // bool start-with-CFA?    start, with CFA on stack, or not
78
  PX_End,     // none                    stop; result is at top of stack
79
  PX_SImm32,  // int32                   push signed int32
80
  PX_DwReg,   // DW_REG_NUMBER           push value of the specified reg
81
  PX_Deref,   // none                    pop X ; push *X
82
  PX_Add,     // none                    pop X ; pop Y ; push Y + X
83
  PX_Sub,     // none                    pop X ; pop Y ; push Y - X
84
  PX_And,     // none                    pop X ; pop Y ; push Y & X
85
  PX_Or,      // none                    pop X ; pop Y ; push Y | X
86
  PX_CmpGES,  // none                    pop X ; pop Y ; push (Y >=s X) ? 1 : 0
87
  PX_Shl      // none                    pop X ; pop Y ; push Y << X
88
};
89
90
struct PfxInstr {
91
  PfxInstr(PfxExprOp opcode, int32_t operand)
92
    : mOpcode(opcode)
93
    , mOperand(operand)
94
0
  {}
95
  explicit PfxInstr(PfxExprOp opcode)
96
    : mOpcode(opcode)
97
    , mOperand(0)
98
0
  {}
99
0
  bool operator==(const PfxInstr& other) const {
100
0
    return mOpcode == other.mOpcode && mOperand == other.mOperand;
101
0
  }
102
  PfxExprOp mOpcode;
103
  int32_t   mOperand;
104
};
105
106
static_assert(sizeof(PfxInstr) <= 8, "PfxInstr size changed unexpectedly");
107
108
// Evaluate the prefix expression whose PfxInstrs start at aPfxInstrs[start].
109
// In the case of any mishap (stack over/underflow, running off the end of
110
// the instruction vector, obviously malformed sequences),
111
// return an invalid TaggedUWord.
112
// RUNS IN NO-MALLOC CONTEXT
113
TaggedUWord EvaluatePfxExpr(int32_t start,
114
                            const UnwindRegs* aOldRegs,
115
                            TaggedUWord aCFA, const StackImage* aStackImg,
116
                            const vector<PfxInstr>& aPfxInstrs);
117
118
119
////////////////////////////////////////////////////////////////
120
// LExpr                                                      //
121
////////////////////////////////////////////////////////////////
122
123
// An expression -- very primitive.  Denotes either "register +
124
// offset", a dereferenced version of the same, or a reference to a
125
// prefix expression stored elsewhere.  So as to allow convenient
126
// handling of Dwarf-derived unwind info, the register may also denote
127
// the CFA.  A large number of these need to be stored, so we ensure
128
// it fits into 8 bytes.  See comment below on RuleSet to see how
129
// expressions fit into the bigger picture.
130
131
enum LExprHow {
132
  UNKNOWN=0, // This LExpr denotes no value.
133
  NODEREF,   // Value is  (mReg + mOffset).
134
  DEREF,     // Value is *(mReg + mOffset).
135
  PFXEXPR    // Value is EvaluatePfxExpr(secMap->mPfxInstrs[mOffset])
136
};
137
138
0
inline static const char* NameOf_LExprHow(LExprHow how) {
139
0
  switch (how) {
140
0
    case UNKNOWN: return "UNKNOWN";
141
0
    case NODEREF: return "NODEREF";
142
0
    case DEREF:   return "DEREF";
143
0
    case PFXEXPR: return "PFXEXPR";
144
0
    default:      return "LExpr-??";
145
0
  }
146
0
}
147
148
149
struct LExpr {
150
  // Denotes an expression with no value.
151
  LExpr()
152
    : mHow(UNKNOWN)
153
    , mReg(0)
154
    , mOffset(0)
155
0
  {}
156
157
  // Denotes any expressible expression.
158
  LExpr(LExprHow how, int16_t reg, int32_t offset)
159
    : mHow(how)
160
    , mReg(reg)
161
    , mOffset(offset)
162
0
  {
163
0
    switch (how) {
164
0
      case UNKNOWN: MOZ_ASSERT(reg == 0 && offset == 0); break;
165
0
      case NODEREF: break;
166
0
      case DEREF:   break;
167
0
      case PFXEXPR: MOZ_ASSERT(reg == 0 && offset >= 0); break;
168
0
      default:      MOZ_ASSERT(0, "LExpr::LExpr: invalid how");
169
0
    }
170
0
  }
171
172
  // Change the offset for an expression that references memory.
173
  LExpr add_delta(long delta)
174
0
  {
175
0
    MOZ_ASSERT(mHow == NODEREF);
176
0
    // If this is a non-debug build and the above assertion would have
177
0
    // failed, at least return LExpr() so that the machinery that uses
178
0
    // the resulting expression fails in a repeatable way.
179
0
    return (mHow == NODEREF) ? LExpr(mHow, mReg, mOffset+delta)
180
0
                             : LExpr(); // Gone bad
181
0
  }
182
183
  // Dereference an expression that denotes a memory address.
184
  LExpr deref()
185
0
  {
186
0
    MOZ_ASSERT(mHow == NODEREF);
187
0
    // Same rationale as for add_delta().
188
0
    return (mHow == NODEREF) ? LExpr(DEREF, mReg, mOffset)
189
0
                             : LExpr(); // Gone bad
190
0
  }
191
192
  // Print a rule for recovery of |aNewReg| whose recovered value
193
  // is this LExpr.
194
  string ShowRule(const char* aNewReg) const;
195
196
  // Evaluate this expression, producing a TaggedUWord.  |aOldRegs|
197
  // holds register values that may be referred to by the expression.
198
  // |aCFA| holds the CFA value, if any, that applies.  |aStackImg|
199
  // contains a chuck of stack that will be consulted if the expression
200
  // references memory.  |aPfxInstrs| holds the vector of PfxInstrs
201
  // that will be consulted if this is a PFXEXPR.
202
  // RUNS IN NO-MALLOC CONTEXT
203
  TaggedUWord EvaluateExpr(const UnwindRegs* aOldRegs,
204
                           TaggedUWord aCFA, const StackImage* aStackImg,
205
                           const vector<PfxInstr>* aPfxInstrs) const;
206
207
  // Representation of expressions.  If |mReg| is DW_REG_CFA (-1) then
208
  // it denotes the CFA.  All other allowed values for |mReg| are
209
  // nonnegative and are DW_REG_ values.
210
  LExprHow mHow:8;
211
  int16_t  mReg;    // A DW_REG_ value
212
  int32_t  mOffset; // 32-bit signed offset should be more than enough.
213
};
214
215
static_assert(sizeof(LExpr) <= 8, "LExpr size changed unexpectedly");
216
217
218
////////////////////////////////////////////////////////////////
219
// RuleSet                                                    //
220
////////////////////////////////////////////////////////////////
221
222
// This is platform-dependent.  For some address range, describes how
223
// to recover the CFA and then how to recover the registers for the
224
// previous frame.
225
//
226
// The set of LExprs contained in a given RuleSet describe a DAG which
227
// says how to compute the caller's registers ("new registers") from
228
// the callee's registers ("old registers").  The DAG can contain a
229
// single internal node, which is the value of the CFA for the callee.
230
// It would be possible to construct a DAG that omits the CFA, but
231
// including it makes the summarisers simpler, and the Dwarf CFI spec
232
// has the CFA as a central concept.
233
//
234
// For this to make sense, |mCfaExpr| can't have
235
// |mReg| == DW_REG_CFA since we have no previous value for the CFA.
236
// All of the other |Expr| fields can -- and usually do -- specify
237
// |mReg| == DW_REG_CFA.
238
//
239
// With that in place, the unwind algorithm proceeds as follows.
240
//
241
// (0) Initially: we have values for the old registers, and a memory
242
//     image.
243
//
244
// (1) Compute the CFA by evaluating |mCfaExpr|.  Add the computed
245
//     value to the set of "old registers".
246
//
247
// (2) Compute values for the registers by evaluating all of the other
248
//     |Expr| fields in the RuleSet.  These can depend on both the old
249
//     register values and the just-computed CFA.
250
//
251
// If we are unwinding without computing a CFA, perhaps because the
252
// RuleSets are derived from EXIDX instead of Dwarf, then
253
// |mCfaExpr.mHow| will be LExpr::UNKNOWN, so the computed value will
254
// be invalid -- that is, TaggedUWord() -- and so any attempt to use
255
// that will result in the same value.  But that's OK because the
256
// RuleSet would make no sense if depended on the CFA but specified no
257
// way to compute it.
258
//
259
// A RuleSet is not allowed to cover zero address range.  Having zero
260
// length would break binary searching in SecMaps and PriMaps.
261
262
class RuleSet {
263
public:
264
  RuleSet();
265
  void   Print(void(*aLog)(const char*)) const;
266
267
  // Find the LExpr* for a given DW_REG_ value in this class.
268
  LExpr* ExprForRegno(DW_REG_NUMBER aRegno);
269
270
  uintptr_t mAddr;
271
  uintptr_t mLen;
272
  // How to compute the CFA.
273
  LExpr  mCfaExpr;
274
  // How to compute caller register values.  These may reference the
275
  // value defined by |mCfaExpr|.
276
#if defined(GP_ARCH_amd64) || defined(GP_ARCH_x86)
277
  LExpr  mXipExpr; // return address
278
  LExpr  mXspExpr;
279
  LExpr  mXbpExpr;
280
#elif defined(GP_ARCH_arm)
281
  LExpr  mR15expr; // return address
282
  LExpr  mR14expr;
283
  LExpr  mR13expr;
284
  LExpr  mR12expr;
285
  LExpr  mR11expr;
286
  LExpr  mR7expr;
287
#elif defined(GP_ARCH_arm64)
288
  LExpr  mX29expr; // frame pointer register
289
  LExpr  mX30expr; // link register
290
  LExpr  mSPexpr;
291
#elif defined(GP_ARCH_mips64)
292
  LExpr  mPCexpr;
293
  LExpr  mFPexpr;
294
  LExpr  mSPexpr;
295
#else
296
#   error "Unknown arch"
297
#endif
298
};
299
300
// Returns |true| for Dwarf register numbers which are members
301
// of the set of registers that LUL unwinds on this target.
302
0
static inline bool registerIsTracked(DW_REG_NUMBER reg) {
303
0
  switch (reg) {
304
0
#   if defined(GP_ARCH_amd64) || defined(GP_ARCH_x86)
305
0
    case DW_REG_INTEL_XBP: case DW_REG_INTEL_XSP: case DW_REG_INTEL_XIP:
306
0
      return true;
307
#   elif defined(GP_ARCH_arm)
308
    case DW_REG_ARM_R7:  case DW_REG_ARM_R11: case DW_REG_ARM_R12:
309
    case DW_REG_ARM_R13: case DW_REG_ARM_R14: case DW_REG_ARM_R15:
310
      return true;
311
#   elif defined(GP_ARCH_arm64)
312
    case DW_REG_AARCH64_X29:  case DW_REG_AARCH64_X30: case DW_REG_AARCH64_SP:
313
      return true;
314
#elif defined(GP_ARCH_mips64)
315
    case DW_REG_MIPS_FP:  case DW_REG_MIPS_SP: case DW_REG_MIPS_PC:
316
      return true;
317
#   else
318
#     error "Unknown arch"
319
#   endif
320
0
    default:
321
0
      return false;
322
0
  }
323
0
}
Unexecuted instantiation: Unified_cpp_tools_profiler1.cpp:lul::registerIsTracked(lul::DW_REG_NUMBER)
Unexecuted instantiation: Unified_cpp_tests_gtest0.cpp:lul::registerIsTracked(lul::DW_REG_NUMBER)
324
325
326
////////////////////////////////////////////////////////////////
327
// SecMap                                                     //
328
////////////////////////////////////////////////////////////////
329
330
// A SecMap may have zero address range, temporarily, whilst RuleSets
331
// are being added to it.  But adding a zero-range SecMap to a PriMap
332
// will make it impossible to maintain the total order of the PriMap
333
// entries, and so that can't be allowed to happen.
334
335
class SecMap {
336
public:
337
  // These summarise the contained mRuleSets, in that they give
338
  // exactly the lowest and highest addresses that any of the entries
339
  // in this SecMap cover.  Hence invariants:
340
  //
341
  // mRuleSets is nonempty
342
  //    <=> mSummaryMinAddr <= mSummaryMaxAddr
343
  //        && mSummaryMinAddr == mRuleSets[0].mAddr
344
  //        && mSummaryMaxAddr == mRuleSets[#rulesets-1].mAddr
345
  //                              + mRuleSets[#rulesets-1].mLen - 1;
346
  //
347
  // This requires that no RuleSet has zero length.
348
  //
349
  // mRuleSets is empty
350
  //    <=> mSummaryMinAddr > mSummaryMaxAddr
351
  //
352
  // This doesn't constrain mSummaryMinAddr and mSummaryMaxAddr uniquely,
353
  // so let's use mSummaryMinAddr == 1 and mSummaryMaxAddr == 0 to denote
354
  // this case.
355
356
  explicit SecMap(void(*aLog)(const char*));
357
  ~SecMap();
358
359
  // Binary search mRuleSets to find one that brackets |ia|, or nullptr
360
  // if none is found.  It's not allowable to do this until PrepareRuleSets
361
  // has been called first.
362
  RuleSet* FindRuleSet(uintptr_t ia);
363
364
  // Add a RuleSet to the collection.  The rule is copied in.  Calling
365
  // this makes the map non-searchable.
366
  void AddRuleSet(const RuleSet* rs);
367
368
  // Add a PfxInstr to the vector of such instrs, and return the index
369
  // in the vector.  Calling this makes the map non-searchable.
370
  uint32_t AddPfxInstr(PfxInstr pfxi);
371
372
  // Returns the entire vector of PfxInstrs.
373
0
  const vector<PfxInstr>* GetPfxInstrs() { return &mPfxInstrs; }
374
375
  // Prepare the map for searching.  Also, remove any rules for code
376
  // address ranges which don't fall inside [start, +len).  |len| may
377
  // not be zero.
378
  void PrepareRuleSets(uintptr_t start, size_t len);
379
380
  bool IsEmpty();
381
382
0
  size_t Size() { return mRuleSets.size(); }
383
384
  size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
385
386
  // The min and max addresses of the addresses in the contained
387
  // RuleSets.  See comment above for invariants.
388
  uintptr_t mSummaryMinAddr;
389
  uintptr_t mSummaryMaxAddr;
390
391
private:
392
  // False whilst adding entries; true once it is safe to call FindRuleSet.
393
  // Transition (false->true) is caused by calling PrepareRuleSets().
394
  bool mUsable;
395
396
  // A vector of RuleSets, sorted, nonoverlapping (post Prepare()).
397
  vector<RuleSet> mRuleSets;
398
399
  // A vector of PfxInstrs, which are referred to by the RuleSets.
400
  // These are provided as a representation of Dwarf expressions
401
  // (DW_CFA_val_expression, DW_CFA_expression, DW_CFA_def_cfa_expression),
402
  // are relatively expensive to evaluate, and and are therefore
403
  // expected to be used only occasionally.
404
  //
405
  // The vector holds a bunch of separate PfxInstr programs, each one
406
  // starting with a PX_Start and terminated by a PX_End, all
407
  // concatenated together.  When a RuleSet can't recover a value
408
  // using a self-contained LExpr, it uses a PFXEXPR whose mOffset is
409
  // the index in this vector of start of the necessary PfxInstr program.
410
  vector<PfxInstr> mPfxInstrs;
411
412
  // A logging sink, for debugging.
413
  void (*mLog)(const char*);
414
};
415
416
} // namespace lul
417
418
#endif // ndef LulMainInt_h