Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/tools/profiler/lul/LulMain.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 LulMain_h
8
#define LulMain_h
9
10
#include "PlatformMacros.h"
11
#include "mozilla/Atomics.h"
12
#include "mozilla/MemoryReporting.h"
13
14
// LUL: A Lightweight Unwind Library.
15
// This file provides the end-user (external) interface for LUL.
16
17
// Some comments about naming in the implementation.  These are safe
18
// to ignore if you are merely using LUL, but are important if you
19
// hack on its internals.
20
//
21
// Debuginfo readers in general have tended to use the word "address"
22
// to mean several different things.  This sometimes makes them
23
// difficult to understand and maintain.  LUL tries hard to avoid
24
// using the word "address" and instead uses the following more
25
// precise terms:
26
//
27
// * SVMA ("Stated Virtual Memory Address"): this is an address of a
28
//   symbol (etc) as it is stated in the symbol table, or other
29
//   metadata, of an object.  Such values are typically small and
30
//   start from zero or thereabouts, unless the object has been
31
//   prelinked.
32
//
33
// * AVMA ("Actual Virtual Memory Address"): this is the address of a
34
//   symbol (etc) in a running process, that is, once the associated
35
//   object has been mapped into a process.  Such values are typically
36
//   much larger than SVMAs, since objects can get mapped arbitrarily
37
//   far along the address space.
38
//
39
// * "Bias": the difference between AVMA and SVMA for a given symbol
40
//   (specifically, AVMA - SVMA).  The bias is always an integral
41
//   number of pages.  Once we know the bias for a given object's
42
//   text section (for example), we can compute the AVMAs of all of
43
//   its text symbols by adding the bias to their SVMAs.
44
//
45
// * "Image address": typically, to read debuginfo from an object we
46
//   will temporarily mmap in the file so as to read symbol tables
47
//   etc.  Addresses in this temporary mapping are called "Image
48
//   addresses".  Note that the temporary mapping is entirely
49
//   unrelated to the mappings of the file that the dynamic linker
50
//   must perform merely in order to get the program to run.  Hence
51
//   image addresses are unrelated to either SVMAs or AVMAs.
52
53
54
namespace lul {
55
56
// A machine word plus validity tag.
57
class TaggedUWord {
58
public:
59
  // RUNS IN NO-MALLOC CONTEXT
60
  // Construct a valid one.
61
  explicit TaggedUWord(uintptr_t w)
62
    : mValue(w)
63
    , mValid(true)
64
0
  {}
65
66
  // RUNS IN NO-MALLOC CONTEXT
67
  // Construct an invalid one.
68
  TaggedUWord()
69
    : mValue(0)
70
    , mValid(false)
71
0
  {}
72
73
  // RUNS IN NO-MALLOC CONTEXT
74
0
  TaggedUWord operator+(TaggedUWord rhs) const {
75
0
    return (Valid() && rhs.Valid()) ? TaggedUWord(Value() + rhs.Value())
76
0
                                    : TaggedUWord();
77
0
  }
78
79
  // RUNS IN NO-MALLOC CONTEXT
80
0
  TaggedUWord operator-(TaggedUWord rhs) const {
81
0
    return (Valid() && rhs.Valid()) ? TaggedUWord(Value() - rhs.Value())
82
0
                                    : TaggedUWord();
83
0
  }
84
85
  // RUNS IN NO-MALLOC CONTEXT
86
0
  TaggedUWord operator&(TaggedUWord rhs) const {
87
0
    return (Valid() && rhs.Valid()) ? TaggedUWord(Value() & rhs.Value())
88
0
                                    : TaggedUWord();
89
0
  }
90
91
  // RUNS IN NO-MALLOC CONTEXT
92
0
  TaggedUWord operator|(TaggedUWord rhs) const {
93
0
    return (Valid() && rhs.Valid()) ? TaggedUWord(Value() | rhs.Value())
94
0
                                    : TaggedUWord();
95
0
  }
96
97
  // RUNS IN NO-MALLOC CONTEXT
98
0
  TaggedUWord CmpGEs(TaggedUWord rhs) const {
99
0
    if (Valid() && rhs.Valid()) {
100
0
      intptr_t s1 = (intptr_t)Value();
101
0
      intptr_t s2 = (intptr_t)rhs.Value();
102
0
      return TaggedUWord(s1 >= s2 ? 1 : 0);
103
0
    }
104
0
    return TaggedUWord();
105
0
  }
106
107
  // RUNS IN NO-MALLOC CONTEXT
108
0
  TaggedUWord operator<<(TaggedUWord rhs) const {
109
0
    if (Valid() && rhs.Valid()) {
110
0
      uintptr_t shift = rhs.Value();
111
0
      if (shift < 8 * sizeof(uintptr_t))
112
0
        return TaggedUWord(Value() << shift);
113
0
    }
114
0
    return TaggedUWord();
115
0
  }
116
117
  // RUNS IN NO-MALLOC CONTEXT
118
  // Is equal?  Note: non-validity on either side gives non-equality.
119
0
  bool operator==(TaggedUWord other) const {
120
0
    return (mValid && other.Valid()) ? (mValue == other.Value()) : false;
121
0
  }
122
123
  // RUNS IN NO-MALLOC CONTEXT
124
  // Is it word-aligned?
125
0
  bool IsAligned() const {
126
0
    return mValid && (mValue & (sizeof(uintptr_t)-1)) == 0;
127
0
  }
128
129
  // RUNS IN NO-MALLOC CONTEXT
130
0
  uintptr_t Value() const { return mValue; }
131
132
  // RUNS IN NO-MALLOC CONTEXT
133
0
  bool      Valid() const { return mValid; }
134
135
private:
136
  uintptr_t mValue;
137
  bool mValid;
138
};
139
140
141
// The registers, with validity tags, that will be unwound.
142
143
struct UnwindRegs {
144
#if defined(GP_ARCH_arm)
145
  TaggedUWord r7;
146
  TaggedUWord r11;
147
  TaggedUWord r12;
148
  TaggedUWord r13;
149
  TaggedUWord r14;
150
  TaggedUWord r15;
151
#elif defined(GP_ARCH_arm64)
152
  TaggedUWord x29;
153
  TaggedUWord x30;
154
  TaggedUWord sp;
155
  TaggedUWord pc;
156
#elif defined(GP_ARCH_amd64) || defined(GP_ARCH_x86)
157
  TaggedUWord xbp;
158
  TaggedUWord xsp;
159
  TaggedUWord xip;
160
#elif defined(GP_ARCH_mips64)
161
  TaggedUWord sp;
162
  TaggedUWord fp;
163
  TaggedUWord pc;
164
#else
165
# error "Unknown plat"
166
#endif
167
};
168
169
170
// The maximum number of bytes in a stack snapshot.  This value can be increased
171
// if necessary, but testing showed that 160k is enough to obtain good
172
// backtraces on x86_64 Linux.  Most backtraces fit comfortably into 4-8k of
173
// stack space, but we do have some very deep stacks occasionally.  Please see
174
// the comments in DoNativeBacktrace as to why it's OK to have this value be so
175
// large.
176
static const size_t N_STACK_BYTES = 160*1024;
177
178
// The stack chunk image that will be unwound.
179
struct StackImage {
180
  // [start_avma, +len) specify the address range in the buffer.
181
  // Obviously we require 0 <= len <= N_STACK_BYTES.
182
  uintptr_t mStartAvma;
183
  size_t    mLen;
184
  uint8_t   mContents[N_STACK_BYTES];
185
};
186
187
188
// Statistics collection for the unwinder.
189
template<typename T>
190
class LULStats {
191
public:
192
  LULStats()
193
    : mContext(0)
194
    , mCFI(0)
195
    , mFP(0)
196
0
  {}
Unexecuted instantiation: lul::LULStats<mozilla::Atomic<unsigned int, (mozilla::MemoryOrdering)2, (mozilla::recordreplay::Behavior)1, void> >::LULStats()
Unexecuted instantiation: lul::LULStats<unsigned int>::LULStats()
197
198
  template <typename S>
199
  explicit LULStats(const LULStats<S>& aOther)
200
    : mContext(aOther.mContext)
201
    , mCFI(aOther.mCFI)
202
    , mFP(aOther.mFP)
203
  {}
204
205
  template <typename S>
206
  LULStats<T>& operator=(const LULStats<S>& aOther)
207
0
  {
208
0
    mContext = aOther.mContext;
209
0
    mCFI     = aOther.mCFI;
210
0
    mFP      = aOther.mFP;
211
0
    return *this;
212
0
  }
213
214
  template <typename S>
215
0
  uint32_t operator-(const LULStats<S>& aOther) {
216
0
    return (mContext - aOther.mContext) +
217
0
           (mCFI - aOther.mCFI) + (mFP - aOther.mFP);
218
0
  }
219
220
  T mContext; // Number of context frames
221
  T mCFI;     // Number of CFI/EXIDX frames
222
  T mFP;      // Number of frame-pointer recovered frames
223
};
224
225
226
// The core unwinder library class.  Just one of these is needed, and
227
// it can be shared by multiple unwinder threads.
228
//
229
// The library operates in one of two modes.
230
//
231
// * Admin mode.  The library is this state after creation.  In Admin
232
//   mode, no unwinding may be performed.  It is however allowable to
233
//   perform administrative tasks -- primarily, loading of unwind info
234
//   -- in this mode.  In particular, it is safe for the library to
235
//   perform dynamic memory allocation in this mode.  Safe in the
236
//   sense that there is no risk of deadlock against unwinding threads
237
//   that might -- because of where they have been sampled -- hold the
238
//   system's malloc lock.
239
//
240
// * Unwind mode.  In this mode, calls to ::Unwind may be made, but
241
//   nothing else.  ::Unwind guarantees not to make any dynamic memory
242
//   requests, so as to guarantee that the calling thread won't
243
//   deadlock in the case where it already holds the system's malloc lock.
244
//
245
// The library is created in Admin mode.  After debuginfo is loaded,
246
// the caller must switch it into Unwind mode by calling
247
// ::EnableUnwinding.  There is no way to switch it back to Admin mode
248
// after that.  To safely switch back to Admin mode would require the
249
// caller (or other external agent) to guarantee that there are no
250
// pending ::Unwind calls.
251
252
class PriMap;
253
class SegArray;
254
class UniqueStringUniverse;
255
256
class LUL {
257
public:
258
  // Create; supply a logging sink.  Sets the object in Admin mode.
259
  explicit LUL(void (*aLog)(const char*));
260
261
  // Destroy.  Caller is responsible for ensuring that no other
262
  // threads are in Unwind calls.  All resources are freed and all
263
  // registered unwinder threads are deregistered.  Can be called
264
  // either in Admin or Unwind mode.
265
  ~LUL();
266
267
  // Notify the library that unwinding is now allowed and so
268
  // admin-mode calls are no longer allowed.  The object is initially
269
  // created in admin mode.  The only possible transition is
270
  // admin->unwinding, therefore.
271
  void EnableUnwinding();
272
273
  // Notify of a new r-x mapping, and load the associated unwind info.
274
  // The filename is strdup'd and used for debug printing.  If
275
  // aMappedImage is NULL, this function will mmap/munmap the file
276
  // itself, so as to be able to read the unwind info.  If
277
  // aMappedImage is non-NULL then it is assumed to point to a
278
  // called-supplied and caller-managed mapped image of the file.
279
  // May only be called in Admin mode.
280
  void NotifyAfterMap(uintptr_t aRXavma, size_t aSize,
281
                      const char* aFileName, const void* aMappedImage);
282
283
  // In rare cases we know an executable area exists but don't know
284
  // what the associated file is.  This call notifies LUL of such
285
  // areas.  This is important for correct functioning of stack
286
  // scanning and of the x86-{linux,android} special-case
287
  // __kernel_syscall function handling.
288
  // This must be called only after the code area in
289
  // question really has been mapped.
290
  // May only be called in Admin mode.
291
  void NotifyExecutableArea(uintptr_t aRXavma, size_t aSize);
292
293
  // Notify that a mapped area has been unmapped; discard any
294
  // associated unwind info.  Acquires mRWlock for writing.  Note that
295
  // to avoid segfaulting the stack-scan unwinder, which inspects code
296
  // areas, this must be called before the code area in question is
297
  // really unmapped.  Note that, unlike NotifyAfterMap(), this
298
  // function takes the start and end addresses of the range to be
299
  // unmapped, rather than a start and a length parameter.  This is so
300
  // as to make it possible to notify an unmap for the entire address
301
  // space using a single call.
302
  // May only be called in Admin mode.
303
  void NotifyBeforeUnmap(uintptr_t aAvmaMin, uintptr_t aAvmaMax);
304
305
  // Apply NotifyBeforeUnmap to the entire address space.  This causes
306
  // LUL to discard all unwind and executable-area information for the
307
  // entire address space.
308
  // May only be called in Admin mode.
309
0
  void NotifyBeforeUnmapAll() {
310
0
    NotifyBeforeUnmap(0, UINTPTR_MAX);
311
0
  }
312
313
  // Returns the number of mappings currently registered.
314
  // May only be called in Admin mode.
315
  size_t CountMappings();
316
317
  // Unwind |aStackImg| starting with the context in |aStartRegs|.
318
  // Write the number of frames recovered in *aFramesUsed.  Put
319
  // the PC values in aFramePCs[0 .. *aFramesUsed-1] and
320
  // the SP values in aFrameSPs[0 .. *aFramesUsed-1].
321
  // |aFramesAvail| is the size of the two output arrays and hence the
322
  // largest possible value of *aFramesUsed.  PC values are always
323
  // valid, and the unwind will stop when the PC becomes invalid, but
324
  // the SP values might be invalid, in which case the value zero will
325
  // be written in the relevant frameSPs[] slot.
326
  //
327
  // This function assumes that the SP values increase as it unwinds
328
  // away from the innermost frame -- that is, that the stack grows
329
  // down.  It monitors SP values as it unwinds to check they
330
  // decrease, so as to avoid looping on corrupted stacks.
331
  //
332
  // May only be called in Unwind mode.  Multiple threads may unwind
333
  // at once.  LUL user is responsible for ensuring that no thread makes
334
  // any Admin calls whilst in Unwind mode.
335
  // MOZ_CRASHes if the calling thread is not registered for unwinding.
336
  //
337
  // The calling thread must previously have been registered via a call to
338
  // RegisterSampledThread.
339
  void Unwind(/*OUT*/uintptr_t* aFramePCs,
340
              /*OUT*/uintptr_t* aFrameSPs,
341
              /*OUT*/size_t* aFramesUsed,
342
              /*OUT*/size_t* aFramePointerFramesAcquired,
343
              size_t aFramesAvail,
344
              UnwindRegs* aStartRegs, StackImage* aStackImg);
345
346
  // The logging sink.  Call to send debug strings to the caller-
347
  // specified destination.  Can only be called by the Admin thread.
348
  void (*mLog)(const char*);
349
350
  // Statistics relating to unwinding.  These have to be atomic since
351
  // unwinding can occur on different threads simultaneously.
352
  LULStats<mozilla::Atomic<uint32_t>> mStats;
353
354
  // Possibly show the statistics.  This may not be called from any
355
  // registered sampling thread, since it involves I/O.
356
  void MaybeShowStats();
357
358
  size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const;
359
360
private:
361
  // The statistics counters at the point where they were last printed.
362
  LULStats<uint32_t> mStatsPrevious;
363
364
  // Are we in admin mode?  Initially |true| but changes to |false|
365
  // once unwinding begins.
366
  bool mAdminMode;
367
368
  // The thread ID associated with admin mode.  This is the only thread
369
  // that is allowed do perform non-Unwind calls on this object.  Conversely,
370
  // no registered Unwinding thread may be the admin thread.  This is so
371
  // as to clearly partition the one thread that may do dynamic memory
372
  // allocation from the threads that are being sampled, since the latter
373
  // absolutely may not do dynamic memory allocation.
374
  int mAdminThreadId;
375
376
  // The top level mapping from code address ranges to postprocessed
377
  // unwind info.  Basically a sorted array of (addr, len, info)
378
  // records.  This field is updated by NotifyAfterMap and NotifyBeforeUnmap.
379
  PriMap* mPriMap;
380
381
  // An auxiliary structure that records which address ranges are
382
  // mapped r-x, for the benefit of the stack scanner.
383
  SegArray* mSegArray;
384
385
  // A UniqueStringUniverse that holds all the strdup'd strings created
386
  // whilst reading unwind information.  This is included so as to make
387
  // it possible to free them in ~LUL.
388
  UniqueStringUniverse* mUSU;
389
};
390
391
392
// Run unit tests on an initialised, loaded-up LUL instance, and print
393
// summary results on |aLUL|'s logging sink.  Also return the number
394
// of tests run in *aNTests and the number that passed in
395
// *aNTestsPassed.
396
void
397
RunLulUnitTests(/*OUT*/int* aNTests, /*OUT*/int*aNTestsPassed, LUL* aLUL);
398
399
} // namespace lul
400
401
#endif // LulMain_h