tools/profiler/LulMainInt.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 LulMainInt_h
     8 #define LulMainInt_h
    10 #include "LulPlatformMacros.h"
    12 #include <vector>
    14 #include "mozilla/Assertions.h"
    16 // This file is provides internal interface inside LUL.  If you are an
    17 // end-user of LUL, do not include it in your code.  The end-user
    18 // interface is in LulMain.h.
    21 namespace lul {
    23 ////////////////////////////////////////////////////////////////
    24 // DW_REG_ constants                                          //
    25 ////////////////////////////////////////////////////////////////
    27 // These are the Dwarf CFI register numbers, as (presumably) defined
    28 // in the ELF ABI supplements for each architecture.
    30 enum DW_REG_NUMBER {
    31   // No real register has this number.  It's convenient to be able to
    32   // treat the CFA (Canonical Frame Address) as "just another
    33   // register", though.
    34   DW_REG_CFA = -1,
    35 #if defined(LUL_ARCH_arm)
    36   // ARM registers
    37   DW_REG_ARM_R7  = 7,
    38   DW_REG_ARM_R11 = 11,
    39   DW_REG_ARM_R12 = 12,
    40   DW_REG_ARM_R13 = 13,
    41   DW_REG_ARM_R14 = 14,
    42   DW_REG_ARM_R15 = 15,
    43 #elif defined(LUL_ARCH_x64)
    44   // Because the X86 (32 bit) and AMD64 (64 bit) summarisers are
    45   // combined, a merged set of register constants is needed.
    46   DW_REG_INTEL_XBP = 6,
    47   DW_REG_INTEL_XSP = 7,
    48   DW_REG_INTEL_XIP = 16,
    49 #elif defined(LUL_ARCH_x86)
    50   DW_REG_INTEL_XBP = 5,
    51   DW_REG_INTEL_XSP = 4,
    52   DW_REG_INTEL_XIP = 8,
    53 #else
    54 # error "Unknown arch"
    55 #endif
    56 };
    59 ////////////////////////////////////////////////////////////////
    60 // LExpr                                                      //
    61 ////////////////////////////////////////////////////////////////
    63 // An expression -- very primitive.  Denotes either "register +
    64 // offset" or a dereferenced version of the same.  So as to allow
    65 // convenient handling of Dwarf-derived unwind info, the register may
    66 // also denote the CFA.  A large number of these need to be stored, so
    67 // we ensure it fits into 8 bytes.  See comment below on RuleSet to
    68 // see how expressions fit into the bigger picture.
    70 struct LExpr {
    71   // Denotes an expression with no value.
    72   LExpr()
    73     : mHow(UNKNOWN)
    74     , mReg(0)
    75     , mOffset(0)
    76   {}
    78   // Denotes any expressible expression.
    79   LExpr(uint8_t how, int16_t reg, int32_t offset)
    80     : mHow(how)
    81     , mReg(reg)
    82     , mOffset(offset)
    83   {}
    85   // Change the offset for an expression that references memory.
    86   LExpr add_delta(long delta)
    87   {
    88     MOZ_ASSERT(mHow == NODEREF);
    89     // If this is a non-debug build and the above assertion would have
    90     // failed, at least return LExpr() so that the machinery that uses
    91     // the resulting expression fails in a repeatable way.
    92     return (mHow == NODEREF) ? LExpr(mHow, mReg, mOffset+delta)
    93                              : LExpr(); // Gone bad
    94   }
    96   // Dereference an expression that denotes a memory address.
    97   LExpr deref()
    98   {
    99     MOZ_ASSERT(mHow == NODEREF);
   100     // Same rationale as for add_delta().
   101     return (mHow == NODEREF) ? LExpr(DEREF, mReg, mOffset)
   102                              : LExpr(); // Gone bad
   103   }
   105   // Representation of expressions.  If |mReg| is DW_REG_CFA (-1) then
   106   // it denotes the CFA.  All other allowed values for |mReg| are
   107   // nonnegative and are DW_REG_ values.
   109   enum { UNKNOWN=0, // This LExpr denotes no value.
   110          NODEREF,   // Value is  (mReg + mOffset).
   111          DEREF };   // Value is *(mReg + mOffset).
   113   uint8_t mHow;    // UNKNOWN, NODEREF or DEREF
   114   int16_t mReg;    // A DW_REG_ value
   115   int32_t mOffset; // 32-bit signed offset should be more than enough.
   116 };
   118 static_assert(sizeof(LExpr) <= 8, "LExpr size changed unexpectedly");
   121 ////////////////////////////////////////////////////////////////
   122 // RuleSet                                                    //
   123 ////////////////////////////////////////////////////////////////
   125 // This is platform-dependent.  For some address range, describes how
   126 // to recover the CFA and then how to recover the registers for the
   127 // previous frame.
   128 //
   129 // The set of LExprs contained in a given RuleSet describe a DAG which
   130 // says how to compute the caller's registers ("new registers") from
   131 // the callee's registers ("old registers").  The DAG can contain a
   132 // single internal node, which is the value of the CFA for the callee.
   133 // It would be possible to construct a DAG that omits the CFA, but
   134 // including it makes the summarisers simpler, and the Dwarf CFI spec
   135 // has the CFA as a central concept.
   136 //
   137 // For this to make sense, |mCfaExpr| can't have
   138 // |mReg| == DW_REG_CFA since we have no previous value for the CFA.
   139 // All of the other |Expr| fields can -- and usually do -- specify
   140 // |mReg| == DW_REG_CFA.
   141 //
   142 // With that in place, the unwind algorithm proceeds as follows.
   143 //
   144 // (0) Initially: we have values for the old registers, and a memory
   145 //     image.
   146 //
   147 // (1) Compute the CFA by evaluating |mCfaExpr|.  Add the computed
   148 //     value to the set of "old registers".
   149 //
   150 // (2) Compute values for the registers by evaluating all of the other
   151 //     |Expr| fields in the RuleSet.  These can depend on both the old
   152 //     register values and the just-computed CFA.
   153 //
   154 // If we are unwinding without computing a CFA, perhaps because the
   155 // RuleSets are derived from EXIDX instead of Dwarf, then
   156 // |mCfaExpr.mHow| will be LExpr::UNKNOWN, so the computed value will
   157 // be invalid -- that is, TaggedUWord() -- and so any attempt to use
   158 // that will result in the same value.  But that's OK because the
   159 // RuleSet would make no sense if depended on the CFA but specified no
   160 // way to compute it.
   161 //
   162 // A RuleSet is not allowed to cover zero address range.  Having zero
   163 // length would break binary searching in SecMaps and PriMaps.
   165 class RuleSet {
   166 public:
   167   RuleSet();
   168   void   Print(void(*aLog)(const char*));
   170   // Find the LExpr* for a given DW_REG_ value in this class.
   171   LExpr* ExprForRegno(DW_REG_NUMBER aRegno);
   173   uintptr_t mAddr;
   174   uintptr_t mLen;
   175   // How to compute the CFA.
   176   LExpr  mCfaExpr;
   177   // How to compute caller register values.  These may reference the
   178   // value defined by |mCfaExpr|.
   179 #if defined(LUL_ARCH_x64) || defined(LUL_ARCH_x86)
   180   LExpr  mXipExpr; // return address
   181   LExpr  mXspExpr;
   182   LExpr  mXbpExpr;
   183 #elif defined(LUL_ARCH_arm)
   184   LExpr  mR15expr; // return address
   185   LExpr  mR14expr;
   186   LExpr  mR13expr;
   187   LExpr  mR12expr;
   188   LExpr  mR11expr;
   189   LExpr  mR7expr;
   190 #else
   191 #   error "Unknown arch"
   192 #endif
   193 };
   196 ////////////////////////////////////////////////////////////////
   197 // SecMap                                                     //
   198 ////////////////////////////////////////////////////////////////
   200 // A SecMap may have zero address range, temporarily, whilst RuleSets
   201 // are being added to it.  But adding a zero-range SecMap to a PriMap
   202 // will make it impossible to maintain the total order of the PriMap
   203 // entries, and so that can't be allowed to happen.
   205 class SecMap {
   206 public:
   207   // These summarise the contained mRuleSets, in that they give
   208   // exactly the lowest and highest addresses that any of the entries
   209   // in this SecMap cover.  Hence invariants:
   210   //
   211   // mRuleSets is nonempty
   212   //    <=> mSummaryMinAddr <= mSummaryMaxAddr
   213   //        && mSummaryMinAddr == mRuleSets[0].mAddr
   214   //        && mSummaryMaxAddr == mRuleSets[#rulesets-1].mAddr
   215   //                              + mRuleSets[#rulesets-1].mLen - 1;
   216   //
   217   // This requires that no RuleSet has zero length.
   218   //
   219   // mRuleSets is empty
   220   //    <=> mSummaryMinAddr > mSummaryMaxAddr
   221   //
   222   // This doesn't constrain mSummaryMinAddr and mSummaryMaxAddr uniquely,
   223   // so let's use mSummaryMinAddr == 1 and mSummaryMaxAddr == 0 to denote
   224   // this case.
   226   SecMap(void(*aLog)(const char*));
   227   ~SecMap();
   229   // Binary search mRuleSets to find one that brackets |ia|, or nullptr
   230   // if none is found.  It's not allowable to do this until PrepareRuleSets
   231   // has been called first.
   232   RuleSet* FindRuleSet(uintptr_t ia);
   234   // Add a RuleSet to the collection.  The rule is copied in.  Calling
   235   // this makes the map non-searchable.
   236   void AddRuleSet(RuleSet* rs);
   238   // Prepare the map for searching.  Also, remove any rules for code
   239   // address ranges which don't fall inside [start, +len).  |len| may
   240   // not be zero.
   241   void PrepareRuleSets(uintptr_t start, size_t len);
   243   bool IsEmpty();
   245   size_t Size() { return mRuleSets.size(); }
   247   // The min and max addresses of the addresses in the contained
   248   // RuleSets.  See comment above for invariants.
   249   uintptr_t mSummaryMinAddr;
   250   uintptr_t mSummaryMaxAddr;
   252 private:
   253   // False whilst adding entries; true once it is safe to call FindRuleSet.
   254   // Transition (false->true) is caused by calling PrepareRuleSets().
   255   bool mUsable;
   257   // A vector of RuleSets, sorted, nonoverlapping (post Prepare()).
   258   std::vector<RuleSet> mRuleSets;
   260   // A logging sink, for debugging.
   261   void (*mLog)(const char*);
   262 };
   264 } // namespace lul
   266 #endif // ndef LulMainInt_h

mercurial