tools/profiler/LulMainInt.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/profiler/LulMainInt.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,266 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef LulMainInt_h
    1.11 +#define LulMainInt_h
    1.12 +
    1.13 +#include "LulPlatformMacros.h"
    1.14 +
    1.15 +#include <vector>
    1.16 +
    1.17 +#include "mozilla/Assertions.h"
    1.18 +
    1.19 +// This file is provides internal interface inside LUL.  If you are an
    1.20 +// end-user of LUL, do not include it in your code.  The end-user
    1.21 +// interface is in LulMain.h.
    1.22 +
    1.23 +
    1.24 +namespace lul {
    1.25 +
    1.26 +////////////////////////////////////////////////////////////////
    1.27 +// DW_REG_ constants                                          //
    1.28 +////////////////////////////////////////////////////////////////
    1.29 +
    1.30 +// These are the Dwarf CFI register numbers, as (presumably) defined
    1.31 +// in the ELF ABI supplements for each architecture.
    1.32 +
    1.33 +enum DW_REG_NUMBER {
    1.34 +  // No real register has this number.  It's convenient to be able to
    1.35 +  // treat the CFA (Canonical Frame Address) as "just another
    1.36 +  // register", though.
    1.37 +  DW_REG_CFA = -1,
    1.38 +#if defined(LUL_ARCH_arm)
    1.39 +  // ARM registers
    1.40 +  DW_REG_ARM_R7  = 7,
    1.41 +  DW_REG_ARM_R11 = 11,
    1.42 +  DW_REG_ARM_R12 = 12,
    1.43 +  DW_REG_ARM_R13 = 13,
    1.44 +  DW_REG_ARM_R14 = 14,
    1.45 +  DW_REG_ARM_R15 = 15,
    1.46 +#elif defined(LUL_ARCH_x64)
    1.47 +  // Because the X86 (32 bit) and AMD64 (64 bit) summarisers are
    1.48 +  // combined, a merged set of register constants is needed.
    1.49 +  DW_REG_INTEL_XBP = 6,
    1.50 +  DW_REG_INTEL_XSP = 7,
    1.51 +  DW_REG_INTEL_XIP = 16,
    1.52 +#elif defined(LUL_ARCH_x86)
    1.53 +  DW_REG_INTEL_XBP = 5,
    1.54 +  DW_REG_INTEL_XSP = 4,
    1.55 +  DW_REG_INTEL_XIP = 8,
    1.56 +#else
    1.57 +# error "Unknown arch"
    1.58 +#endif
    1.59 +};
    1.60 +
    1.61 +
    1.62 +////////////////////////////////////////////////////////////////
    1.63 +// LExpr                                                      //
    1.64 +////////////////////////////////////////////////////////////////
    1.65 +
    1.66 +// An expression -- very primitive.  Denotes either "register +
    1.67 +// offset" or a dereferenced version of the same.  So as to allow
    1.68 +// convenient handling of Dwarf-derived unwind info, the register may
    1.69 +// also denote the CFA.  A large number of these need to be stored, so
    1.70 +// we ensure it fits into 8 bytes.  See comment below on RuleSet to
    1.71 +// see how expressions fit into the bigger picture.
    1.72 +
    1.73 +struct LExpr {
    1.74 +  // Denotes an expression with no value.
    1.75 +  LExpr()
    1.76 +    : mHow(UNKNOWN)
    1.77 +    , mReg(0)
    1.78 +    , mOffset(0)
    1.79 +  {}
    1.80 +
    1.81 +  // Denotes any expressible expression.
    1.82 +  LExpr(uint8_t how, int16_t reg, int32_t offset)
    1.83 +    : mHow(how)
    1.84 +    , mReg(reg)
    1.85 +    , mOffset(offset)
    1.86 +  {}
    1.87 +
    1.88 +  // Change the offset for an expression that references memory.
    1.89 +  LExpr add_delta(long delta)
    1.90 +  {
    1.91 +    MOZ_ASSERT(mHow == NODEREF);
    1.92 +    // If this is a non-debug build and the above assertion would have
    1.93 +    // failed, at least return LExpr() so that the machinery that uses
    1.94 +    // the resulting expression fails in a repeatable way.
    1.95 +    return (mHow == NODEREF) ? LExpr(mHow, mReg, mOffset+delta)
    1.96 +                             : LExpr(); // Gone bad
    1.97 +  }
    1.98 +
    1.99 +  // Dereference an expression that denotes a memory address.
   1.100 +  LExpr deref()
   1.101 +  {
   1.102 +    MOZ_ASSERT(mHow == NODEREF);
   1.103 +    // Same rationale as for add_delta().
   1.104 +    return (mHow == NODEREF) ? LExpr(DEREF, mReg, mOffset)
   1.105 +                             : LExpr(); // Gone bad
   1.106 +  }
   1.107 +
   1.108 +  // Representation of expressions.  If |mReg| is DW_REG_CFA (-1) then
   1.109 +  // it denotes the CFA.  All other allowed values for |mReg| are
   1.110 +  // nonnegative and are DW_REG_ values.
   1.111 +
   1.112 +  enum { UNKNOWN=0, // This LExpr denotes no value.
   1.113 +         NODEREF,   // Value is  (mReg + mOffset).
   1.114 +         DEREF };   // Value is *(mReg + mOffset).
   1.115 +
   1.116 +  uint8_t mHow;    // UNKNOWN, NODEREF or DEREF
   1.117 +  int16_t mReg;    // A DW_REG_ value
   1.118 +  int32_t mOffset; // 32-bit signed offset should be more than enough.
   1.119 +};
   1.120 +
   1.121 +static_assert(sizeof(LExpr) <= 8, "LExpr size changed unexpectedly");
   1.122 +
   1.123 +
   1.124 +////////////////////////////////////////////////////////////////
   1.125 +// RuleSet                                                    //
   1.126 +////////////////////////////////////////////////////////////////
   1.127 +
   1.128 +// This is platform-dependent.  For some address range, describes how
   1.129 +// to recover the CFA and then how to recover the registers for the
   1.130 +// previous frame.
   1.131 +//
   1.132 +// The set of LExprs contained in a given RuleSet describe a DAG which
   1.133 +// says how to compute the caller's registers ("new registers") from
   1.134 +// the callee's registers ("old registers").  The DAG can contain a
   1.135 +// single internal node, which is the value of the CFA for the callee.
   1.136 +// It would be possible to construct a DAG that omits the CFA, but
   1.137 +// including it makes the summarisers simpler, and the Dwarf CFI spec
   1.138 +// has the CFA as a central concept.
   1.139 +//
   1.140 +// For this to make sense, |mCfaExpr| can't have
   1.141 +// |mReg| == DW_REG_CFA since we have no previous value for the CFA.
   1.142 +// All of the other |Expr| fields can -- and usually do -- specify
   1.143 +// |mReg| == DW_REG_CFA.
   1.144 +//
   1.145 +// With that in place, the unwind algorithm proceeds as follows.
   1.146 +//
   1.147 +// (0) Initially: we have values for the old registers, and a memory
   1.148 +//     image.
   1.149 +//
   1.150 +// (1) Compute the CFA by evaluating |mCfaExpr|.  Add the computed
   1.151 +//     value to the set of "old registers".
   1.152 +//
   1.153 +// (2) Compute values for the registers by evaluating all of the other
   1.154 +//     |Expr| fields in the RuleSet.  These can depend on both the old
   1.155 +//     register values and the just-computed CFA.
   1.156 +//
   1.157 +// If we are unwinding without computing a CFA, perhaps because the
   1.158 +// RuleSets are derived from EXIDX instead of Dwarf, then
   1.159 +// |mCfaExpr.mHow| will be LExpr::UNKNOWN, so the computed value will
   1.160 +// be invalid -- that is, TaggedUWord() -- and so any attempt to use
   1.161 +// that will result in the same value.  But that's OK because the
   1.162 +// RuleSet would make no sense if depended on the CFA but specified no
   1.163 +// way to compute it.
   1.164 +//
   1.165 +// A RuleSet is not allowed to cover zero address range.  Having zero
   1.166 +// length would break binary searching in SecMaps and PriMaps.
   1.167 +
   1.168 +class RuleSet {
   1.169 +public:
   1.170 +  RuleSet();
   1.171 +  void   Print(void(*aLog)(const char*));
   1.172 +
   1.173 +  // Find the LExpr* for a given DW_REG_ value in this class.
   1.174 +  LExpr* ExprForRegno(DW_REG_NUMBER aRegno);
   1.175 +
   1.176 +  uintptr_t mAddr;
   1.177 +  uintptr_t mLen;
   1.178 +  // How to compute the CFA.
   1.179 +  LExpr  mCfaExpr;
   1.180 +  // How to compute caller register values.  These may reference the
   1.181 +  // value defined by |mCfaExpr|.
   1.182 +#if defined(LUL_ARCH_x64) || defined(LUL_ARCH_x86)
   1.183 +  LExpr  mXipExpr; // return address
   1.184 +  LExpr  mXspExpr;
   1.185 +  LExpr  mXbpExpr;
   1.186 +#elif defined(LUL_ARCH_arm)
   1.187 +  LExpr  mR15expr; // return address
   1.188 +  LExpr  mR14expr;
   1.189 +  LExpr  mR13expr;
   1.190 +  LExpr  mR12expr;
   1.191 +  LExpr  mR11expr;
   1.192 +  LExpr  mR7expr;
   1.193 +#else
   1.194 +#   error "Unknown arch"
   1.195 +#endif
   1.196 +};
   1.197 +
   1.198 +
   1.199 +////////////////////////////////////////////////////////////////
   1.200 +// SecMap                                                     //
   1.201 +////////////////////////////////////////////////////////////////
   1.202 +
   1.203 +// A SecMap may have zero address range, temporarily, whilst RuleSets
   1.204 +// are being added to it.  But adding a zero-range SecMap to a PriMap
   1.205 +// will make it impossible to maintain the total order of the PriMap
   1.206 +// entries, and so that can't be allowed to happen.
   1.207 +
   1.208 +class SecMap {
   1.209 +public:
   1.210 +  // These summarise the contained mRuleSets, in that they give
   1.211 +  // exactly the lowest and highest addresses that any of the entries
   1.212 +  // in this SecMap cover.  Hence invariants:
   1.213 +  //
   1.214 +  // mRuleSets is nonempty
   1.215 +  //    <=> mSummaryMinAddr <= mSummaryMaxAddr
   1.216 +  //        && mSummaryMinAddr == mRuleSets[0].mAddr
   1.217 +  //        && mSummaryMaxAddr == mRuleSets[#rulesets-1].mAddr
   1.218 +  //                              + mRuleSets[#rulesets-1].mLen - 1;
   1.219 +  //
   1.220 +  // This requires that no RuleSet has zero length.
   1.221 +  //
   1.222 +  // mRuleSets is empty
   1.223 +  //    <=> mSummaryMinAddr > mSummaryMaxAddr
   1.224 +  //
   1.225 +  // This doesn't constrain mSummaryMinAddr and mSummaryMaxAddr uniquely,
   1.226 +  // so let's use mSummaryMinAddr == 1 and mSummaryMaxAddr == 0 to denote
   1.227 +  // this case.
   1.228 +
   1.229 +  SecMap(void(*aLog)(const char*));
   1.230 +  ~SecMap();
   1.231 +
   1.232 +  // Binary search mRuleSets to find one that brackets |ia|, or nullptr
   1.233 +  // if none is found.  It's not allowable to do this until PrepareRuleSets
   1.234 +  // has been called first.
   1.235 +  RuleSet* FindRuleSet(uintptr_t ia);
   1.236 +
   1.237 +  // Add a RuleSet to the collection.  The rule is copied in.  Calling
   1.238 +  // this makes the map non-searchable.
   1.239 +  void AddRuleSet(RuleSet* rs);
   1.240 +
   1.241 +  // Prepare the map for searching.  Also, remove any rules for code
   1.242 +  // address ranges which don't fall inside [start, +len).  |len| may
   1.243 +  // not be zero.
   1.244 +  void PrepareRuleSets(uintptr_t start, size_t len);
   1.245 +
   1.246 +  bool IsEmpty();
   1.247 +
   1.248 +  size_t Size() { return mRuleSets.size(); }
   1.249 +
   1.250 +  // The min and max addresses of the addresses in the contained
   1.251 +  // RuleSets.  See comment above for invariants.
   1.252 +  uintptr_t mSummaryMinAddr;
   1.253 +  uintptr_t mSummaryMaxAddr;
   1.254 +
   1.255 +private:
   1.256 +  // False whilst adding entries; true once it is safe to call FindRuleSet.
   1.257 +  // Transition (false->true) is caused by calling PrepareRuleSets().
   1.258 +  bool mUsable;
   1.259 +
   1.260 +  // A vector of RuleSets, sorted, nonoverlapping (post Prepare()).
   1.261 +  std::vector<RuleSet> mRuleSets;
   1.262 +
   1.263 +  // A logging sink, for debugging.
   1.264 +  void (*mLog)(const char*);
   1.265 +};
   1.266 +
   1.267 +} // namespace lul
   1.268 +
   1.269 +#endif // ndef LulMainInt_h

mercurial