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