Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===-- LVObject.h ----------------------------------------------*- C++ -*-===// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | // |
||
| 9 | // This file defines the LVObject class, which is used to describe a debug |
||
| 10 | // information object. |
||
| 11 | // |
||
| 12 | //===----------------------------------------------------------------------===// |
||
| 13 | |||
| 14 | #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |
||
| 15 | #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |
||
| 16 | |||
| 17 | #include "llvm/BinaryFormat/Dwarf.h" |
||
| 18 | #include "llvm/DebugInfo/CodeView/CodeView.h" |
||
| 19 | #include "llvm/DebugInfo/CodeView/TypeIndex.h" |
||
| 20 | #include "llvm/DebugInfo/LogicalView/Core/LVSupport.h" |
||
| 21 | #include <limits> |
||
| 22 | #include <list> |
||
| 23 | #include <map> |
||
| 24 | #include <string> |
||
| 25 | |||
| 26 | namespace llvm { |
||
| 27 | namespace dwarf { |
||
| 28 | // Support for CodeView ModifierOptions::Unaligned. |
||
| 29 | constexpr Tag DW_TAG_unaligned = Tag(dwarf::DW_TAG_hi_user + 1); |
||
| 30 | } // namespace dwarf |
||
| 31 | } // namespace llvm |
||
| 32 | |||
| 33 | namespace llvm { |
||
| 34 | namespace logicalview { |
||
| 35 | |||
| 36 | using LVSectionIndex = uint64_t; |
||
| 37 | using LVAddress = uint64_t; |
||
| 38 | using LVHalf = uint16_t; |
||
| 39 | using LVLevel = uint32_t; |
||
| 40 | using LVOffset = uint64_t; |
||
| 41 | using LVSigned = int64_t; |
||
| 42 | using LVUnsigned = uint64_t; |
||
| 43 | using LVSmall = uint8_t; |
||
| 44 | |||
| 45 | class LVElement; |
||
| 46 | class LVLine; |
||
| 47 | class LVLocation; |
||
| 48 | class LVLocationSymbol; |
||
| 49 | class LVObject; |
||
| 50 | class LVOperation; |
||
| 51 | class LVScope; |
||
| 52 | class LVSymbol; |
||
| 53 | class LVType; |
||
| 54 | |||
| 55 | class LVOptions; |
||
| 56 | class LVPatterns; |
||
| 57 | |||
| 58 | StringRef typeNone(); |
||
| 59 | StringRef typeVoid(); |
||
| 60 | StringRef typeInt(); |
||
| 61 | StringRef typeUnknown(); |
||
| 62 | StringRef emptyString(); |
||
| 63 | |||
| 64 | using LVElementSetFunction = void (LVElement::*)(); |
||
| 65 | using LVElementGetFunction = bool (LVElement::*)() const; |
||
| 66 | using LVLineSetFunction = void (LVLine::*)(); |
||
| 67 | using LVLineGetFunction = bool (LVLine::*)() const; |
||
| 68 | using LVObjectSetFunction = void (LVObject::*)(); |
||
| 69 | using LVObjectGetFunction = bool (LVObject::*)() const; |
||
| 70 | using LVScopeSetFunction = void (LVScope::*)(); |
||
| 71 | using LVScopeGetFunction = bool (LVScope::*)() const; |
||
| 72 | using LVSymbolSetFunction = void (LVSymbol::*)(); |
||
| 73 | using LVSymbolGetFunction = bool (LVSymbol::*)() const; |
||
| 74 | using LVTypeSetFunction = void (LVType::*)(); |
||
| 75 | using LVTypeGetFunction = bool (LVType::*)() const; |
||
| 76 | |||
| 77 | // The LVScope class represents a logical scope and uses vectors to store its |
||
| 78 | // children, which are pointers to other allocated logical elements (types, |
||
| 79 | // symbols, lines, scopes, ranges). On destruction, we have to traverse each |
||
| 80 | // vector and destroy its elements. The other case is LVSymbol. |
||
| 81 | // These definitions are intended to be used by the LVScope and LVSymbol |
||
| 82 | // to support automatic vector cleanup. |
||
| 83 | using LVAutoLines = LVAutoSmallVector<LVLine *>; |
||
| 84 | using LVAutoLocations = LVAutoSmallVector<LVLocation *>; |
||
| 85 | using LVAutoOperations = LVAutoSmallVector<LVOperation *, 8>; |
||
| 86 | using LVAutoScopes = LVAutoSmallVector<LVScope *>; |
||
| 87 | using LVAutoSymbols = LVAutoSmallVector<LVSymbol *>; |
||
| 88 | using LVAutoTypes = LVAutoSmallVector<LVType *>; |
||
| 89 | |||
| 90 | // These definitions are intended to be used when the vector will be used |
||
| 91 | // just a container, with no automatic destruction. |
||
| 92 | using LVElements = SmallVector<LVElement *, 8>; |
||
| 93 | using LVLines = SmallVector<LVLine *, 8>; |
||
| 94 | using LVLocations = SmallVector<LVLocation *, 8>; |
||
| 95 | using LVOperations = SmallVector<LVOperation *, 8>; |
||
| 96 | using LVScopes = SmallVector<LVScope *, 8>; |
||
| 97 | using LVSymbols = SmallVector<LVSymbol *, 8>; |
||
| 98 | using LVTypes = SmallVector<LVType *, 8>; |
||
| 99 | |||
| 100 | using LVOffsets = SmallVector<LVOffset, 8>; |
||
| 101 | |||
| 102 | const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max(); |
||
| 103 | |||
| 104 | enum class LVBinaryType { NONE, ELF, COFF }; |
||
| 105 | enum class LVComparePass { Missing, Added }; |
||
| 106 | |||
| 107 | // Validate functions. |
||
| 108 | using LVValidLocation = bool (LVLocation::*)(); |
||
| 109 | |||
| 110 | // Keep counters of objects. |
||
| 111 | struct LVCounter { |
||
| 112 | unsigned Lines = 0; |
||
| 113 | unsigned Scopes = 0; |
||
| 114 | unsigned Symbols = 0; |
||
| 115 | unsigned Types = 0; |
||
| 116 | void reset() { |
||
| 117 | Lines = 0; |
||
| 118 | Scopes = 0; |
||
| 119 | Symbols = 0; |
||
| 120 | Types = 0; |
||
| 121 | } |
||
| 122 | }; |
||
| 123 | |||
| 124 | class LVObject { |
||
| 125 | enum class Property { |
||
| 126 | IsLocation, // Location. |
||
| 127 | IsGlobalReference, // This object is being referenced from another CU. |
||
| 128 | IsGeneratedName, // The Object name was generated. |
||
| 129 | IsResolved, // Object has been resolved. |
||
| 130 | IsResolvedName, // Object name has been resolved. |
||
| 131 | IsDiscarded, // Object has been stripped by the linker. |
||
| 132 | IsOptimized, // Object has been optimized by the compiler. |
||
| 133 | IsAdded, // Object has been 'added'. |
||
| 134 | IsMatched, // Object has been matched to a given pattern. |
||
| 135 | IsMissing, // Object is 'missing'. |
||
| 136 | IsMissingLink, // Object is indirectly 'missing'. |
||
| 137 | IsInCompare, // In 'compare' mode. |
||
| 138 | IsFileFromReference, // File ID from specification. |
||
| 139 | IsLineFromReference, // Line No from specification. |
||
| 140 | HasMoved, // The object was moved from 'target' to 'reference'. |
||
| 141 | HasPattern, // The object has a pattern. |
||
| 142 | IsFinalized, // CodeView object is finalized. |
||
| 143 | IsReferenced, // CodeView object being referenced. |
||
| 144 | HasCodeViewLocation, // CodeView object with debug location. |
||
| 145 | LastEntry |
||
| 146 | }; |
||
| 147 | // Typed bitvector with properties for this object. |
||
| 148 | LVProperties<Property> Properties; |
||
| 149 | |||
| 150 | LVOffset Offset = 0; |
||
| 151 | uint32_t LineNumber = 0; |
||
| 152 | LVLevel ScopeLevel = 0; |
||
| 153 | union { |
||
| 154 | dwarf::Tag Tag; |
||
| 155 | dwarf::Attribute Attr; |
||
| 156 | LVSmall Opcode; |
||
| 157 | } TagAttrOpcode = {dwarf::DW_TAG_null}; |
||
| 158 | |||
| 159 | // The parent of this object (nullptr if the root scope). For locations, |
||
| 160 | // the parent is a symbol object; otherwise it is a scope object. |
||
| 161 | union { |
||
| 162 | LVElement *Element; |
||
| 163 | LVScope *Scope; |
||
| 164 | LVSymbol *Symbol; |
||
| 165 | } Parent = {nullptr}; |
||
| 166 | |||
| 167 | // We do not support any object duplication, as they are created by parsing |
||
| 168 | // the debug information. There is only the case where we need a very basic |
||
| 169 | // object, to manipulate its offset, line number and scope level. Allow the |
||
| 170 | // copy constructor to create that object; it is used to print a reference |
||
| 171 | // to another object and in the case of templates, to print its encoded args. |
||
| 172 | LVObject(const LVObject &Object) { |
||
| 173 | #ifndef NDEBUG |
||
| 174 | incID(); |
||
| 175 | #endif |
||
| 176 | Properties = Object.Properties; |
||
| 177 | Offset = Object.Offset; |
||
| 178 | LineNumber = Object.LineNumber; |
||
| 179 | ScopeLevel = Object.ScopeLevel; |
||
| 180 | TagAttrOpcode = Object.TagAttrOpcode; |
||
| 181 | Parent = Object.Parent; |
||
| 182 | } |
||
| 183 | |||
| 184 | #ifndef NDEBUG |
||
| 185 | // This is an internal ID used for debugging logical elements. It is used |
||
| 186 | // for cases where an unique offset within the binary input file is not |
||
| 187 | // available. |
||
| 188 | static uint64_t GID; |
||
| 189 | uint64_t ID = 0; |
||
| 190 | |||
| 191 | void incID() { |
||
| 192 | ++GID; |
||
| 193 | ID = GID; |
||
| 194 | } |
||
| 195 | #endif |
||
| 196 | |||
| 197 | protected: |
||
| 198 | // Get a string representation for the given number and discriminator. |
||
| 199 | std::string lineAsString(uint32_t LineNumber, LVHalf Discriminator, |
||
| 200 | bool ShowZero) const; |
||
| 201 | |||
| 202 | // Get a string representation for the given number. |
||
| 203 | std::string referenceAsString(uint32_t LineNumber, bool Spaces) const; |
||
| 204 | |||
| 205 | // Print the Filename or Pathname. |
||
| 206 | // Empty implementation for those objects that do not have any user |
||
| 207 | // source file references, such as debug locations. |
||
| 208 | virtual void printFileIndex(raw_ostream &OS, bool Full = true) const {} |
||
| 209 | |||
| 210 | public: |
||
| 211 | LVObject() { |
||
| 212 | #ifndef NDEBUG |
||
| 213 | incID(); |
||
| 214 | #endif |
||
| 215 | }; |
||
| 216 | LVObject &operator=(const LVObject &) = delete; |
||
| 217 | virtual ~LVObject() = default; |
||
| 218 | |||
| 219 | PROPERTY(Property, IsLocation); |
||
| 220 | PROPERTY(Property, IsGlobalReference); |
||
| 221 | PROPERTY(Property, IsGeneratedName); |
||
| 222 | PROPERTY(Property, IsResolved); |
||
| 223 | PROPERTY(Property, IsResolvedName); |
||
| 224 | PROPERTY(Property, IsDiscarded); |
||
| 225 | PROPERTY(Property, IsOptimized); |
||
| 226 | PROPERTY(Property, IsAdded); |
||
| 227 | PROPERTY(Property, IsMatched); |
||
| 228 | PROPERTY(Property, IsMissing); |
||
| 229 | PROPERTY(Property, IsMissingLink); |
||
| 230 | PROPERTY(Property, IsInCompare); |
||
| 231 | PROPERTY(Property, IsFileFromReference); |
||
| 232 | PROPERTY(Property, IsLineFromReference); |
||
| 233 | PROPERTY(Property, HasMoved); |
||
| 234 | PROPERTY(Property, HasPattern); |
||
| 235 | PROPERTY(Property, IsFinalized); |
||
| 236 | PROPERTY(Property, IsReferenced); |
||
| 237 | PROPERTY(Property, HasCodeViewLocation); |
||
| 238 | |||
| 239 | // True if the scope has been named or typed or with line number. |
||
| 240 | virtual bool isNamed() const { return false; } |
||
| 241 | virtual bool isTyped() const { return false; } |
||
| 242 | virtual bool isFiled() const { return false; } |
||
| 243 | bool isLined() const { return LineNumber != 0; } |
||
| 244 | |||
| 245 | // DWARF tag, attribute or expression opcode. |
||
| 246 | dwarf::Tag getTag() const { return TagAttrOpcode.Tag; } |
||
| 247 | void setTag(dwarf::Tag Tag) { TagAttrOpcode.Tag = Tag; } |
||
| 248 | dwarf::Attribute getAttr() const { return TagAttrOpcode.Attr; } |
||
| 249 | void setAttr(dwarf::Attribute Attr) { TagAttrOpcode.Attr = Attr; } |
||
| 250 | LVSmall getOpcode() const { return TagAttrOpcode.Opcode; } |
||
| 251 | void setOpcode(LVSmall Opcode) { TagAttrOpcode.Opcode = Opcode; } |
||
| 252 | |||
| 253 | // DIE offset. |
||
| 254 | LVOffset getOffset() const { return Offset; } |
||
| 255 | void setOffset(LVOffset DieOffset) { Offset = DieOffset; } |
||
| 256 | |||
| 257 | // Level where this object is located. |
||
| 258 | LVLevel getLevel() const { return ScopeLevel; } |
||
| 259 | void setLevel(LVLevel Level) { ScopeLevel = Level; } |
||
| 260 | |||
| 261 | virtual StringRef getName() const { return StringRef(); } |
||
| 262 | virtual void setName(StringRef ObjectName) {} |
||
| 263 | |||
| 264 | LVElement *getParent() const { |
||
| 265 | assert((!Parent.Element || |
||
| 266 | (Parent.Element && static_cast<LVElement *>(Parent.Element))) && |
||
| 267 | "Invalid element"); |
||
| 268 | return Parent.Element; |
||
| 269 | } |
||
| 270 | LVScope *getParentScope() const { |
||
| 271 | assert((!Parent.Scope || |
||
| 272 | (Parent.Scope && static_cast<LVScope *>(Parent.Scope))) && |
||
| 273 | "Invalid scope"); |
||
| 274 | return Parent.Scope; |
||
| 275 | } |
||
| 276 | LVSymbol *getParentSymbol() const { |
||
| 277 | assert((!Parent.Symbol || |
||
| 278 | (Parent.Symbol && static_cast<LVSymbol *>(Parent.Symbol))) && |
||
| 279 | "Invalid symbol"); |
||
| 280 | return Parent.Symbol; |
||
| 281 | } |
||
| 282 | void setParent(LVScope *Scope); |
||
| 283 | void setParent(LVSymbol *Symbol); |
||
| 284 | void resetParent() { Parent = {nullptr}; } |
||
| 285 | |||
| 286 | virtual LVAddress getLowerAddress() const { return 0; } |
||
| 287 | virtual void setLowerAddress(LVAddress Address) {} |
||
| 288 | virtual LVAddress getUpperAddress() const { return 0; } |
||
| 289 | virtual void setUpperAddress(LVAddress Address) {} |
||
| 290 | |||
| 291 | uint32_t getLineNumber() const { return LineNumber; } |
||
| 292 | void setLineNumber(uint32_t Number) { LineNumber = Number; } |
||
| 293 | |||
| 294 | virtual const char *kind() const { return nullptr; } |
||
| 295 | |||
| 296 | std::string indentAsString() const; |
||
| 297 | std::string indentAsString(LVLevel Level) const; |
||
| 298 | |||
| 299 | // String used as padding for printing objects with no line number. |
||
| 300 | virtual std::string noLineAsString(bool ShowZero) const; |
||
| 301 | |||
| 302 | // Line number for display; in the case of inlined functions, we use the |
||
| 303 | // DW_AT_call_line attribute; otherwise use DW_AT_decl_line attribute. |
||
| 304 | virtual std::string lineNumberAsString(bool ShowZero = false) const { |
||
| 305 | return lineAsString(getLineNumber(), 0, ShowZero); |
||
| 306 | } |
||
| 307 | std::string lineNumberAsStringStripped(bool ShowZero = false) const; |
||
| 308 | |||
| 309 | // This function prints the logical view to an output stream. |
||
| 310 | // Split: Prints the compilation unit view to a file. |
||
| 311 | // Match: Prints the object only if it satisfies the patterns collected |
||
| 312 | // from the command line. See the '--select' option. |
||
| 313 | // Print: Print the object only if satisfies the conditions specified by |
||
| 314 | // the different '--print' options. |
||
| 315 | // Full: Prints full information for objects representing debug locations, |
||
| 316 | // aggregated scopes, compile unit, functions and namespaces. |
||
| 317 | virtual Error doPrint(bool Split, bool Match, bool Print, raw_ostream &OS, |
||
| 318 | bool Full = true) const; |
||
| 319 | void printAttributes(raw_ostream &OS, bool Full = true) const; |
||
| 320 | void printAttributes(raw_ostream &OS, bool Full, StringRef Name, |
||
| 321 | LVObject *Parent, StringRef Value, |
||
| 322 | bool UseQuotes = false, bool PrintRef = false) const; |
||
| 323 | |||
| 324 | // Mark branch as missing (current element and parents). |
||
| 325 | void markBranchAsMissing(); |
||
| 326 | |||
| 327 | // Prints the common information for an object (name, type, etc). |
||
| 328 | virtual void print(raw_ostream &OS, bool Full = true) const; |
||
| 329 | // Prints additional information for an object, depending on its kind |
||
| 330 | // (class attributes, debug ranges, files, directories, etc). |
||
| 331 | virtual void printExtra(raw_ostream &OS, bool Full = true) const {} |
||
| 332 | |||
| 333 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
||
| 334 | virtual void dump() const { print(dbgs()); } |
||
| 335 | #endif |
||
| 336 | |||
| 337 | uint64_t getID() const { |
||
| 338 | return |
||
| 339 | #ifndef NDEBUG |
||
| 340 | ID; |
||
| 341 | #else |
||
| 342 | 0; |
||
| 343 | #endif |
||
| 344 | } |
||
| 345 | }; |
||
| 346 | |||
| 347 | } // end namespace logicalview |
||
| 348 | } // end namespace llvm |
||
| 349 | |||
| 350 | #endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |