| //===-- LVObject.h ----------------------------------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the LVObject class, which is used to describe a debug |
| // information object. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |
| #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |
| |
| #include "llvm/BinaryFormat/Dwarf.h" |
| #include "llvm/DebugInfo/CodeView/CodeView.h" |
| #include "llvm/DebugInfo/CodeView/TypeIndex.h" |
| #include "llvm/DebugInfo/LogicalView/Core/LVSupport.h" |
| #include <limits> |
| #include <list> |
| #include <map> |
| #include <string> |
| |
| namespace llvm { |
| namespace dwarf { |
| // Support for CodeView ModifierOptions::Unaligned. |
| constexpr Tag DW_TAG_unaligned = Tag(dwarf::DW_TAG_hi_user + 1); |
| } // namespace dwarf |
| } // namespace llvm |
| |
| namespace llvm { |
| namespace logicalview { |
| |
| using LVSectionIndex = uint64_t; |
| using LVAddress = uint64_t; |
| using LVHalf = uint16_t; |
| using LVLevel = uint32_t; |
| using LVOffset = uint64_t; |
| using LVSigned = int64_t; |
| using LVUnsigned = uint64_t; |
| using LVSmall = uint8_t; |
| |
| class LVElement; |
| class LVLine; |
| class LVLocation; |
| class LVLocationSymbol; |
| class LVObject; |
| class LVOperation; |
| class LVScope; |
| class LVSymbol; |
| class LVType; |
| |
| class LVOptions; |
| class LVPatterns; |
| |
| StringRef typeNone(); |
| StringRef typeVoid(); |
| StringRef typeInt(); |
| StringRef typeUnknown(); |
| StringRef emptyString(); |
| |
| using LVElementSetFunction = void (LVElement::*)(); |
| using LVElementGetFunction = bool (LVElement::*)() const; |
| using LVLineSetFunction = void (LVLine::*)(); |
| using LVLineGetFunction = bool (LVLine::*)() const; |
| using LVObjectSetFunction = void (LVObject::*)(); |
| using LVObjectGetFunction = bool (LVObject::*)() const; |
| using LVScopeSetFunction = void (LVScope::*)(); |
| using LVScopeGetFunction = bool (LVScope::*)() const; |
| using LVSymbolSetFunction = void (LVSymbol::*)(); |
| using LVSymbolGetFunction = bool (LVSymbol::*)() const; |
| using LVTypeSetFunction = void (LVType::*)(); |
| using LVTypeGetFunction = bool (LVType::*)() const; |
| |
| using LVElements = SmallVector<LVElement *, 8>; |
| using LVLines = SmallVector<LVLine *, 8>; |
| using LVLocations = SmallVector<LVLocation *, 8>; |
| using LVOperations = SmallVector<LVOperation *, 8>; |
| using LVScopes = SmallVector<LVScope *, 8>; |
| using LVSymbols = SmallVector<LVSymbol *, 8>; |
| using LVTypes = SmallVector<LVType *, 8>; |
| |
| using LVOffsets = SmallVector<LVOffset, 8>; |
| |
| const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max(); |
| |
| enum class LVBinaryType { NONE, ELF, COFF }; |
| enum class LVComparePass { Missing, Added }; |
| |
| // Validate functions. |
| using LVValidLocation = bool (LVLocation::*)(); |
| |
| // Keep counters of objects. |
| struct LVCounter { |
| unsigned Lines = 0; |
| unsigned Scopes = 0; |
| unsigned Symbols = 0; |
| unsigned Types = 0; |
| void reset() { |
| Lines = 0; |
| Scopes = 0; |
| Symbols = 0; |
| Types = 0; |
| } |
| }; |
| |
| class LVObject { |
| enum class Property { |
| IsLocation, // Location. |
| IsGlobalReference, // This object is being referenced from another CU. |
| IsGeneratedName, // The Object name was generated. |
| IsResolved, // Object has been resolved. |
| IsResolvedName, // Object name has been resolved. |
| IsDiscarded, // Object has been stripped by the linker. |
| IsOptimized, // Object has been optimized by the compiler. |
| IsAdded, // Object has been 'added'. |
| IsMatched, // Object has been matched to a given pattern. |
| IsMissing, // Object is 'missing'. |
| IsMissingLink, // Object is indirectly 'missing'. |
| IsInCompare, // In 'compare' mode. |
| IsFileFromReference, // File ID from specification. |
| IsLineFromReference, // Line No from specification. |
| HasMoved, // The object was moved from 'target' to 'reference'. |
| HasPattern, // The object has a pattern. |
| IsFinalized, // CodeView object is finalized. |
| IsReferenced, // CodeView object being referenced. |
| HasCodeViewLocation, // CodeView object with debug location. |
| LastEntry |
| }; |
| // Typed bitvector with properties for this object. |
| LVProperties<Property> Properties; |
| |
| LVOffset Offset = 0; |
| uint32_t LineNumber = 0; |
| LVLevel ScopeLevel = 0; |
| union { |
| dwarf::Tag Tag; |
| dwarf::Attribute Attr; |
| LVSmall Opcode; |
| } TagAttrOpcode = {dwarf::DW_TAG_null}; |
| |
| // The parent of this object (nullptr if the root scope). For locations, |
| // the parent is a symbol object; otherwise it is a scope object. |
| union { |
| LVElement *Element; |
| LVScope *Scope; |
| LVSymbol *Symbol; |
| } Parent = {nullptr}; |
| |
| // We do not support any object duplication, as they are created by parsing |
| // the debug information. There is only the case where we need a very basic |
| // object, to manipulate its offset, line number and scope level. Allow the |
| // copy constructor to create that object; it is used to print a reference |
| // to another object and in the case of templates, to print its encoded args. |
| LVObject(const LVObject &Object) { |
| #ifndef NDEBUG |
| incID(); |
| #endif |
| Properties = Object.Properties; |
| Offset = Object.Offset; |
| LineNumber = Object.LineNumber; |
| ScopeLevel = Object.ScopeLevel; |
| TagAttrOpcode = Object.TagAttrOpcode; |
| Parent = Object.Parent; |
| } |
| |
| #ifndef NDEBUG |
| // This is an internal ID used for debugging logical elements. It is used |
| // for cases where an unique offset within the binary input file is not |
| // available. |
| static uint64_t GID; |
| uint64_t ID = 0; |
| |
| void incID() { |
| ++GID; |
| ID = GID; |
| } |
| #endif |
| |
| protected: |
| // Get a string representation for the given number and discriminator. |
| std::string lineAsString(uint32_t LineNumber, LVHalf Discriminator, |
| bool ShowZero) const; |
| |
| // Get a string representation for the given number. |
| std::string referenceAsString(uint32_t LineNumber, bool Spaces) const; |
| |
| // Print the Filename or Pathname. |
| // Empty implementation for those objects that do not have any user |
| // source file references, such as debug locations. |
| virtual void printFileIndex(raw_ostream &OS, bool Full = true) const {} |
| |
| public: |
| LVObject() { |
| #ifndef NDEBUG |
| incID(); |
| #endif |
| }; |
| LVObject &operator=(const LVObject &) = delete; |
| virtual ~LVObject() = default; |
| |
| PROPERTY(Property, IsLocation); |
| PROPERTY(Property, IsGlobalReference); |
| PROPERTY(Property, IsGeneratedName); |
| PROPERTY(Property, IsResolved); |
| PROPERTY(Property, IsResolvedName); |
| PROPERTY(Property, IsDiscarded); |
| PROPERTY(Property, IsOptimized); |
| PROPERTY(Property, IsAdded); |
| PROPERTY(Property, IsMatched); |
| PROPERTY(Property, IsMissing); |
| PROPERTY(Property, IsMissingLink); |
| PROPERTY(Property, IsInCompare); |
| PROPERTY(Property, IsFileFromReference); |
| PROPERTY(Property, IsLineFromReference); |
| PROPERTY(Property, HasMoved); |
| PROPERTY(Property, HasPattern); |
| PROPERTY(Property, IsFinalized); |
| PROPERTY(Property, IsReferenced); |
| PROPERTY(Property, HasCodeViewLocation); |
| |
| // True if the scope has been named or typed or with line number. |
| virtual bool isNamed() const { return false; } |
| virtual bool isTyped() const { return false; } |
| virtual bool isFiled() const { return false; } |
| bool isLined() const { return LineNumber != 0; } |
| |
| // DWARF tag, attribute or expression opcode. |
| dwarf::Tag getTag() const { return TagAttrOpcode.Tag; } |
| void setTag(dwarf::Tag Tag) { TagAttrOpcode.Tag = Tag; } |
| dwarf::Attribute getAttr() const { return TagAttrOpcode.Attr; } |
| void setAttr(dwarf::Attribute Attr) { TagAttrOpcode.Attr = Attr; } |
| LVSmall getOpcode() const { return TagAttrOpcode.Opcode; } |
| void setOpcode(LVSmall Opcode) { TagAttrOpcode.Opcode = Opcode; } |
| |
| // DIE offset. |
| LVOffset getOffset() const { return Offset; } |
| void setOffset(LVOffset DieOffset) { Offset = DieOffset; } |
| |
| // Level where this object is located. |
| LVLevel getLevel() const { return ScopeLevel; } |
| void setLevel(LVLevel Level) { ScopeLevel = Level; } |
| |
| virtual StringRef getName() const { return StringRef(); } |
| virtual void setName(StringRef ObjectName) {} |
| |
| LVElement *getParent() const { |
| assert((!Parent.Element || |
| (Parent.Element && static_cast<LVElement *>(Parent.Element))) && |
| "Invalid element"); |
| return Parent.Element; |
| } |
| LVScope *getParentScope() const { |
| assert((!Parent.Scope || |
| (Parent.Scope && static_cast<LVScope *>(Parent.Scope))) && |
| "Invalid scope"); |
| return Parent.Scope; |
| } |
| LVSymbol *getParentSymbol() const { |
| assert((!Parent.Symbol || |
| (Parent.Symbol && static_cast<LVSymbol *>(Parent.Symbol))) && |
| "Invalid symbol"); |
| return Parent.Symbol; |
| } |
| void setParent(LVScope *Scope); |
| void setParent(LVSymbol *Symbol); |
| void resetParent() { Parent = {nullptr}; } |
| |
| virtual LVAddress getLowerAddress() const { return 0; } |
| virtual void setLowerAddress(LVAddress Address) {} |
| virtual LVAddress getUpperAddress() const { return 0; } |
| virtual void setUpperAddress(LVAddress Address) {} |
| |
| uint32_t getLineNumber() const { return LineNumber; } |
| void setLineNumber(uint32_t Number) { LineNumber = Number; } |
| |
| virtual const char *kind() const { return nullptr; } |
| |
| std::string indentAsString() const; |
| std::string indentAsString(LVLevel Level) const; |
| |
| // String used as padding for printing objects with no line number. |
| virtual std::string noLineAsString(bool ShowZero) const; |
| |
| // Line number for display; in the case of inlined functions, we use the |
| // DW_AT_call_line attribute; otherwise use DW_AT_decl_line attribute. |
| virtual std::string lineNumberAsString(bool ShowZero = false) const { |
| return lineAsString(getLineNumber(), 0, ShowZero); |
| } |
| std::string lineNumberAsStringStripped(bool ShowZero = false) const; |
| |
| // This function prints the logical view to an output stream. |
| // Split: Prints the compilation unit view to a file. |
| // Match: Prints the object only if it satisfies the patterns collected |
| // from the command line. See the '--select' option. |
| // Print: Print the object only if satisfies the conditions specified by |
| // the different '--print' options. |
| // Full: Prints full information for objects representing debug locations, |
| // aggregated scopes, compile unit, functions and namespaces. |
| virtual Error doPrint(bool Split, bool Match, bool Print, raw_ostream &OS, |
| bool Full = true) const; |
| void printAttributes(raw_ostream &OS, bool Full = true) const; |
| void printAttributes(raw_ostream &OS, bool Full, StringRef Name, |
| LVObject *Parent, StringRef Value, |
| bool UseQuotes = false, bool PrintRef = false) const; |
| |
| // Mark branch as missing (current element and parents). |
| void markBranchAsMissing(); |
| |
| // Prints the common information for an object (name, type, etc). |
| virtual void print(raw_ostream &OS, bool Full = true) const; |
| // Prints additional information for an object, depending on its kind |
| // (class attributes, debug ranges, files, directories, etc). |
| virtual void printExtra(raw_ostream &OS, bool Full = true) const {} |
| |
| #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
| virtual void dump() const { print(dbgs()); } |
| #endif |
| |
| uint64_t getID() const { |
| return |
| #ifndef NDEBUG |
| ID; |
| #else |
| 0; |
| #endif |
| } |
| }; |
| |
| } // end namespace logicalview |
| } // end namespace llvm |
| |
| #endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVOBJECT_H |