LCOV - code coverage report
Current view: top level - tools/profiler/lul - LulMain.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 48 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 :   explicit TaggedUWord(uintptr_t w)
      62           0 :     : mValue(w)
      63           0 :     , mValid(true)
      64           0 :   {}
      65             : 
      66             :   // RUNS IN NO-MALLOC CONTEXT
      67             :   // Construct an invalid one.
      68           0 :   TaggedUWord()
      69           0 :     : mValue(0)
      70           0 :     , 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             :   }
      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             :   }
      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             :   }
      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             :   }
      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             :     }
     104           0 :     return TaggedUWord();
     105             :   }
     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             :     }
     114           0 :     return TaggedUWord();
     115             :   }
     116             : 
     117             :   // RUNS IN NO-MALLOC CONTEXT
     118             :   // Is equal?  Note: non-validity on either side gives non-equality.
     119             :   bool operator==(TaggedUWord other) const {
     120             :     return (mValid && other.Valid()) ? (mValue == other.Value()) : false;
     121             :   }
     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             :   }
     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           0 : 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_amd64) || defined(GP_ARCH_x86)
     152             :   TaggedUWord xbp;
     153             :   TaggedUWord xsp;
     154             :   TaggedUWord xip;
     155             : #else
     156             : # error "Unknown plat"
     157             : #endif
     158             : };
     159             : 
     160             : 
     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;
     168             : 
     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];
     176             : };
     177             : 
     178             : 
     179             : // Statistics collection for the unwinder.
     180             : template<typename T>
     181             : class LULStats {
     182             : public:
     183           0 :   LULStats()
     184             :     : mContext(0)
     185             :     , mCFI(0)
     186           0 :     , mFP(0)
     187           0 :   {}
     188             : 
     189             :   template <typename S>
     190             :   explicit LULStats(const LULStats<S>& aOther)
     191             :     : mContext(aOther.mContext)
     192             :     , mCFI(aOther.mCFI)
     193             :     , mFP(aOther.mFP)
     194             :   {}
     195             : 
     196             :   template <typename S>
     197           0 :   LULStats<T>& operator=(const LULStats<S>& aOther)
     198             :   {
     199           0 :     mContext = aOther.mContext;
     200           0 :     mCFI     = aOther.mCFI;
     201           0 :     mFP      = aOther.mFP;
     202           0 :     return *this;
     203             :   }
     204             : 
     205             :   template <typename S>
     206           0 :   uint32_t operator-(const LULStats<S>& aOther) {
     207           0 :     return (mContext - aOther.mContext) +
     208           0 :            (mCFI - aOther.mCFI) + (mFP - aOther.mFP);
     209             :   }
     210             : 
     211             :   T mContext; // Number of context frames
     212             :   T mCFI;     // Number of CFI/EXIDX frames
     213             :   T mFP;      // Number of frame-pointer recovered frames
     214             : };
     215             : 
     216             : 
     217             : // The core unwinder library class.  Just one of these is needed, and
     218             : // it can be shared by multiple unwinder threads.
     219             : //
     220             : // The library operates in one of two modes.
     221             : //
     222             : // * Admin mode.  The library is this state after creation.  In Admin
     223             : //   mode, no unwinding may be performed.  It is however allowable to
     224             : //   perform administrative tasks -- primarily, loading of unwind info
     225             : //   -- in this mode.  In particular, it is safe for the library to
     226             : //   perform dynamic memory allocation in this mode.  Safe in the
     227             : //   sense that there is no risk of deadlock against unwinding threads
     228             : //   that might -- because of where they have been sampled -- hold the
     229             : //   system's malloc lock.
     230             : //
     231             : // * Unwind mode.  In this mode, calls to ::Unwind may be made, but
     232             : //   nothing else.  ::Unwind guarantees not to make any dynamic memory
     233             : //   requests, so as to guarantee that the calling thread won't
     234             : //   deadlock in the case where it already holds the system's malloc lock.
     235             : //
     236             : // The library is created in Admin mode.  After debuginfo is loaded,
     237             : // the caller must switch it into Unwind mode by calling
     238             : // ::EnableUnwinding.  There is no way to switch it back to Admin mode
     239             : // after that.  To safely switch back to Admin mode would require the
     240             : // caller (or other external agent) to guarantee that there are no
     241             : // pending ::Unwind calls.
     242             : 
     243             : class PriMap;
     244             : class SegArray;
     245             : class UniqueStringUniverse;
     246             : 
     247             : class LUL {
     248             : public:
     249             :   // Create; supply a logging sink.  Sets the object in Admin mode.
     250             :   explicit LUL(void (*aLog)(const char*));
     251             : 
     252             :   // Destroy.  Caller is responsible for ensuring that no other
     253             :   // threads are in Unwind calls.  All resources are freed and all
     254             :   // registered unwinder threads are deregistered.  Can be called
     255             :   // either in Admin or Unwind mode.
     256             :   ~LUL();
     257             : 
     258             :   // Notify the library that unwinding is now allowed and so
     259             :   // admin-mode calls are no longer allowed.  The object is initially
     260             :   // created in admin mode.  The only possible transition is
     261             :   // admin->unwinding, therefore.
     262             :   void EnableUnwinding();
     263             : 
     264             :   // Notify of a new r-x mapping, and load the associated unwind info.
     265             :   // The filename is strdup'd and used for debug printing.  If
     266             :   // aMappedImage is NULL, this function will mmap/munmap the file
     267             :   // itself, so as to be able to read the unwind info.  If
     268             :   // aMappedImage is non-NULL then it is assumed to point to a
     269             :   // called-supplied and caller-managed mapped image of the file.
     270             :   // May only be called in Admin mode.
     271             :   void NotifyAfterMap(uintptr_t aRXavma, size_t aSize,
     272             :                       const char* aFileName, const void* aMappedImage);
     273             : 
     274             :   // In rare cases we know an executable area exists but don't know
     275             :   // what the associated file is.  This call notifies LUL of such
     276             :   // areas.  This is important for correct functioning of stack
     277             :   // scanning and of the x86-{linux,android} special-case
     278             :   // __kernel_syscall function handling.
     279             :   // This must be called only after the code area in
     280             :   // question really has been mapped.
     281             :   // May only be called in Admin mode.
     282             :   void NotifyExecutableArea(uintptr_t aRXavma, size_t aSize);
     283             : 
     284             :   // Notify that a mapped area has been unmapped; discard any
     285             :   // associated unwind info.  Acquires mRWlock for writing.  Note that
     286             :   // to avoid segfaulting the stack-scan unwinder, which inspects code
     287             :   // areas, this must be called before the code area in question is
     288             :   // really unmapped.  Note that, unlike NotifyAfterMap(), this
     289             :   // function takes the start and end addresses of the range to be
     290             :   // unmapped, rather than a start and a length parameter.  This is so
     291             :   // as to make it possible to notify an unmap for the entire address
     292             :   // space using a single call.
     293             :   // May only be called in Admin mode.
     294             :   void NotifyBeforeUnmap(uintptr_t aAvmaMin, uintptr_t aAvmaMax);
     295             : 
     296             :   // Apply NotifyBeforeUnmap to the entire address space.  This causes
     297             :   // LUL to discard all unwind and executable-area information for the
     298             :   // entire address space.
     299             :   // May only be called in Admin mode.
     300             :   void NotifyBeforeUnmapAll() {
     301             :     NotifyBeforeUnmap(0, UINTPTR_MAX);
     302             :   }
     303             : 
     304             :   // Returns the number of mappings currently registered.
     305             :   // May only be called in Admin mode.
     306             :   size_t CountMappings();
     307             : 
     308             :   // Unwind |aStackImg| starting with the context in |aStartRegs|.
     309             :   // Write the number of frames recovered in *aFramesUsed.  Put
     310             :   // the PC values in aFramePCs[0 .. *aFramesUsed-1] and
     311             :   // the SP values in aFrameSPs[0 .. *aFramesUsed-1].
     312             :   // |aFramesAvail| is the size of the two output arrays and hence the
     313             :   // largest possible value of *aFramesUsed.  PC values are always
     314             :   // valid, and the unwind will stop when the PC becomes invalid, but
     315             :   // the SP values might be invalid, in which case the value zero will
     316             :   // be written in the relevant frameSPs[] slot.
     317             :   //
     318             :   // This function assumes that the SP values increase as it unwinds
     319             :   // away from the innermost frame -- that is, that the stack grows
     320             :   // down.  It monitors SP values as it unwinds to check they
     321             :   // decrease, so as to avoid looping on corrupted stacks.
     322             :   //
     323             :   // May only be called in Unwind mode.  Multiple threads may unwind
     324             :   // at once.  LUL user is responsible for ensuring that no thread makes
     325             :   // any Admin calls whilst in Unwind mode.
     326             :   // MOZ_CRASHes if the calling thread is not registered for unwinding.
     327             :   //
     328             :   // The calling thread must previously have been registered via a call to
     329             :   // RegisterSampledThread.
     330             :   void Unwind(/*OUT*/uintptr_t* aFramePCs,
     331             :               /*OUT*/uintptr_t* aFrameSPs,
     332             :               /*OUT*/size_t* aFramesUsed,
     333             :               /*OUT*/size_t* aFramePointerFramesAcquired,
     334             :               size_t aFramesAvail,
     335             :               UnwindRegs* aStartRegs, StackImage* aStackImg);
     336             : 
     337             :   // The logging sink.  Call to send debug strings to the caller-
     338             :   // specified destination.  Can only be called by the Admin thread.
     339             :   void (*mLog)(const char*);
     340             : 
     341             :   // Statistics relating to unwinding.  These have to be atomic since
     342             :   // unwinding can occur on different threads simultaneously.
     343             :   LULStats<mozilla::Atomic<uint32_t>> mStats;
     344             : 
     345             :   // Possibly show the statistics.  This may not be called from any
     346             :   // registered sampling thread, since it involves I/O.
     347             :   void MaybeShowStats();
     348             : 
     349             :   size_t SizeOfIncludingThis(mozilla::MallocSizeOf) const;
     350             : 
     351             : private:
     352             :   // The statistics counters at the point where they were last printed.
     353             :   LULStats<uint32_t> mStatsPrevious;
     354             : 
     355             :   // Are we in admin mode?  Initially |true| but changes to |false|
     356             :   // once unwinding begins.
     357             :   bool mAdminMode;
     358             : 
     359             :   // The thread ID associated with admin mode.  This is the only thread
     360             :   // that is allowed do perform non-Unwind calls on this object.  Conversely,
     361             :   // no registered Unwinding thread may be the admin thread.  This is so
     362             :   // as to clearly partition the one thread that may do dynamic memory
     363             :   // allocation from the threads that are being sampled, since the latter
     364             :   // absolutely may not do dynamic memory allocation.
     365             :   int mAdminThreadId;
     366             : 
     367             :   // The top level mapping from code address ranges to postprocessed
     368             :   // unwind info.  Basically a sorted array of (addr, len, info)
     369             :   // records.  This field is updated by NotifyAfterMap and NotifyBeforeUnmap.
     370             :   PriMap* mPriMap;
     371             : 
     372             :   // An auxiliary structure that records which address ranges are
     373             :   // mapped r-x, for the benefit of the stack scanner.
     374             :   SegArray* mSegArray;
     375             : 
     376             :   // A UniqueStringUniverse that holds all the strdup'd strings created
     377             :   // whilst reading unwind information.  This is included so as to make
     378             :   // it possible to free them in ~LUL.
     379             :   UniqueStringUniverse* mUSU;
     380             : };
     381             : 
     382             : 
     383             : // Run unit tests on an initialised, loaded-up LUL instance, and print
     384             : // summary results on |aLUL|'s logging sink.  Also return the number
     385             : // of tests run in *aNTests and the number that passed in
     386             : // *aNTestsPassed.
     387             : void
     388             : RunLulUnitTests(/*OUT*/int* aNTests, /*OUT*/int*aNTestsPassed, LUL* aLUL);
     389             : 
     390             : } // namespace lul
     391             : 
     392             : #endif // LulMain_h

Generated by: LCOV version 1.13