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