#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
#include "llvm/DebugInfo/LogicalView/Core/LVStringPool.h"
+#include "llvm/Support/Casting.h"
#include <set>
namespace llvm {
namespace logicalview {
+// RTTI Subclasses ID.
+enum class LVSubclassID : unsigned char {
+ LV_ELEMENT,
+ LV_LINE_FIRST,
+ LV_LINE,
+ LV_LINE_DEBUG,
+ LV_LINE_ASSEMBLER,
+ LV_LINE_LAST,
+ lV_SCOPE_FIRST,
+ LV_SCOPE,
+ LV_SCOPE_AGGREGATE,
+ LV_SCOPE_ALIAS,
+ LV_SCOPE_ARRAY,
+ LV_SCOPE_COMPILE_UNIT,
+ LV_SCOPE_ENUMERATION,
+ LV_SCOPE_FORMAL_PACK,
+ LV_SCOPE_FUNCTION,
+ LV_SCOPE_FUNCTION_INLINED,
+ LV_SCOPE_FUNCTION_TYPE,
+ LV_SCOPE_NAMESPACE,
+ LV_SCOPE_ROOT,
+ LV_SCOPE_TEMPLATE_PACK,
+ LV_SCOPE_LAST,
+ LV_SYMBOL_FIRST,
+ LV_SYMBOL,
+ LV_SYMBOL_LAST,
+ LV_TYPE_FIRST,
+ LV_TYPE,
+ LV_TYPE_DEFINITION,
+ LV_TYPE_ENUMERATOR,
+ LV_TYPE_IMPORT,
+ LV_TYPE_PARAM,
+ LV_TYPE_SUBRANGE,
+ LV_TYPE_LAST
+};
+
enum class LVElementKind { Discarded, Global, Optimized, LastEntry };
using LVElementKindSet = std::set<LVElementKind>;
class LVElement : public LVObject {
+ enum class Property {
+ IsLine, // A logical line.
+ IsScope, // A logical scope.
+ IsSymbol, // A logical symbol.
+ IsType, // A logical type.
+ IsEnumClass,
+ IsExternal,
+ HasType,
+ HasAugmentedName,
+ IsTypedefReduced,
+ IsArrayResolved,
+ IsMemberPointerResolved,
+ IsTemplateResolved,
+ IsInlined,
+ IsInlinedAbstract,
+ InvalidFilename,
+ HasReference,
+ HasReferenceAbstract,
+ HasReferenceExtension,
+ HasReferenceSpecification,
+ QualifiedResolved,
+ IncludeInPrint,
+ IsStatic,
+ TransformName,
+ IsScoped, // CodeView local type.
+ IsNested, // CodeView nested type.
+ IsScopedAlready, // CodeView nested type inserted in correct scope.
+ IsArtificial,
+ IsReferencedType,
+ IsSystem,
+ OffsetFromTypeIndex,
+ IsAnonymous,
+ LastEntry
+ };
+ // Typed bitvector with properties for this element.
+ LVProperties<Property> Properties;
+
+ /// RTTI.
+ const LVSubclassID SubclassID;
+
// Indexes in the String Pool.
size_t NameIndex = 0;
+ size_t QualifiedNameIndex = 0;
size_t FilenameIndex = 0;
+ uint16_t AccessibilityCode : 2; // DW_AT_accessibility.
+ uint16_t InlineCode : 2; // DW_AT_inline.
+ uint16_t VirtualityCode : 2; // DW_AT_virtuality.
+
+ // The given Specification points to an element that is connected via the
+ // DW_AT_specification, DW_AT_abstract_origin or DW_AT_extension attribute.
+ void setFileLine(LVElement *Specification);
+
+ // Get the qualified name that include its parents name.
+ void resolveQualifiedName();
+
+protected:
+ // Type of this element.
+ LVElement *ElementType = nullptr;
+
+ // Print the FileName Index.
+ void printFileIndex(raw_ostream &OS, bool Full = true) const override;
+
public:
- LVElement() = default;
+ LVElement(LVSubclassID ID)
+ : LVObject(), SubclassID(ID), AccessibilityCode(0), InlineCode(0),
+ VirtualityCode(0) {}
+ LVElement(const LVElement &) = delete;
+ LVElement &operator=(const LVElement &) = delete;
virtual ~LVElement() = default;
+ LVSubclassID getSubclassID() const { return SubclassID; }
+
+ PROPERTY(Property, IsLine);
+ PROPERTY(Property, IsScope);
+ PROPERTY(Property, IsSymbol);
+ PROPERTY(Property, IsType);
+ PROPERTY(Property, IsEnumClass);
+ PROPERTY(Property, IsExternal);
+ PROPERTY(Property, HasType);
+ PROPERTY(Property, HasAugmentedName);
+ PROPERTY(Property, IsTypedefReduced);
+ PROPERTY(Property, IsArrayResolved);
+ PROPERTY(Property, IsMemberPointerResolved);
+ PROPERTY(Property, IsTemplateResolved);
+ PROPERTY(Property, IsInlined);
+ PROPERTY(Property, IsInlinedAbstract);
+ PROPERTY(Property, InvalidFilename);
+ PROPERTY(Property, HasReference);
+ PROPERTY(Property, HasReferenceAbstract);
+ PROPERTY(Property, HasReferenceExtension);
+ PROPERTY(Property, HasReferenceSpecification);
+ PROPERTY(Property, QualifiedResolved);
+ PROPERTY(Property, IncludeInPrint);
+ PROPERTY(Property, IsStatic);
+ PROPERTY(Property, TransformName);
+ PROPERTY(Property, IsScoped);
+ PROPERTY(Property, IsNested);
+ PROPERTY(Property, IsScopedAlready);
+ PROPERTY(Property, IsArtificial);
+ PROPERTY(Property, IsReferencedType);
+ PROPERTY(Property, IsSystem);
+ PROPERTY(Property, OffsetFromTypeIndex);
+ PROPERTY(Property, IsAnonymous);
+
bool isNamed() const override { return NameIndex != 0; }
+ bool isTyped() const override { return ElementType != nullptr; }
+ bool isFiled() const override { return FilenameIndex != 0; }
+
+ // The Element class type can point to a Type or Scope.
+ bool getIsKindType() const { return ElementType && ElementType->getIsType(); }
+ bool getIsKindScope() const {
+ return ElementType && ElementType->getIsScope();
+ }
StringRef getName() const override {
return getStringPool().getString(NameIndex);
}
+ void setName(StringRef ElementName) override;
// Get pathname associated with the Element.
StringRef getPathname() const {
return getStringPool().getString(getFilenameIndex());
}
+ // Set filename associated with the Element.
+ void setFilename(StringRef Filename);
+
+ // Set the Element qualified name.
+ void setQualifiedName(StringRef Name) {
+ QualifiedNameIndex = getStringPool().getIndex(Name);
+ }
+ StringRef getQualifiedName() const {
+ return getStringPool().getString(QualifiedNameIndex);
+ }
+
+ size_t getNameIndex() const { return NameIndex; }
+ size_t getQualifiedNameIndex() const { return QualifiedNameIndex; }
+
// Element type name.
StringRef getTypeName() const;
+
+ virtual StringRef getProducer() const { return StringRef(); }
+ virtual void setProducer(StringRef ProducerName) {}
+
+ virtual bool isCompileUnit() const { return false; }
+ virtual bool isRoot() const { return false; }
+
+ virtual void setReference(LVElement *Element) {}
+ virtual void setReference(LVScope *Scope) {}
+ virtual void setReference(LVSymbol *Symbol) {}
+ virtual void setReference(LVType *Type) {}
+
+ virtual void setLinkageName(StringRef LinkageName) {}
+ virtual StringRef getLinkageName() const { return StringRef(); }
+ virtual size_t getLinkageNameIndex() const { return 0; }
+
+ virtual uint32_t getCallLineNumber() const { return 0; }
+ virtual void setCallLineNumber(uint32_t Number) {}
+ virtual size_t getCallFilenameIndex() const { return 0; }
+ virtual void setCallFilenameIndex(size_t Index) {}
size_t getFilenameIndex() const { return FilenameIndex; }
+ void setFilenameIndex(size_t Index) { FilenameIndex = Index; }
+
+ // Set the File location for the Element.
+ void setFile(LVElement *Reference = nullptr);
+
+ virtual bool isBase() const { return false; }
+ virtual bool isTemplateParam() const { return false; }
+
+ virtual uint32_t getBitSize() const { return 0; }
+ virtual void setBitSize(uint32_t Size) {}
+
+ virtual int64_t getCount() const { return 0; }
+ virtual void setCount(int64_t Value) {}
+ virtual int64_t getLowerBound() const { return 0; }
+ virtual void setLowerBound(int64_t Value) {}
+ virtual int64_t getUpperBound() const { return 0; }
+ virtual void setUpperBound(int64_t Value) {}
+ virtual std::pair<unsigned, unsigned> getBounds() const { return {}; }
+ virtual void setBounds(unsigned Lower, unsigned Upper) {}
+
+ // Access DW_AT_GNU_discriminator attribute.
+ virtual uint32_t getDiscriminator() const { return 0; }
+ virtual void setDiscriminator(uint32_t Value) {}
+
+ // Process the values for a DW_TAG_enumerator.
+ virtual std::string getValue() const { return {}; }
+ virtual void setValue(StringRef Value) {}
+ virtual size_t getValueIndex() const { return 0; }
+
+ // DWARF Accessibility Codes.
+ uint32_t getAccessibilityCode() const { return AccessibilityCode; }
+ void setAccessibilityCode(uint32_t Access) { AccessibilityCode = Access; }
+ StringRef
+ accessibilityString(uint32_t Access = dwarf::DW_ACCESS_private) const;
+
+ // DWARF Inline Codes.
+ uint32_t getInlineCode() const { return InlineCode; }
+ void setInlineCode(uint32_t Code) { InlineCode = Code; }
+ StringRef inlineCodeString(uint32_t Code) const;
+
+ // DWARF Virtuality Codes.
+ uint32_t getVirtualityCode() const { return VirtualityCode; }
+ void setVirtualityCode(uint32_t Virtuality) { VirtualityCode = Virtuality; }
+ StringRef
+ virtualityString(uint32_t Virtuality = dwarf::DW_VIRTUALITY_none) const;
+
+ // DWARF Extern Codes.
+ StringRef externalString() const;
+
+ LVElement *getType() const { return ElementType; }
+ LVType *getTypeAsType() const;
+ LVScope *getTypeAsScope() const;
+
+ void setType(LVElement *Element = nullptr) {
+ ElementType = Element;
+ if (Element) {
+ setHasType();
+ Element->setIsReferencedType();
+ }
+ }
+
+ // Set the type for the element, handling template parameters.
+ void setGenericType(LVElement *Element);
+
+ StringRef getTypeQualifiedName() const {
+ return ElementType ? ElementType->getQualifiedName() : "";
+ }
+
+ StringRef typeAsString() const;
+ std::string typeOffsetAsString() const;
+ std::string discriminatorAsString() const;
+
+ LVScope *traverseParents(LVScopeGetFunction GetFunction) const;
+
+ LVScope *getFunctionParent() const;
+ virtual LVScope *getCompileUnitParent() const;
+
+ // Print any referenced element.
+ void printReference(raw_ostream &OS, bool Full, LVElement *Parent) const;
+
+ // Print the linkage name (Symbols and functions).
+ void printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
+ LVScope *Scope) const;
+ void printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent) const;
+
+ // Generate the full name for the Element.
+ void resolveFullname(LVElement *BaseType, StringRef Name = emptyString());
+
+ // Generate a name for unnamed elements.
+ void generateName(std::string &Prefix) const;
+ void generateName();
+
+ virtual bool removeElement(LVElement *Element) { return false; }
+ virtual void updateLevel(LVScope *Parent, bool Moved = false);
+
+ // During the parsing of the debug information, the logical elements are
+ // created with information extracted from its description entries (DIE).
+ // But they are not complete for the logical view concept. A second pass
+ // is executed in order to collect their additional information.
+ // The following functions 'resolve' some of their properties, such as
+ // name, references, parents, extra information based on the element kind.
+ virtual void resolve();
+ virtual void resolveExtra() {}
+ virtual void resolveName();
+ virtual void resolveReferences() {}
+ void resolveParents();
};
} // end namespace logicalview
};
using LVLineKindSet = std::set<LVLineKind>;
+// Class to represent a logical line.
+class LVLine : public LVElement {
+ // Typed bitvector with kinds for this line.
+ LVProperties<LVLineKind> Kinds;
+
+public:
+ LVLine() : LVElement(LVSubclassID::LV_LINE) {
+ setIsLine();
+ setIncludeInPrint();
+ }
+ LVLine(const LVLine &) = delete;
+ LVLine &operator=(const LVLine &) = delete;
+ virtual ~LVLine() = default;
+
+ static bool classof(const LVElement *Element) {
+ return Element->getSubclassID() == LVSubclassID::LV_LINE;
+ }
+
+ KIND(LVLineKind, IsBasicBlock);
+ KIND(LVLineKind, IsDiscriminator);
+ KIND(LVLineKind, IsEndSequence);
+ KIND(LVLineKind, IsEpilogueBegin);
+ KIND(LVLineKind, IsLineDebug);
+ KIND(LVLineKind, IsLineAssembler);
+ KIND(LVLineKind, IsNewStatement);
+ KIND(LVLineKind, IsPrologueEnd);
+ KIND(LVLineKind, IsAlwaysStepInto);
+ KIND(LVLineKind, IsNeverStepInto);
+
+ const char *kind() const override;
+
+ // Use the offset to store the line address.
+ uint64_t getAddress() const { return getOffset(); }
+ void setAddress(uint64_t address) { setOffset(address); }
+
+ // String used for printing objects with no line number.
+ std::string noLineAsString(bool ShowZero = false) const override;
+
+ // 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.
+ std::string lineNumberAsString(bool ShowZero = false) const override {
+ return lineAsString(getLineNumber(), getDiscriminator(), ShowZero);
+ }
+
+ void print(raw_ostream &OS, bool Full = true) const override;
+ void printExtra(raw_ostream &OS, bool Full = true) const override {}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const override { print(dbgs()); }
+#endif
+};
+
+// Class to represent a DWARF line record object.
+class LVLineDebug final : public LVLine {
+ // Discriminator value (DW_LNE_set_discriminator). The DWARF standard
+ // defines the discriminator as an unsigned LEB128 integer.
+ uint32_t Discriminator = 0;
+
+public:
+ LVLineDebug() : LVLine() { setIsLineDebug(); }
+ LVLineDebug(const LVLineDebug &) = delete;
+ LVLineDebug &operator=(const LVLineDebug &) = delete;
+ ~LVLineDebug() = default;
+
+ // Additional line information. It includes attributes that describes
+ // states in the machine instructions (basic block, end prologue, etc).
+ std::string statesInfo(bool Formatted) const;
+
+ // Access DW_LNE_set_discriminator attribute.
+ uint32_t getDiscriminator() const override { return Discriminator; }
+ void setDiscriminator(uint32_t Value) override {
+ Discriminator = Value;
+ setIsDiscriminator();
+ }
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent an assembler line extracted from the text section.
+class LVLineAssembler final : public LVLine {
+public:
+ LVLineAssembler() : LVLine() { setIsLineAssembler(); }
+ LVLineAssembler(const LVLineAssembler &) = delete;
+ LVLineAssembler &operator=(const LVLineAssembler &) = delete;
+ ~LVLineAssembler() = default;
+
+ // Print blanks as the line number.
+ std::string noLineAsString(bool ShowZero) const override {
+ return std::string(8, ' ');
+ };
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
} // end namespace logicalview
} // end namespace llvm
#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 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;
+
+// The LVScope class represents a logical scope and uses vectors to store its
+// children, which are pointers to other allocated logical elements (types,
+// symbols, lines, scopes, ranges). On destruction, we have to traverse each
+// vector and destroy its elements. The other case is LVSymbol.
+// These definitions are intended to be used by the LVScope and LVSymbol
+// to support automatic vector cleanup.
+using LVAutoLines = LVAutoSmallVector<LVLine *>;
+using LVAutoLocations = LVAutoSmallVector<LVLocation *>;
+using LVAutoOperations = LVAutoSmallVector<LVOperation *, 8>;
+using LVAutoScopes = LVAutoSmallVector<LVScope *>;
+using LVAutoSymbols = LVAutoSmallVector<LVSymbol *>;
+using LVAutoTypes = LVAutoSmallVector<LVType *>;
+
+// These definitions are intended to be used when the vector will be used
+// just a container, with no automatic destruction.
+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 };
+
+// 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) {
+ Properties = Object.Properties;
+ Offset = Object.Offset;
+ LineNumber = Object.LineNumber;
+ ScopeLevel = Object.ScopeLevel;
+ TagAttrOpcode = Object.TagAttrOpcode;
+ Parent = Object.Parent;
+ }
protected:
// Get a string representation for the given number and discriminator.
public:
LVObject() = default;
+ LVObject &operator=(const LVObject &) = delete;
virtual ~LVObject() = default;
- // True if the scope has been named.
+ 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}; }
+
+ 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;
+
+ // 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
};
} // end namespace logicalview
--- /dev/null
+//===-- LVReader.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 LVReader class, which is used to describe a debug
+// information reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include <map>
+
+namespace llvm {
+namespace logicalview {
+
+class LVScopeCompileUnit;
+class LVObject;
+
+class LVSplitContext final {
+ std::unique_ptr<ToolOutputFile> OutputFile;
+ std::string Location;
+
+public:
+ LVSplitContext() = default;
+ LVSplitContext(const LVSplitContext &) = delete;
+ LVSplitContext &operator=(const LVSplitContext &) = delete;
+ ~LVSplitContext() = default;
+
+ Error createSplitFolder(StringRef Where);
+ std::error_code open(std::string Name, std::string Extension,
+ raw_ostream &OS);
+ void close() {
+ if (OutputFile) {
+ OutputFile->os().close();
+ OutputFile = nullptr;
+ }
+ }
+
+ std::string getLocation() const { return Location; }
+ raw_fd_ostream &os() { return OutputFile->os(); }
+};
+
+class LVReader {
+ LVBinaryType BinaryType;
+
+ // Context used by '--output=split' command line option.
+ LVSplitContext SplitContext;
+
+ // Compile Units DIE Offset => Scope.
+ using LVCompileUnits = std::map<LVOffset, LVScopeCompileUnit *>;
+ LVCompileUnits CompileUnits;
+
+ // Create split folder.
+ Error createSplitFolder();
+ bool OutputSplit = false;
+
+protected:
+ LVScopeRoot *Root = nullptr;
+ std::string InputFilename;
+ std::string FileFormatName;
+ ScopedPrinter &W;
+ raw_ostream &OS;
+ LVScopeCompileUnit *CompileUnit = nullptr;
+
+ // Record Compilation Unit entry.
+ void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) {
+ CompileUnits.emplace(Offset, CompileUnit);
+ }
+
+ // Create the Scope Root.
+ virtual Error createScopes() {
+ Root = new LVScopeRoot();
+ Root->setName(getFilename());
+ if (options().getAttributeFormat())
+ Root->setFileFormatName(FileFormatName);
+ return Error::success();
+ }
+
+ virtual Error printScopes();
+ virtual Error printMatchedElements(bool UseMatchedElements);
+ virtual void sortScopes() {}
+
+public:
+ LVReader() = delete;
+ LVReader(StringRef InputFilename, StringRef FileFormatName, ScopedPrinter &W,
+ LVBinaryType BinaryType = LVBinaryType::NONE)
+ : BinaryType(BinaryType), OutputSplit(options().getOutputSplit()),
+ InputFilename(InputFilename), FileFormatName(FileFormatName), W(W),
+ OS(W.getOStream()) {}
+ LVReader(const LVReader &) = delete;
+ LVReader &operator=(const LVReader &) = delete;
+ virtual ~LVReader() {
+ if (Root)
+ delete Root;
+ }
+
+ StringRef getFilename(LVObject *Object, size_t Index) const;
+ StringRef getFilename() const { return InputFilename; }
+ void setFilename(std::string Name) { InputFilename = std::move(Name); }
+ StringRef getFileFormatName() const { return FileFormatName; }
+
+ raw_ostream &outputStream() { return OS; }
+
+ bool isBinaryTypeNone() const { return BinaryType == LVBinaryType::NONE; }
+ bool isBinaryTypeELF() const { return BinaryType == LVBinaryType::ELF; }
+ bool isBinaryTypeCOFF() const { return BinaryType == LVBinaryType::COFF; }
+
+ LVScopeCompileUnit *getCompileUnit() const { return CompileUnit; }
+ void setCompileUnit(LVScope *Scope) {
+ assert(Scope && Scope->isCompileUnit() && "Scope is not a compile unit");
+ CompileUnit = static_cast<LVScopeCompileUnit *>(Scope);
+ }
+
+ // Access to the scopes root.
+ LVScopeRoot *getScopesRoot() const { return Root; }
+
+ Error doPrint();
+ Error doLoad();
+
+ virtual bool isSystemEntry(LVElement *Element, StringRef Name = {}) {
+ return false;
+ };
+
+ // Access to split context.
+ LVSplitContext &getSplitContext() { return SplitContext; }
+
+ // Conditions to print an object.
+ bool doPrintLine(const LVLine *Line) const { return true; }
+ bool doPrintScope(const LVScope *Scope) const { return true; }
+ bool doPrintSymbol(const LVSymbol *Symbol) const { return true; }
+ bool doPrintType(const LVType *Type) const { return true; }
+
+ static LVReader &getInstance();
+ static void setInstance(LVReader *Reader);
+
+ void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const { print(dbgs()); }
+#endif
+};
+
+inline LVReader &getReader() { return LVReader::getInstance(); }
+inline LVSplitContext &getReaderSplitContext() {
+ return getReader().getSplitContext();
+}
+inline LVScopeCompileUnit *getReaderCompileUnit() {
+ return getReader().getCompileUnit();
+}
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H
#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
#include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
+#include <map>
#include <set>
namespace llvm {
};
using LVScopeKindSet = std::set<LVScopeKind>;
+using LVOffsetElementMap = std::map<LVOffset, LVElement *>;
+
+// Class to represent a DWARF Scope.
+class LVScope : public LVElement {
+ enum class Property {
+ HasDiscriminator,
+ CanHaveRanges,
+ CanHaveLines,
+ HasGlobals,
+ HasLocals,
+ HasLines,
+ HasScopes,
+ HasSymbols,
+ HasTypes,
+ IsComdat,
+ HasComdatScopes, // Compile Unit has comdat functions.
+ HasRanges,
+ AddedMissing, // Added missing referenced symbols.
+ LastEntry
+ };
+
+ // Typed bitvector with kinds and properties for this scope.
+ LVProperties<LVScopeKind> Kinds;
+ LVProperties<Property> Properties;
+
+ // Decide if the scope will be printed, using some conditions given by:
+ // only-globals, only-locals, a-pattern.
+ bool resolvePrinting() const;
+
+ // Traverse the scope parent tree, executing the given callback function
+ // on each scope.
+ void traverseParents(LVScopeGetFunction GetFunction,
+ LVScopeSetFunction SetFunction);
+
+protected:
+ // Types, Symbols, Scopes, Lines in this scope.
+ LVAutoTypes *Types = nullptr;
+ LVAutoSymbols *Symbols = nullptr;
+ LVAutoScopes *Scopes = nullptr;
+ LVAutoLines *Lines = nullptr;
+
+ // Vector of elements (types, scopes and symbols).
+ // It is the union of (*Types, *Symbols and *Scopes) to be used for
+ // the following reasons:
+ // - Preserve the order the logical elements are read in.
+ // - To have a single container with all the logical elements, when
+ // the traversal does not require any specific element kind.
+ LVElements *Children = nullptr;
+
+ // Resolve the template parameters/arguments relationship.
+ void resolveTemplate();
+ void printEncodedArgs(raw_ostream &OS, bool Full) const;
+
+ virtual void printSizes(raw_ostream &OS) const {}
+ virtual void printSummary(raw_ostream &OS) const {}
+
+ // Encoded template arguments.
+ virtual StringRef getEncodedArgs() const { return StringRef(); }
+ virtual void setEncodedArgs(StringRef EncodedArgs) {}
+
+public:
+ LVScope() : LVElement(LVSubclassID::LV_SCOPE) {
+ setIsScope();
+ setIncludeInPrint();
+ }
+ LVScope(const LVScope &) = delete;
+ LVScope &operator=(const LVScope &) = delete;
+ virtual ~LVScope();
+
+ static bool classof(const LVElement *Element) {
+ return Element->getSubclassID() == LVSubclassID::LV_SCOPE;
+ }
+
+ KIND(LVScopeKind, IsAggregate);
+ KIND(LVScopeKind, IsArray);
+ KIND_2(LVScopeKind, IsBlock, CanHaveRanges, CanHaveLines);
+ KIND_1(LVScopeKind, IsCallSite, IsFunction);
+ KIND_1(LVScopeKind, IsCatchBlock, IsBlock);
+ KIND_1(LVScopeKind, IsClass, IsAggregate);
+ KIND_3(LVScopeKind, IsCompileUnit, CanHaveRanges, CanHaveLines,
+ TransformName);
+ KIND_1(LVScopeKind, IsEntryPoint, IsFunction);
+ KIND(LVScopeKind, IsEnumeration);
+ KIND_2(LVScopeKind, IsFunction, CanHaveRanges, CanHaveLines);
+ KIND_1(LVScopeKind, IsFunctionType, IsFunction);
+ KIND_2(LVScopeKind, IsInlinedFunction, IsFunction, IsInlined);
+ KIND_1(LVScopeKind, IsLabel, IsFunction);
+ KIND_1(LVScopeKind, IsLexicalBlock, IsBlock);
+ KIND(LVScopeKind, IsMember);
+ KIND(LVScopeKind, IsNamespace);
+ KIND_1(LVScopeKind, IsRoot, TransformName);
+ KIND_1(LVScopeKind, IsStructure, IsAggregate);
+ KIND_1(LVScopeKind, IsSubprogram, IsFunction);
+ KIND(LVScopeKind, IsTemplate);
+ KIND(LVScopeKind, IsTemplateAlias);
+ KIND(LVScopeKind, IsTemplatePack);
+ KIND_1(LVScopeKind, IsTryBlock, IsBlock);
+ KIND_1(LVScopeKind, IsUnion, IsAggregate);
+
+ PROPERTY(Property, HasDiscriminator);
+ PROPERTY(Property, CanHaveRanges);
+ PROPERTY(Property, CanHaveLines);
+ PROPERTY(Property, HasGlobals);
+ PROPERTY(Property, HasLocals);
+ PROPERTY(Property, HasLines);
+ PROPERTY(Property, HasScopes);
+ PROPERTY(Property, HasSymbols);
+ PROPERTY(Property, HasTypes);
+ PROPERTY(Property, IsComdat);
+ PROPERTY(Property, HasComdatScopes);
+ PROPERTY(Property, HasRanges);
+ PROPERTY(Property, AddedMissing);
+
+ bool isCompileUnit() const override { return getIsCompileUnit(); }
+ bool isRoot() const override { return getIsRoot(); }
+
+ const char *kind() const override;
+
+ // Get the specific children.
+ const LVLines *getLines() const { return Lines; }
+ const LVScopes *getScopes() const { return Scopes; }
+ const LVSymbols *getSymbols() const { return Symbols; }
+ const LVTypes *getTypes() const { return Types; }
+ const LVElements *getChildren() const { return Children; }
+
+ void addElement(LVElement *Element);
+ void addElement(LVLine *Line);
+ void addElement(LVScope *Scope);
+ void addElement(LVSymbol *Symbol);
+ void addElement(LVType *Type);
+ void addToChildren(LVElement *Element);
+
+ // Add the missing elements from the given 'Reference', which is the
+ // scope associated with any DW_AT_specification, DW_AT_abstract_origin.
+ void addMissingElements(LVScope *Reference);
+
+ // Traverse the scope parent tree and the children, executing the given
+ // callback function on each element.
+ void traverseParentsAndChildren(LVObjectGetFunction GetFunction,
+ LVObjectSetFunction SetFunction);
+
+ // Get the size of specific children.
+ size_t lineCount() const { return Lines ? Lines->size() : 0; }
+ size_t scopeCount() const { return Scopes ? Scopes->size() : 0; }
+ size_t symbolCount() const { return Symbols ? Symbols->size() : 0; }
+ size_t typeCount() const { return Types ? Types->size() : 0; }
+
+ Error doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
+ bool Full = true) const override;
+ // Sort the logical elements using the criteria specified by the
+ // command line option '--output-sort'.
+ void sort();
+
+ // Get template parameter types.
+ bool getTemplateParameterTypes(LVTypes &Params);
+
+ // DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension.
+ virtual LVScope *getReference() const { return nullptr; }
+
+ // Follow a chain of references given by DW_AT_abstract_origin and/or
+ // DW_AT_specification and update the scope name.
+ StringRef resolveReferencesChain();
+
+ bool removeElement(LVElement *Element) override;
+ void updateLevel(LVScope *Parent, bool Moved) override;
+
+ void resolve() override;
+ void resolveName() override;
+ void resolveReferences() override;
+
+ // Return the chain of parents as a string.
+ void getQualifiedName(std::string &QualifiedName) const;
+ // Encode the template arguments.
+ void encodeTemplateArguments(std::string &Name) const;
+ void encodeTemplateArguments(std::string &Name, const LVTypes *Types) const;
+
+ void resolveElements();
+
+ void print(raw_ostream &OS, bool Full = true) const override;
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+ virtual void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) {}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const override { print(dbgs()); }
+#endif
+};
+
+// Class to represent a DWARF Union/Structure/Class.
+class LVScopeAggregate final : public LVScope {
+ LVScope *Reference = nullptr; // DW_AT_specification, DW_AT_abstract_origin.
+ size_t EncodedArgsIndex = 0; // Template encoded arguments.
+
+public:
+ LVScopeAggregate() : LVScope() {}
+ LVScopeAggregate(const LVScopeAggregate &) = delete;
+ LVScopeAggregate &operator=(const LVScopeAggregate &) = delete;
+ ~LVScopeAggregate() = default;
+
+ // DW_AT_specification, DW_AT_abstract_origin.
+ LVScope *getReference() const override { return Reference; }
+ void setReference(LVScope *Scope) override {
+ Reference = Scope;
+ setHasReference();
+ }
+ void setReference(LVElement *Element) override {
+ setReference(static_cast<LVScope *>(Element));
+ }
+
+ StringRef getEncodedArgs() const override {
+ return getStringPool().getString(EncodedArgsIndex);
+ }
+ void setEncodedArgs(StringRef EncodedArgs) override {
+ EncodedArgsIndex = getStringPool().getIndex(EncodedArgs);
+ }
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF Template alias.
+class LVScopeAlias final : public LVScope {
+public:
+ LVScopeAlias() : LVScope() {
+ setIsTemplateAlias();
+ setIsTemplate();
+ }
+ LVScopeAlias(const LVScopeAlias &) = delete;
+ LVScopeAlias &operator=(const LVScopeAlias &) = delete;
+ ~LVScopeAlias() = default;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF array (DW_TAG_array_type).
+class LVScopeArray final : public LVScope {
+public:
+ LVScopeArray() : LVScope() { setIsArray(); }
+ LVScopeArray(const LVScopeArray &) = delete;
+ LVScopeArray &operator=(const LVScopeArray &) = delete;
+ ~LVScopeArray() = default;
+
+ void resolveExtra() override;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF Compilation Unit (CU).
+class LVScopeCompileUnit final : public LVScope {
+ // Names (files and directories) used by the Compile Unit.
+ std::vector<size_t> Filenames;
+
+ // Toolchain producer.
+ size_t ProducerIndex = 0;
+
+ // Compilation directory name.
+ size_t CompilationDirectoryIndex = 0;
+
+ // Keep record of elements. They are needed at the compilation unit level
+ // to print the summary at the end of the printing.
+ LVCounter Allocated;
+ LVCounter Found;
+ LVCounter Printed;
+
+ // Elements that match a given command line pattern.
+ LVElements MatchedElements;
+ LVScopes MatchedScopes;
+
+ // It records the mapping between logical lines representing a debug line
+ // entry and its address in the text section. It is used to find a line
+ // giving its exact or closest address.
+ using LVAddressToLine = std::map<LVAddress, LVLine *>;
+ LVAddressToLine AddressToLine;
+
+ // Record scopes contribution in bytes to the debug information.
+ using LVSizesMap = std::map<const LVScope *, LVOffset>;
+ LVSizesMap Sizes;
+ LVOffset CUContributionSize = 0;
+
+ // Record scope sizes indexed by lexical level.
+ // Setting an initial size that will cover a very deep nested scopes.
+ const size_t TotalInitialSize = 8;
+ using LVTotalsEntry = std::pair<unsigned, float>;
+ SmallVector<LVTotalsEntry> Totals;
+ // Maximum seen lexical level. It is used to control how many entries
+ // in the 'Totals' vector are valid values.
+ LVLevel MaxSeenLevel = 0;
+
+ void printScopeSize(const LVScope *Scope, raw_ostream &OS);
+ void printScopeSize(const LVScope *Scope, raw_ostream &OS) const {
+ (const_cast<LVScopeCompileUnit *>(this))->printScopeSize(Scope, OS);
+ }
+ void printTotals(raw_ostream &OS) const;
+
+protected:
+ void printSizes(raw_ostream &OS) const override;
+ void printSummary(raw_ostream &OS) const override;
+
+public:
+ LVScopeCompileUnit() : LVScope(), Totals(TotalInitialSize, {0, 0.0}) {
+ setIsCompileUnit();
+ }
+ LVScopeCompileUnit(const LVScopeCompileUnit &) = delete;
+ LVScopeCompileUnit &operator=(const LVScopeCompileUnit &) = delete;
+ ~LVScopeCompileUnit() = default;
+
+ // Get the line located at the given address.
+ LVLine *lineLowerBound(LVAddress Address) const;
+ LVLine *lineUpperBound(LVAddress Address) const;
+
+ StringRef getCompilationDirectory() const {
+ return getStringPool().getString(CompilationDirectoryIndex);
+ }
+ void setCompilationDirectory(StringRef CompilationDirectory) {
+ CompilationDirectoryIndex = getStringPool().getIndex(CompilationDirectory);
+ }
+
+ StringRef getFilename(size_t Index) const;
+ void addFilename(StringRef Name) {
+ Filenames.push_back(getStringPool().getIndex(Name));
+ }
+
+ StringRef getProducer() const override {
+ return getStringPool().getString(ProducerIndex);
+ }
+ void setProducer(StringRef ProducerName) override {
+ ProducerIndex = getStringPool().getIndex(ProducerName);
+ }
+
+ void printLocalNames(raw_ostream &OS, bool Full = true) const;
+ void printSummary(raw_ostream &OS, const LVCounter &Counter,
+ const char *Header) const;
+
+ void incrementPrintedLines();
+ void incrementPrintedScopes();
+ void incrementPrintedSymbols();
+ void incrementPrintedTypes();
+
+ // Values are used by '--summary' option (allocated).
+ void increment(LVLine *Line);
+ void increment(LVScope *Scope);
+ void increment(LVSymbol *Symbol);
+ void increment(LVType *Type);
+
+ // A new element has been added to the scopes tree. Take the following steps:
+ // Increase the added element counters, for printing summary.
+ // Notify the Reader if element comparison.
+ void addedElement(LVLine *Line);
+ void addedElement(LVScope *Scope);
+ void addedElement(LVSymbol *Symbol);
+ void addedElement(LVType *Type);
+
+ void addSize(LVScope *Scope, LVOffset Lower, LVOffset Upper);
+
+ void print(raw_ostream &OS, bool Full = true) const override;
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+ void printMatchedElements(raw_ostream &OS, bool UseMatchedElements) override;
+};
+
+// Class to represent a DWARF enumerator (DW_TAG_enumeration_type).
+class LVScopeEnumeration final : public LVScope {
+public:
+ LVScopeEnumeration() : LVScope() { setIsEnumeration(); }
+ LVScopeEnumeration(const LVScopeEnumeration &) = delete;
+ LVScopeEnumeration &operator=(const LVScopeEnumeration &) = delete;
+ ~LVScopeEnumeration() = default;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF formal parameter pack
+// (DW_TAG_GNU_formal_parameter_pack).
+class LVScopeFormalPack final : public LVScope {
+public:
+ LVScopeFormalPack() : LVScope() { setIsTemplatePack(); }
+ LVScopeFormalPack(const LVScopeFormalPack &) = delete;
+ LVScopeFormalPack &operator=(const LVScopeFormalPack &) = delete;
+ ~LVScopeFormalPack() = default;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF Function.
+class LVScopeFunction : public LVScope {
+ LVScope *Reference = nullptr; // DW_AT_specification, DW_AT_abstract_origin.
+ size_t LinkageNameIndex = 0; // Function DW_AT_linkage_name attribute.
+ size_t EncodedArgsIndex = 0; // Template encoded arguments.
+
+public:
+ LVScopeFunction() : LVScope() {}
+ LVScopeFunction(const LVScopeFunction &) = delete;
+ LVScopeFunction &operator=(const LVScopeFunction &) = delete;
+ virtual ~LVScopeFunction() = default;
+
+ // DW_AT_specification, DW_AT_abstract_origin.
+ LVScope *getReference() const override { return Reference; }
+ void setReference(LVScope *Scope) override {
+ Reference = Scope;
+ setHasReference();
+ }
+ void setReference(LVElement *Element) override {
+ setReference(static_cast<LVScope *>(Element));
+ }
+
+ StringRef getEncodedArgs() const override {
+ return getStringPool().getString(EncodedArgsIndex);
+ }
+ void setEncodedArgs(StringRef EncodedArgs) override {
+ EncodedArgsIndex = getStringPool().getIndex(EncodedArgs);
+ }
+
+ void setLinkageName(StringRef LinkageName) override {
+ LinkageNameIndex = getStringPool().getIndex(LinkageName);
+ }
+ StringRef getLinkageName() const override {
+ return getStringPool().getString(LinkageNameIndex);
+ }
+ size_t getLinkageNameIndex() const override { return LinkageNameIndex; }
+
+ void setName(StringRef ObjectName) override;
+
+ void resolveExtra() override;
+ void resolveReferences() override;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF inlined function.
+class LVScopeFunctionInlined final : public LVScopeFunction {
+ size_t CallFilenameIndex = 0;
+ uint32_t CallLineNumber = 0;
+ uint32_t Discriminator = 0;
+
+public:
+ LVScopeFunctionInlined() : LVScopeFunction() { setIsInlinedFunction(); }
+ LVScopeFunctionInlined(const LVScopeFunctionInlined &) = delete;
+ LVScopeFunctionInlined &operator=(const LVScopeFunctionInlined &) = delete;
+ ~LVScopeFunctionInlined() = default;
+
+ uint32_t getDiscriminator() const override { return Discriminator; }
+ void setDiscriminator(uint32_t Value) override {
+ Discriminator = Value;
+ setHasDiscriminator();
+ }
+
+ uint32_t getCallLineNumber() const override { return CallLineNumber; }
+ void setCallLineNumber(uint32_t Number) override { CallLineNumber = Number; }
+ size_t getCallFilenameIndex() const override { return CallFilenameIndex; }
+ void setCallFilenameIndex(size_t Index) override {
+ CallFilenameIndex = Index;
+ }
+
+ // 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.
+ std::string lineNumberAsString(bool ShowZero = false) const override {
+ return lineAsString(getCallLineNumber(), getDiscriminator(), ShowZero);
+ }
+
+ void resolveExtra() override;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF subroutine type.
+class LVScopeFunctionType final : public LVScopeFunction {
+public:
+ LVScopeFunctionType() : LVScopeFunction() { setIsFunctionType(); }
+ LVScopeFunctionType(const LVScopeFunctionType &) = delete;
+ LVScopeFunctionType &operator=(const LVScopeFunctionType &) = delete;
+ ~LVScopeFunctionType() = default;
+
+ void resolveExtra() override;
+};
+
+// Class to represent a DWARF Namespace.
+class LVScopeNamespace final : public LVScope {
+ LVScope *Reference = nullptr; // Reference to DW_AT_extension attribute.
+
+public:
+ LVScopeNamespace() : LVScope() { setIsNamespace(); }
+ LVScopeNamespace(const LVScopeNamespace &) = delete;
+ LVScopeNamespace &operator=(const LVScopeNamespace &) = delete;
+ ~LVScopeNamespace() = default;
+
+ // Access DW_AT_extension reference.
+ LVScope *getReference() const override { return Reference; }
+ void setReference(LVScope *Scope) override {
+ Reference = Scope;
+ setHasReference();
+ }
+ void setReference(LVElement *Element) override {
+ setReference(static_cast<LVScope *>(Element));
+ }
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent the binary file being analyzed.
+class LVScopeRoot final : public LVScope {
+ size_t FileFormatNameIndex = 0;
+
+public:
+ LVScopeRoot() : LVScope() { setIsRoot(); }
+ LVScopeRoot(const LVScopeRoot &) = delete;
+ LVScopeRoot &operator=(const LVScopeRoot &) = delete;
+ ~LVScopeRoot() = default;
+
+ StringRef getFileFormatName() const {
+ return getStringPool().getString(FileFormatNameIndex);
+ }
+ void setFileFormatName(StringRef FileFormatName) {
+ FileFormatNameIndex = getStringPool().getIndex(FileFormatName);
+ }
+
+ void print(raw_ostream &OS, bool Full = true) const override;
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+ Error doPrintMatches(bool Split, raw_ostream &OS,
+ bool UseMatchedElements) const;
+};
+
+// Class to represent a DWARF template parameter pack
+// (DW_TAG_GNU_template_parameter_pack).
+class LVScopeTemplatePack final : public LVScope {
+public:
+ LVScopeTemplatePack() : LVScope() { setIsTemplatePack(); }
+ LVScopeTemplatePack(const LVScopeTemplatePack &) = delete;
+ LVScopeTemplatePack &operator=(const LVScopeTemplatePack &) = delete;
+ ~LVScopeTemplatePack() = default;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
} // end namespace logicalview
} // end namespace llvm
namespace llvm {
namespace logicalview {
+class LVObject;
+
// Object Sorting Mode.
enum class LVSortMode {
None = 0, // No given sort.
Offset // Sort by offset.
};
+// Type of function to be called when sorting an object.
+using LVSortValue = int;
+using LVSortFunction = LVSortValue (*)(const LVObject *LHS,
+ const LVObject *RHS);
+
+// Get the comparator function, based on the command line options.
+LVSortFunction getSortFunction();
+
+// Comparator functions that can be used for sorting.
+LVSortValue compareKind(const LVObject *LHS, const LVObject *RHS);
+LVSortValue compareLine(const LVObject *LHS, const LVObject *RHS);
+LVSortValue compareName(const LVObject *LHS, const LVObject *RHS);
+LVSortValue compareOffset(const LVObject *LHS, const LVObject *RHS);
+LVSortValue sortByKind(const LVObject *LHS, const LVObject *RHS);
+LVSortValue sortByLine(const LVObject *LHS, const LVObject *RHS);
+LVSortValue sortByName(const LVObject *LHS, const LVObject *RHS);
+
} // end namespace logicalview
} // end namespace llvm
namespace llvm {
namespace logicalview {
+template <typename T>
+using TypeIsValid = std::bool_constant<std::is_pointer<T>::value>;
+
+// Utility class to help memory management and perform an automatic cleaning.
+template <typename T, unsigned N = 8>
+class LVAutoSmallVector : public SmallVector<T, N> {
+ static_assert(TypeIsValid<T>::value, "T must be a pointer type");
+
+public:
+ using iterator = typename SmallVector<T, N>::iterator;
+ LVAutoSmallVector() : SmallVector<T, N>::SmallVector() {}
+
+ ~LVAutoSmallVector() {
+ // Destroy the constructed elements in the vector.
+ for (auto *Item : *this)
+ delete Item;
+ }
+};
+
+// Used to record specific characteristics about the objects.
+template <typename T> class LVProperties {
+ SmallBitVector Bits = SmallBitVector(static_cast<unsigned>(T::LastEntry) + 1);
+
+public:
+ LVProperties() = default;
+
+ void set(T Idx) { Bits[static_cast<unsigned>(Idx)] = 1; }
+ void reset(T Idx) { Bits[static_cast<unsigned>(Idx)] = 0; }
+ bool get(T Idx) const { return Bits[static_cast<unsigned>(Idx)]; }
+};
+
+// Generate get, set and reset 'bool' functions for LVProperties instances.
+// FAMILY: instance name.
+// ENUM: enumeration instance.
+// FIELD: enumerator instance.
+// F1, F2, F3: optional 'set' functions to be called.
+#define BOOL_BIT(FAMILY, ENUM, FIELD) \
+ bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \
+ void set##FIELD() { FAMILY.set(ENUM::FIELD); } \
+ void reset##FIELD() { FAMILY.reset(ENUM::FIELD); }
+
+#define BOOL_BIT_1(FAMILY, ENUM, FIELD, F1) \
+ bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \
+ void set##FIELD() { \
+ FAMILY.set(ENUM::FIELD); \
+ set##F1(); \
+ } \
+ void reset##FIELD() { FAMILY.reset(ENUM::FIELD); }
+
+#define BOOL_BIT_2(FAMILY, ENUM, FIELD, F1, F2) \
+ bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \
+ void set##FIELD() { \
+ FAMILY.set(ENUM::FIELD); \
+ set##F1(); \
+ set##F2(); \
+ } \
+ void reset##FIELD() { FAMILY.reset(ENUM::FIELD); }
+
+#define BOOL_BIT_3(FAMILY, ENUM, FIELD, F1, F2, F3) \
+ bool get##FIELD() const { return FAMILY.get(ENUM::FIELD); } \
+ void set##FIELD() { \
+ FAMILY.set(ENUM::FIELD); \
+ set##F1(); \
+ set##F2(); \
+ set##F3(); \
+ } \
+ void reset##FIELD() { FAMILY.reset(ENUM::FIELD); }
+
+// Generate get, set and reset functions for 'properties'.
+#define PROPERTY(ENUM, FIELD) BOOL_BIT(Properties, ENUM, FIELD)
+#define PROPERTY_1(ENUM, FIELD, F1) BOOL_BIT_1(Properties, ENUM, FIELD, F1)
+#define PROPERTY_2(ENUM, FIELD, F1, F2) \
+ BOOL_BIT_2(Properties, ENUM, FIELD, F1, F2)
+#define PROPERTY_3(ENUM, FIELD, F1, F2, F3) \
+ BOOL_BIT_3(Properties, ENUM, FIELD, F1, F2, F3)
+
+// Generate get, set and reset functions for 'kinds'.
+#define KIND(ENUM, FIELD) BOOL_BIT(Kinds, ENUM, FIELD)
+#define KIND_1(ENUM, FIELD, F1) BOOL_BIT_1(Kinds, ENUM, FIELD, F1)
+#define KIND_2(ENUM, FIELD, F1, F2) BOOL_BIT_2(Kinds, ENUM, FIELD, F1, F2)
+#define KIND_3(ENUM, FIELD, F1, F2, F3) \
+ BOOL_BIT_3(Kinds, ENUM, FIELD, F1, F2, F3)
+
const int HEX_WIDTH = 12;
inline FormattedNumber hexValue(uint64_t N, unsigned Width = HEX_WIDTH,
bool Upper = false) {
return (Twine("[") + Twine(hexString(Value)) + Twine("]")).str();
}
+// Return a string with the First and Others separated by spaces.
+template <typename... Args>
+std::string formatAttributes(const StringRef First, Args... Others) {
+ const auto List = {First, Others...};
+ std::stringstream Stream;
+ size_t Size = 0;
+ for (const StringRef &Item : List) {
+ Stream << (Size ? " " : "") << Item.str();
+ Size = Item.size();
+ }
+ Stream << (Size ? " " : "");
+ return Stream.str();
+}
+
+// Unified and flattened pathnames.
+std::string transformPath(StringRef Path);
+std::string flattenedFilePath(StringRef Path);
+
+inline std::string formattedKind(StringRef Kind) {
+ return (Twine("{") + Twine(Kind) + Twine("}")).str();
+}
+
+inline std::string formattedName(StringRef Name) {
+ return (Twine("'") + Twine(Name) + Twine("'")).str();
+}
+
+inline std::string formattedNames(StringRef Name1, StringRef Name2) {
+ return (Twine("'") + Twine(Name1) + Twine(Name2) + Twine("'")).str();
+}
+
} // end namespace logicalview
} // end namespace llvm
};
using LVSymbolKindSet = std::set<LVSymbolKind>;
+class LVSymbol final : public LVElement {
+ enum class Property { HasLocation, FillGaps, LastEntry };
+
+ // Typed bitvector with kinds and properties for this symbol.
+ LVProperties<LVSymbolKind> Kinds;
+ LVProperties<Property> Properties;
+
+ // CodeView symbol Linkage name.
+ size_t LinkageNameIndex = 0;
+
+ // Reference to DW_AT_specification, DW_AT_abstract_origin attribute.
+ LVSymbol *Reference = nullptr;
+
+ // Bitfields length.
+ uint32_t BitSize = 0;
+
+ // Index in the String pool representing any initial value.
+ size_t ValueIndex = 0;
+
+public:
+ LVSymbol() : LVElement(LVSubclassID::LV_SYMBOL) {
+ setIsSymbol();
+ setIncludeInPrint();
+ }
+ LVSymbol(const LVSymbol &) = delete;
+ LVSymbol &operator=(const LVSymbol &) = delete;
+ ~LVSymbol() = default;
+
+ static bool classof(const LVElement *Element) {
+ return Element->getSubclassID() == LVSubclassID::LV_SYMBOL;
+ }
+
+ KIND(LVSymbolKind, IsCallSiteParameter);
+ KIND(LVSymbolKind, IsConstant);
+ KIND(LVSymbolKind, IsInheritance);
+ KIND(LVSymbolKind, IsMember);
+ KIND(LVSymbolKind, IsParameter);
+ KIND(LVSymbolKind, IsUnspecified);
+ KIND(LVSymbolKind, IsVariable);
+
+ PROPERTY(Property, HasLocation);
+ PROPERTY(Property, FillGaps);
+
+ const char *kind() const override;
+
+ // Access DW_AT_specification, DW_AT_abstract_origin reference.
+ LVSymbol *getReference() const { return Reference; }
+ void setReference(LVSymbol *Symbol) override {
+ Reference = Symbol;
+ setHasReference();
+ }
+ void setReference(LVElement *Element) override {
+ assert((!Element || isa<LVSymbol>(Element)) && "Invalid element");
+ setReference(static_cast<LVSymbol *>(Element));
+ }
+
+ void setLinkageName(StringRef LinkageName) override {
+ LinkageNameIndex = getStringPool().getIndex(LinkageName);
+ }
+ StringRef getLinkageName() const override {
+ return getStringPool().getString(LinkageNameIndex);
+ }
+ size_t getLinkageNameIndex() const override { return LinkageNameIndex; }
+
+ uint32_t getBitSize() const override { return BitSize; }
+ void setBitSize(uint32_t Size) override { BitSize = Size; }
+
+ // Process the values for a DW_AT_const_value.
+ std::string getValue() const override {
+ return std::string(getStringPool().getString(ValueIndex));
+ }
+ void setValue(StringRef Value) override {
+ ValueIndex = getStringPool().getIndex(Value);
+ }
+ size_t getValueIndex() const override { return ValueIndex; }
+
+ // Follow a chain of references given by DW_AT_abstract_origin and/or
+ // DW_AT_specification and update the symbol name.
+ StringRef resolveReferencesChain();
+
+ void resolveName() override;
+ void resolveReferences() override;
+
+ void print(raw_ostream &OS, bool Full = true) const override;
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const override { print(dbgs()); }
+#endif
+};
+
} // end namespace logicalview
} // end namespace llvm
};
using LVTypeKindSelection = std::set<LVTypeKind>;
+// Class to represent a DWARF Type.
+class LVType : public LVElement {
+ enum class Property { IsSubrangeCount, LastEntry };
+
+ // Typed bitvector with kinds and properties for this type.
+ LVProperties<LVTypeKind> Kinds;
+ LVProperties<Property> Properties;
+
+public:
+ LVType() : LVElement(LVSubclassID::LV_TYPE) { setIsType(); }
+ LVType(const LVType &) = delete;
+ LVType &operator=(const LVType &) = delete;
+ virtual ~LVType() = default;
+
+ static bool classof(const LVElement *Element) {
+ return Element->getSubclassID() == LVSubclassID::LV_TYPE;
+ }
+
+ KIND(LVTypeKind, IsBase);
+ KIND(LVTypeKind, IsConst);
+ KIND(LVTypeKind, IsEnumerator);
+ KIND(LVTypeKind, IsImport);
+ KIND_1(LVTypeKind, IsImportDeclaration, IsImport);
+ KIND_1(LVTypeKind, IsImportModule, IsImport);
+ KIND(LVTypeKind, IsPointer);
+ KIND(LVTypeKind, IsPointerMember);
+ KIND(LVTypeKind, IsReference);
+ KIND(LVTypeKind, IsRestrict);
+ KIND(LVTypeKind, IsRvalueReference);
+ KIND(LVTypeKind, IsSubrange);
+ KIND(LVTypeKind, IsTemplateParam);
+ KIND_1(LVTypeKind, IsTemplateTemplateParam, IsTemplateParam);
+ KIND_1(LVTypeKind, IsTemplateTypeParam, IsTemplateParam);
+ KIND_1(LVTypeKind, IsTemplateValueParam, IsTemplateParam);
+ KIND(LVTypeKind, IsTypedef);
+ KIND(LVTypeKind, IsUnaligned);
+ KIND(LVTypeKind, IsUnspecified);
+ KIND(LVTypeKind, IsVolatile);
+ KIND(LVTypeKind, IsModifier);
+
+ PROPERTY(Property, IsSubrangeCount);
+
+ const char *kind() const override;
+
+ // Follow a chain of references given by DW_AT_abstract_origin and/or
+ // DW_AT_specification and update the type name.
+ StringRef resolveReferencesChain();
+
+ bool isBase() const override { return getIsBase(); }
+ bool isTemplateParam() const override { return getIsTemplateParam(); }
+
+ // Encode the specific template argument.
+ virtual void encodeTemplateArgument(std::string &Name) const {}
+
+ // Return the underlying type for a type definition.
+ virtual LVElement *getUnderlyingType() { return nullptr; }
+ virtual void setUnderlyingType(LVElement *Element) {}
+
+ void resolveName() override;
+ void resolveReferences() override;
+
+ void print(raw_ostream &OS, bool Full = true) const override;
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ void dump() const override { print(dbgs()); }
+#endif
+};
+
+// Class to represent DW_TAG_typedef_type.
+class LVTypeDefinition final : public LVType {
+public:
+ LVTypeDefinition() : LVType() {
+ setIsTypedef();
+ setIncludeInPrint();
+ }
+ LVTypeDefinition(const LVTypeDefinition &) = delete;
+ LVTypeDefinition &operator=(const LVTypeDefinition &) = delete;
+ ~LVTypeDefinition() = default;
+
+ // Return the underlying type for a type definition.
+ LVElement *getUnderlyingType() override;
+ void setUnderlyingType(LVElement *Element) override { setType(Element); }
+
+ void resolveExtra() override;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DW_TAG_enumerator.
+class LVTypeEnumerator final : public LVType {
+ // Index in the String pool representing any initial value.
+ size_t ValueIndex = 0;
+
+public:
+ LVTypeEnumerator() : LVType() {
+ setIsEnumerator();
+ setIncludeInPrint();
+ }
+ LVTypeEnumerator(const LVTypeEnumerator &) = delete;
+ LVTypeEnumerator &operator=(const LVTypeEnumerator &) = delete;
+ ~LVTypeEnumerator() = default;
+
+ // Process the values for a DW_TAG_enumerator.
+ std::string getValue() const override {
+ return std::string(getStringPool().getString(ValueIndex));
+ }
+ void setValue(StringRef Value) override {
+ ValueIndex = getStringPool().getIndex(Value);
+ }
+ size_t getValueIndex() const override { return ValueIndex; }
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent DW_TAG_imported_module / DW_TAG_imported_declaration.
+class LVTypeImport final : public LVType {
+public:
+ LVTypeImport() : LVType() { setIncludeInPrint(); }
+ LVTypeImport(const LVTypeImport &) = delete;
+ LVTypeImport &operator=(const LVTypeImport &) = delete;
+ ~LVTypeImport() = default;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DWARF Template parameter holder (type or param).
+class LVTypeParam final : public LVType {
+ // Index in the String pool representing any initial value.
+ size_t ValueIndex = 0;
+
+public:
+ LVTypeParam();
+ LVTypeParam(const LVTypeParam &) = delete;
+ LVTypeParam &operator=(const LVTypeParam &) = delete;
+ ~LVTypeParam() = default;
+
+ // Template parameter value.
+ std::string getValue() const override {
+ return std::string(getStringPool().getString(ValueIndex));
+ }
+ void setValue(StringRef Value) override {
+ ValueIndex = getStringPool().getIndex(Value);
+ }
+ size_t getValueIndex() const override { return ValueIndex; }
+
+ // Encode the specific template argument.
+ void encodeTemplateArgument(std::string &Name) const override;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+// Class to represent a DW_TAG_subrange_type.
+class LVTypeSubrange final : public LVType {
+ // Values describing the subrange bounds.
+ int64_t LowerBound = 0; // DW_AT_lower_bound or DW_AT_count value.
+ int64_t UpperBound = 0; // DW_AT_upper_bound value.
+
+public:
+ LVTypeSubrange() : LVType() {
+ setIsSubrange();
+ setIncludeInPrint();
+ }
+ LVTypeSubrange(const LVTypeSubrange &) = delete;
+ LVTypeSubrange &operator=(const LVTypeSubrange &) = delete;
+ ~LVTypeSubrange() = default;
+
+ int64_t getCount() const override {
+ return getIsSubrangeCount() ? LowerBound : 0;
+ }
+ void setCount(int64_t Value) override {
+ LowerBound = Value;
+ setIsSubrangeCount();
+ }
+
+ int64_t getLowerBound() const override { return LowerBound; }
+ void setLowerBound(int64_t Value) override { LowerBound = Value; }
+
+ int64_t getUpperBound() const override { return UpperBound; }
+ void setUpperBound(int64_t Value) override { UpperBound = Value; }
+
+ std::pair<unsigned, unsigned> getBounds() const override {
+ return {LowerBound, UpperBound};
+ }
+ void setBounds(unsigned Lower, unsigned Upper) override {
+ LowerBound = Lower;
+ UpperBound = Upper;
+ }
+
+ void resolveExtra() override;
+
+ void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
} // end namespace logicalview
} // end namespace llvm
endmacro()
add_lv_impl_folder(Core
+ Core/LVElement.cpp
+ Core/LVLine.cpp
+ Core/LVObject.cpp
Core/LVOptions.cpp
+ Core/LVReader.cpp
+ Core/LVScope.cpp
+ Core/LVSort.cpp
+ Core/LVSupport.cpp
+ Core/LVSymbol.cpp
+ Core/LVType.cpp
)
list(APPEND LIBLV_ADDITIONAL_HEADER_DIRS
--- /dev/null
+//===-- LVElement.cpp -----------------------------------------------------===//
+//
+// 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 implements the LVElement class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Element"
+
+LVType *LVElement::getTypeAsType() const {
+ return ElementType && ElementType->getIsType()
+ ? static_cast<LVType *>(ElementType)
+ : nullptr;
+}
+
+LVScope *LVElement::getTypeAsScope() const {
+ return ElementType && ElementType->getIsScope()
+ ? static_cast<LVScope *>(ElementType)
+ : nullptr;
+}
+
+// Set the element type.
+void LVElement::setGenericType(LVElement *Element) {
+ if (!Element->isTemplateParam()) {
+ setType(Element);
+ return;
+ }
+ // For template parameters, the instance type can be a type or a scope.
+ if (options().getAttributeArgument()) {
+ if (Element->getIsKindType())
+ setType(Element->getTypeAsType());
+ else if (Element->getIsKindScope())
+ setType(Element->getTypeAsScope());
+ } else
+ setType(Element);
+}
+
+// Discriminator as string.
+std::string LVElement::discriminatorAsString() const {
+ uint32_t Discriminator = getDiscriminator();
+ std::string String;
+ raw_string_ostream Stream(String);
+ if (Discriminator && options().getAttributeDiscriminator())
+ Stream << "," << Discriminator;
+ return String;
+}
+
+// Get the type as a string.
+StringRef LVElement::typeAsString() const {
+ return getHasType() ? getTypeName() : typeVoid();
+}
+
+// Get name for element type.
+StringRef LVElement::getTypeName() const {
+ return ElementType ? ElementType->getName() : StringRef();
+}
+
+static size_t getStringIndex(StringRef Name) {
+ // Convert the name to Unified format ('\' have been converted into '/').
+ std::string Pathname(transformPath(Name));
+
+ // Depending on the --attribute=filename and --attribute=pathname command
+ // line options, use the basename or the full pathname as the name.
+ if (!options().getAttributePathname()) {
+ // Get the basename by ignoring any prefix up to the last slash ('/').
+ StringRef Basename = Pathname;
+ size_t Pos = Basename.rfind('/');
+ if (Pos != std::string::npos)
+ Basename = Basename.substr(Pos + 1);
+ return getStringPool().getIndex(Basename);
+ }
+
+ return getStringPool().getIndex(Pathname);
+}
+
+void LVElement::setName(StringRef ElementName) {
+ // In the case of Root or Compile Unit, get index for the flatted out name.
+ NameIndex = getTransformName() ? getStringIndex(ElementName)
+ : getStringPool().getIndex(ElementName);
+}
+
+void LVElement::setFilename(StringRef Filename) {
+ // Get index for the flattened out filename.
+ FilenameIndex = getStringIndex(Filename);
+}
+
+// Return the string representation of a DIE offset.
+std::string LVElement::typeOffsetAsString() const {
+ if (options().getAttributeOffset()) {
+ LVElement *Element = getType();
+ return hexSquareString(Element ? Element->getOffset() : 0);
+ }
+ return {};
+}
+
+StringRef LVElement::accessibilityString(uint32_t Access) const {
+ uint32_t Value = getAccessibilityCode();
+ switch (Value ? Value : Access) {
+ case dwarf::DW_ACCESS_public:
+ return "public";
+ case dwarf::DW_ACCESS_protected:
+ return "protected";
+ case dwarf::DW_ACCESS_private:
+ return "private";
+ default:
+ return StringRef();
+ }
+}
+
+StringRef LVElement::externalString() const {
+ return getIsExternal() ? "extern" : StringRef();
+}
+
+StringRef LVElement::inlineCodeString(uint32_t Code) const {
+ uint32_t Value = getInlineCode();
+ switch (Value ? Value : Code) {
+ case dwarf::DW_INL_not_inlined:
+ return "not_inlined";
+ case dwarf::DW_INL_inlined:
+ return "inlined";
+ case dwarf::DW_INL_declared_not_inlined:
+ return "declared_not_inlined";
+ case dwarf::DW_INL_declared_inlined:
+ return "declared_inlined";
+ default:
+ return StringRef();
+ }
+}
+
+StringRef LVElement::virtualityString(uint32_t Virtuality) const {
+ uint32_t Value = getVirtualityCode();
+ switch (Value ? Value : Virtuality) {
+ case dwarf::DW_VIRTUALITY_none:
+ return StringRef();
+ case dwarf::DW_VIRTUALITY_virtual:
+ return "virtual";
+ case dwarf::DW_VIRTUALITY_pure_virtual:
+ return "pure virtual";
+ default:
+ return StringRef();
+ }
+}
+
+void LVElement::resolve() {
+ if (getIsResolved())
+ return;
+ setIsResolved();
+
+ resolveReferences();
+ resolveParents();
+ resolveExtra();
+ resolveName();
+}
+
+// Set File/Line using the specification element.
+void LVElement::setFileLine(LVElement *Specification) {
+ // In the case of inlined functions, the correct scope must be associated
+ // with the file and line information of the outline version.
+ if (!isLined()) {
+ setLineNumber(Specification->getLineNumber());
+ setIsLineFromReference();
+ }
+ if (!isFiled()) {
+ setFilenameIndex(Specification->getFilenameIndex());
+ setIsFileFromReference();
+ }
+}
+
+void LVElement::resolveName() {
+ // Set the qualified name if requested.
+ if (options().getAttributeQualified())
+ resolveQualifiedName();
+
+ setIsResolvedName();
+}
+
+// Resolve any parents.
+void LVElement::resolveParents() {
+ if (isRoot() || isCompileUnit())
+ return;
+
+ LVScope *Parent = getParentScope();
+ if (Parent && !Parent->getIsCompileUnit())
+ Parent->resolve();
+}
+
+// Generate a name for unnamed elements.
+void LVElement::generateName(std::string &Prefix) const {
+ LVScope *Scope = getParentScope();
+ if (!Scope)
+ return;
+
+ // Use its parent name and any line information.
+ Prefix.append(std::string(Scope->getName()));
+ Prefix.append("::");
+ Prefix.append(isLined() ? lineNumberAsString(/*ShowZero=*/true) : "?");
+
+ // Remove any whitespaces.
+ Prefix.erase(std::remove_if(Prefix.begin(), Prefix.end(), ::isspace),
+ Prefix.end());
+}
+
+// Generate a name for unnamed elements.
+void LVElement::generateName() {
+ setIsAnonymous();
+ std::string Name;
+ generateName(Name);
+ setName(Name);
+ setIsGeneratedName();
+}
+
+void LVElement::updateLevel(LVScope *Parent, bool Moved) {
+ setLevel(Parent->getLevel() + 1);
+ if (Moved)
+ setHasMoved();
+}
+
+// Generate the full name for the element, to include special qualifiers.
+void LVElement::resolveFullname(LVElement *BaseType, StringRef Name) {
+ // For the following sample code,
+ // void *p;
+ // some compilers do not generate an attribute for the associated type:
+ // DW_TAG_variable
+ // DW_AT_name 'p'
+ // DW_AT_type $1
+ // ...
+ // $1: DW_TAG_pointer_type
+ // ...
+ // For those cases, generate the implicit 'void' type.
+ StringRef BaseTypename = BaseType ? BaseType->getName() : emptyString();
+ bool GetBaseTypename = false;
+ bool UseBaseTypename = true;
+ bool UseNameText = true;
+
+ switch (getTag()) {
+ case dwarf::DW_TAG_pointer_type: // "*";
+ if (!BaseType)
+ BaseTypename = typeVoid();
+ break;
+ case dwarf::DW_TAG_const_type: // "const"
+ case dwarf::DW_TAG_ptr_to_member_type: // "*"
+ case dwarf::DW_TAG_rvalue_reference_type: // "&&"
+ case dwarf::DW_TAG_reference_type: // "&"
+ case dwarf::DW_TAG_restrict_type: // "restrict"
+ case dwarf::DW_TAG_volatile_type: // "volatile"
+ case dwarf::DW_TAG_unaligned: // "unaligned"
+ break;
+ case dwarf::DW_TAG_base_type:
+ case dwarf::DW_TAG_compile_unit:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_enumerator:
+ case dwarf::DW_TAG_namespace:
+ case dwarf::DW_TAG_skeleton_unit:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_unspecified_type:
+ case dwarf::DW_TAG_GNU_template_parameter_pack:
+ GetBaseTypename = true;
+ break;
+ case dwarf::DW_TAG_array_type:
+ case dwarf::DW_TAG_call_site:
+ case dwarf::DW_TAG_entry_point:
+ case dwarf::DW_TAG_enumeration_type:
+ case dwarf::DW_TAG_GNU_call_site:
+ case dwarf::DW_TAG_imported_module:
+ case dwarf::DW_TAG_imported_declaration:
+ case dwarf::DW_TAG_inlined_subroutine:
+ case dwarf::DW_TAG_label:
+ case dwarf::DW_TAG_subprogram:
+ case dwarf::DW_TAG_subrange_type:
+ case dwarf::DW_TAG_subroutine_type:
+ case dwarf::DW_TAG_typedef:
+ GetBaseTypename = true;
+ UseBaseTypename = false;
+ break;
+ case dwarf::DW_TAG_template_type_parameter:
+ case dwarf::DW_TAG_template_value_parameter:
+ UseBaseTypename = false;
+ break;
+ case dwarf::DW_TAG_GNU_template_template_param:
+ break;
+ case dwarf::DW_TAG_catch_block:
+ case dwarf::DW_TAG_lexical_block:
+ case dwarf::DW_TAG_try_block:
+ UseNameText = false;
+ break;
+ default:
+ llvm_unreachable("Invalid type.");
+ return;
+ break;
+ }
+
+ // Overwrite if no given value. 'Name' is empty when resolving for scopes
+ // and symbols. In the case of types, it represents the type base name.
+ if (Name.empty() && GetBaseTypename)
+ Name = getName();
+
+ // Concatenate the elements to get the full type name.
+ // Type will be: base_parent + pre + base + parent + post.
+ std::string Fullname;
+
+ if (UseNameText && Name.size())
+ Fullname.append(std::string(Name));
+ if (UseBaseTypename && BaseTypename.size()) {
+ if (UseNameText && Name.size())
+ Fullname.append(" ");
+ Fullname.append(std::string(BaseTypename));
+ }
+
+ // For a better and consistent layout, check if the generated name
+ // contains double space sequences.
+ assert((Fullname.find(" ", 0) == std::string::npos) &&
+ "Extra double spaces in name.");
+
+ LLVM_DEBUG({ dbgs() << "Fullname = '" << Fullname << "'\n"; });
+ setName(Fullname.c_str());
+}
+
+void LVElement::setFile(LVElement *Reference) {
+ if (!options().getAttributeAnySource())
+ return;
+
+ // At this point, any existing reference to another element, have been
+ // resolved and the file ID extracted from the DI entry.
+ if (Reference)
+ setFileLine(Reference);
+
+ // The file information is used to show the source file for any element
+ // and display any new source file in relation to its parent element.
+ // a) Elements that are not inlined.
+ // - We record the DW_AT_decl_line and DW_AT_decl_file.
+ // b) Elements that are inlined.
+ // - We record the DW_AT_decl_line and DW_AT_decl_file.
+ // - We record the DW_AT_call_line and DW_AT_call_file.
+ // For both cases, we use the DW_AT_decl_file value to detect any changes
+ // in the source filename containing the element. Changes on this value
+ // indicates that the element being printed is not contained in the
+ // previous printed filename.
+
+ // The source files are indexed starting at 0, but DW_AT_decl_file defines
+ // that 0 means no file; a value of 1 means the 0th entry.
+ size_t Index = 0;
+
+ // An element with no source file information will use the reference
+ // attribute (DW_AT_specification, DW_AT_abstract_origin, DW_AT_extension)
+ // to update its information.
+ if (getIsFileFromReference() && Reference) {
+ Index = Reference->getFilenameIndex();
+ if (Reference->getInvalidFilename())
+ setInvalidFilename();
+ setFilenameIndex(Index);
+ return;
+ }
+
+ // The source files are indexed starting at 0, but DW_AT_decl_file
+ // defines that 0 means no file; a value of 1 means the 0th entry.
+ Index = getFilenameIndex();
+ if (Index) {
+ StringRef Filename = getReader().getFilename(this, Index);
+ Filename.size() ? setFilename(Filename) : setInvalidFilename();
+ }
+}
+
+LVScope *LVElement::traverseParents(LVScopeGetFunction GetFunction) const {
+ LVScope *Parent = getParentScope();
+ while (Parent && !(Parent->*GetFunction)())
+ Parent = Parent->getParentScope();
+ return Parent;
+}
+
+LVScope *LVElement::getFunctionParent() const {
+ return traverseParents(&LVScope::getIsFunction);
+}
+
+LVScope *LVElement::getCompileUnitParent() const {
+ return traverseParents(&LVScope::getIsCompileUnit);
+}
+
+// Resolve the qualified name to include the parent hierarchy names.
+void LVElement::resolveQualifiedName() {
+ if (!getIsReferencedType() || isBase() || getQualifiedResolved() ||
+ !getIncludeInPrint())
+ return;
+
+ std::string Name;
+
+ // Get the qualified name, excluding the Compile Unit.
+ LVScope *Parent = getParentScope();
+ if (Parent && !Parent->getIsRoot()) {
+ while (Parent && !Parent->getIsCompileUnit()) {
+ Name.insert(0, "::");
+ if (Parent->isNamed())
+ Name.insert(0, std::string(Parent->getName()));
+ else {
+ std::string Temp;
+ Parent->generateName(Temp);
+ Name.insert(0, Temp);
+ }
+ Parent = Parent->getParentScope();
+ }
+ }
+
+ if (Name.size()) {
+ setQualifiedName(Name);
+ setQualifiedResolved();
+ }
+ LLVM_DEBUG({
+ dbgs() << "Offset: " << hexSquareString(getOffset())
+ << ", Kind: " << formattedKind(kind())
+ << ", Name: " << formattedName(getName())
+ << ", QualifiedName: " << formattedName(Name) << "\n";
+ });
+}
+
+// Print the FileName Index.
+void LVElement::printFileIndex(raw_ostream &OS, bool Full) const {
+ if (options().getPrintFormatting() && options().getAttributeAnySource() &&
+ getFilenameIndex()) {
+
+ // Check if there is a change in the File ID sequence.
+ size_t Index = getFilenameIndex();
+ if (options().changeFilenameIndex(Index)) {
+ // Just to keep a nice layout.
+ OS << "\n";
+ printAttributes(OS, /*Full=*/false);
+
+ OS << " {Source} ";
+ if (getInvalidFilename())
+ OS << format("[0x%08x]\n", Index);
+ else
+ OS << formattedName(getPathname()) << "\n";
+ }
+ }
+}
+
+void LVElement::printReference(raw_ostream &OS, bool Full,
+ LVElement *Parent) const {
+ if (options().getPrintFormatting() && options().getAttributeReference())
+ printAttributes(OS, Full, "{Reference} ", Parent,
+ referenceAsString(getLineNumber(), /*Spaces=*/false),
+ /*UseQuotes=*/false, /*PrintRef=*/true);
+}
+
+void LVElement::printLinkageName(raw_ostream &OS, bool Full,
+ LVElement *Parent) const {
+ if (options().getPrintFormatting() && options().getAttributeLinkage()) {
+ printAttributes(OS, Full, "{Linkage} ", Parent, getLinkageName(),
+ /*UseQuotes=*/true, /*PrintRef=*/false);
+ }
+}
--- /dev/null
+//===-- LVLine.cpp --------------------------------------------------------===//
+//
+// 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 implements the LVLine class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Line"
+
+namespace {
+const char *const KindBasicBlock = "BasicBlock";
+const char *const KindDiscriminator = "Discriminator";
+const char *const KindEndSequence = "EndSequence";
+const char *const KindEpilogueBegin = "EpilogueBegin";
+const char *const KindLineDebug = "Line";
+const char *const KindLineSource = "Code";
+const char *const KindNewStatement = "NewStatement";
+const char *const KindPrologueEnd = "PrologueEnd";
+const char *const KindUndefined = "Undefined";
+const char *const KindAlwaysStepInto = "AlwaysStepInto"; // CodeView
+const char *const KindNeverStepInto = "NeverStepInto"; // CodeView
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Logical line.
+//===----------------------------------------------------------------------===//
+// Return a string representation for the line kind.
+const char *LVLine::kind() const {
+ const char *Kind = KindUndefined;
+ if (getIsLineDebug())
+ Kind = KindLineDebug;
+ else if (getIsLineAssembler())
+ Kind = KindLineSource;
+ return Kind;
+}
+
+// String used as padding for printing elements with no line number.
+std::string LVLine::noLineAsString(bool ShowZero) const {
+ return (ShowZero || options().getAttributeZero()) ? (" 0 ")
+ : (" - ");
+}
+
+void LVLine::print(raw_ostream &OS, bool Full) const {
+ if (getReader().doPrintLine(this)) {
+ getReaderCompileUnit()->incrementPrintedLines();
+ LVElement::print(OS, Full);
+ printExtra(OS, Full);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF line record.
+//===----------------------------------------------------------------------===//
+std::string LVLineDebug::statesInfo(bool Formatted) const {
+ // Returns the DWARF extra qualifiers.
+ std::string String;
+ raw_string_ostream Stream(String);
+
+ std::string Separator = Formatted ? " " : "";
+ if (getIsNewStatement()) {
+ Stream << Separator << "{" << KindNewStatement << "}";
+ Separator = " ";
+ }
+ if (getIsDiscriminator()) {
+ Stream << Separator << "{" << KindDiscriminator << "}";
+ Separator = " ";
+ }
+ if (getIsBasicBlock()) {
+ Stream << Separator << "{" << KindBasicBlock << "}";
+ Separator = " ";
+ }
+ if (getIsEndSequence()) {
+ Stream << Separator << "{" << KindEndSequence << "}";
+ Separator = " ";
+ }
+ if (getIsEpilogueBegin()) {
+ Stream << Separator << "{" << KindEpilogueBegin << "}";
+ Separator = " ";
+ }
+ if (getIsPrologueEnd()) {
+ Stream << Separator << "{" << KindPrologueEnd << "}";
+ Separator = " ";
+ }
+ if (getIsAlwaysStepInto()) {
+ Stream << Separator << "{" << KindAlwaysStepInto << "}";
+ Separator = " ";
+ }
+ if (getIsNeverStepInto()) {
+ Stream << Separator << "{" << KindNeverStepInto << "}";
+ Separator = " ";
+ }
+
+ return String;
+}
+
+void LVLineDebug::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind());
+
+ if (options().getAttributeQualifier()) {
+ // The qualifier includes the states information and the source filename
+ // that contains the line element.
+ OS << statesInfo(/*Formatted=*/true);
+ OS << " " << formattedName(getPathname());
+ }
+ OS << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// Assembler line extracted from the ELF .text section.
+//===----------------------------------------------------------------------===//
+void LVLineAssembler::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind());
+ OS << " " << formattedName(getName());
+ OS << "\n";
+}
--- /dev/null
+//===-- LVObject.cpp ------------------------------------------------------===//
+//
+// 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 implements the LVObject class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include <iomanip>
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Object"
+
+StringRef llvm::logicalview::typeNone() { return StringRef(); }
+StringRef llvm::logicalview::typeVoid() { return "void"; }
+StringRef llvm::logicalview::typeInt() { return "int"; }
+StringRef llvm::logicalview::typeUnknown() { return "?"; }
+StringRef llvm::logicalview::emptyString() { return StringRef(); }
+
+// Get a string representing the indentation level.
+std::string LVObject::indentAsString(LVLevel Level) const {
+ return std::string(Level * 2, ' ');
+}
+
+// Get a string representing the indentation level.
+std::string LVObject::indentAsString() const {
+ return (options().getPrintFormatting() || options().getPrintOffset())
+ ? indentAsString(ScopeLevel)
+ : "";
+}
+
+// String used as padding for printing objects with no line number.
+std::string LVObject::noLineAsString(bool ShowZero) const {
+ return std::string(8, ' ');
+}
+
+// Get a string representation for the given number and discriminator.
+std::string LVObject::lineAsString(uint32_t LineNumber, LVHalf Discriminator,
+ bool ShowZero) const {
+ // The representation is formatted as:
+ // a) line number (xxxxx) and discriminator (yy): 'xxxxx,yy'
+ // b) Only line number (xxxxx): 'xxxxx '
+ // c) No line number: ' '
+ std::stringstream Stream;
+ if (LineNumber) {
+ if (Discriminator && options().getAttributeDiscriminator())
+ Stream << std::setw(5) << LineNumber << "," << std::left << std::setw(2)
+ << Discriminator;
+ else
+ Stream << std::setw(5) << LineNumber << " ";
+ } else
+ Stream << noLineAsString(ShowZero);
+
+ return Stream.str();
+}
+
+// Same as 'LineString' but with stripped whitespaces.
+std::string LVObject::lineNumberAsStringStripped(bool ShowZero) const {
+ return std::string(StringRef(lineNumberAsString(ShowZero)).trim());
+}
+
+std::string LVObject::referenceAsString(uint32_t LineNumber,
+ bool Spaces) const {
+ std::string String;
+ raw_string_ostream Stream(String);
+ if (LineNumber)
+ Stream << "@" << LineNumber << (Spaces ? " " : "");
+
+ return String;
+}
+
+void LVObject::setParent(LVScope *Scope) {
+ Parent.Scope = Scope;
+ setLevel(Scope->getLevel() + 1);
+}
+void LVObject::setParent(LVSymbol *Symbol) {
+ Parent.Symbol = Symbol;
+ setLevel(Symbol->getLevel() + 1);
+}
+
+Error LVObject::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
+ bool Full) const {
+ print(OS, Full);
+ return Error::success();
+}
+
+void LVObject::printAttributes(raw_ostream &OS, bool Full, StringRef Name,
+ LVObject *Parent, StringRef Value,
+ bool UseQuotes, bool PrintRef) const {
+ // The current object will be the enclosing scope, use its offset and level.
+ LVObject Object(*Parent);
+ Object.setLevel(Parent->getLevel() + 1);
+ Object.setLineNumber(0);
+ Object.printAttributes(OS, Full);
+
+ // Print the line.
+ std::string TheLineNumber(Object.lineNumberAsString());
+ std::string TheIndentation(Object.indentAsString());
+ OS << format(" %5s %s ", TheLineNumber.c_str(), TheIndentation.c_str());
+
+ OS << Name;
+ if (PrintRef && options().getAttributeOffset())
+ OS << hexSquareString(getOffset());
+ if (UseQuotes)
+ OS << formattedName(Value) << "\n";
+ else
+ OS << Value << "\n";
+}
+
+void LVObject::printAttributes(raw_ostream &OS, bool Full) const {
+ if (options().getAttributeOffset())
+ OS << hexSquareString(getOffset());
+ if (options().getAttributeLevel()) {
+ std::stringstream Stream;
+ Stream.str(std::string());
+ Stream << "[" << std::setfill('0') << std::setw(3) << getLevel() << "]";
+ std::string TheLevel(Stream.str());
+ OS << TheLevel;
+ }
+ if (options().getAttributeGlobal())
+ OS << (getIsGlobalReference() ? 'X' : ' ');
+}
+
+void LVObject::print(raw_ostream &OS, bool Full) const {
+ printFileIndex(OS, Full);
+ printAttributes(OS, Full);
+
+ // Print the line and any discriminator.
+ std::stringstream Stream;
+ Stream << " " << std::setw(5) << lineNumberAsString() << " "
+ << indentAsString() << " ";
+ OS << Stream.str();
+}
--- /dev/null
+//===-- LVReader.cpp ------------------------------------------------------===//
+//
+// 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 implements the LVReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <tuple>
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Reader"
+
+//===----------------------------------------------------------------------===//
+// Class to represent a split context.
+//===----------------------------------------------------------------------===//
+Error LVSplitContext::createSplitFolder(StringRef Where) {
+ // The 'location' will represent the root directory for the output created
+ // by the context. It will contain the different CUs files, that will be
+ // extracted from a single ELF.
+ Location = std::string(Where);
+
+ // Add a trailing slash, if there is none.
+ size_t Pos = Location.find_last_of('/');
+ if (Location.length() != Pos + 1)
+ Location.append("/");
+
+ // Make sure the new directory exists, creating it if necessary.
+ if (std::error_code EC = llvm::sys::fs::create_directories(Location))
+ return createStringError(EC, "Error: could not create directory %s",
+ Location.c_str());
+
+ return Error::success();
+}
+
+std::error_code LVSplitContext::open(std::string ContextName,
+ std::string Extension, raw_ostream &OS) {
+ assert(OutputFile == nullptr && "OutputFile already set.");
+
+ // Transforms '/', '\', '.', ':' into '_'.
+ std::string Name(flattenedFilePath(ContextName));
+ Name.append(Extension);
+ // Add the split context location folder name.
+ if (!Location.empty())
+ Name.insert(0, Location);
+
+ std::error_code EC;
+ OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None);
+ if (EC)
+ return EC;
+
+ // Don't remove output file.
+ OutputFile->keep();
+ return std::error_code();
+}
+
+LVReader *CurrentReader = nullptr;
+LVReader &LVReader::getInstance() {
+ if (CurrentReader)
+ return *CurrentReader;
+ outs() << "Invalid instance reader.\n";
+ llvm_unreachable("Invalid instance reader.");
+}
+void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; }
+
+Error LVReader::createSplitFolder() {
+ if (OutputSplit) {
+ // If the '--output=split' was specified, but no '--split-folder'
+ // option, use the input file as base for the split location.
+ if (options().getOutputFolder().empty())
+ options().setOutputFolder(getFilename().str() + "_cus");
+
+ SmallString<128> SplitFolder;
+ SplitFolder = options().getOutputFolder();
+ sys::fs::make_absolute(SplitFolder);
+
+ // Return error if unable to create a split context location.
+ if (Error Err = SplitContext.createSplitFolder(SplitFolder))
+ return Err;
+
+ OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n";
+ }
+
+ return Error::success();
+}
+
+// Get the filename for given object.
+StringRef LVReader::getFilename(LVObject *Object, size_t Index) const {
+ if (CompileUnits.size()) {
+ // Get Compile Unit for the given object.
+ LVCompileUnits::const_iterator Iter =
+ std::prev(CompileUnits.lower_bound(Object->getOffset()));
+ if (Iter != CompileUnits.end())
+ return Iter->second->getFilename(Index);
+ }
+
+ return CompileUnit ? CompileUnit->getFilename(Index) : StringRef();
+}
+
+// The Reader is the module that creates the logical view using the debug
+// information contained in the binary file specified in the command line.
+// This is the main entry point for the Reader and performs the following
+// steps:
+// - Process any patterns collected from the '--select' options.
+// - For each compile unit in the debug information:
+// * Create the logical elements (scopes, symbols, types, lines).
+// * Collect debug ranges and debug locations.
+// * Move the collected logical lines to their associated scopes.
+// - Once all the compile units have been processed, traverse the scopes
+// tree in order to:
+// * Calculate symbol coverage.
+// * Detect invalid ranges and locations.
+// * "resolve" the logical elements. During this pass, the names and
+// file information are updated, to reflect any dependency with other
+// logical elements.
+Error LVReader::doLoad() {
+ // Set current Reader instance.
+ setInstance(this);
+
+ // Delegate the scope tree creation to the specific reader.
+ if (Error Err = createScopes())
+ return Err;
+
+ // As the elements can depend on elements from a different compile unit,
+ // information such as name and file/line source information needs to be
+ // updated.
+ Root->resolveElements();
+
+ sortScopes();
+ return Error::success();
+}
+
+// Default handler for a generic reader.
+Error LVReader::doPrint() {
+ // Set current Reader instance.
+ setInstance(this);
+
+ return printScopes();
+}
+
+Error LVReader::printScopes() {
+ if (bool DoPrint = options().getPrintExecute()) {
+ if (Error Err = createSplitFolder())
+ return Err;
+
+ // Start printing from the root.
+ bool DoMatch = false;
+ return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS);
+ }
+
+ return Error::success();
+}
+
+Error LVReader::printMatchedElements(bool UseMatchedElements) {
+ if (Error Err = createSplitFolder())
+ return Err;
+
+ return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements);
+}
+
+void LVReader::print(raw_ostream &OS) const {
+ OS << "LVReader\n";
+ LLVM_DEBUG(dbgs() << "PrintReader\n");
+}
--- /dev/null
+//===-- LVScope.cpp -------------------------------------------------------===//
+//
+// 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 implements the LVScope class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Scope"
+
+namespace {
+const char *const KindArray = "Array";
+const char *const KindBlock = "Block";
+const char *const KindCallSite = "CallSite";
+const char *const KindClass = "Class";
+const char *const KindCompileUnit = "CompileUnit";
+const char *const KindEnumeration = "Enumeration";
+const char *const KindFile = "File";
+const char *const KindFunction = "Function";
+const char *const KindInlinedFunction = "InlinedFunction";
+const char *const KindNamespace = "Namespace";
+const char *const KindStruct = "Struct";
+const char *const KindTemplateAlias = "TemplateAlias";
+const char *const KindTemplatePack = "TemplatePack";
+const char *const KindUndefined = "Undefined";
+const char *const KindUnion = "Union";
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// DWARF lexical block, such as: namespace, function, compile unit, module, etc.
+//===----------------------------------------------------------------------===//
+LVScope::~LVScope() {
+ delete Types;
+ delete Symbols;
+ delete Scopes;
+ delete Lines;
+ delete Children;
+}
+
+// Return a string representation for the scope kind.
+const char *LVScope::kind() const {
+ const char *Kind = KindUndefined;
+ if (getIsArray())
+ Kind = KindArray;
+ else if (getIsBlock())
+ Kind = KindBlock;
+ else if (getIsCallSite())
+ Kind = KindCallSite;
+ else if (getIsCompileUnit())
+ Kind = KindCompileUnit;
+ else if (getIsEnumeration())
+ Kind = KindEnumeration;
+ else if (getIsInlinedFunction())
+ Kind = KindInlinedFunction;
+ else if (getIsNamespace())
+ Kind = KindNamespace;
+ else if (getIsTemplatePack())
+ Kind = KindTemplatePack;
+ else if (getIsRoot())
+ Kind = KindFile;
+ else if (getIsTemplateAlias())
+ Kind = KindTemplateAlias;
+ else if (getIsClass())
+ Kind = KindClass;
+ else if (getIsFunction())
+ Kind = KindFunction;
+ else if (getIsStructure())
+ Kind = KindStruct;
+ else if (getIsUnion())
+ Kind = KindUnion;
+ return Kind;
+}
+
+void LVScope::addToChildren(LVElement *Element) {
+ if (!Children)
+ Children = new LVElements();
+ Children->push_back(Element);
+}
+
+void LVScope::addElement(LVElement *Element) {
+ assert(Element && "Invalid element.");
+ if (Element->getIsType())
+ addElement(static_cast<LVType *>(Element));
+ else if (Element->getIsScope())
+ addElement(static_cast<LVScope *>(Element));
+ else if (Element->getIsSymbol())
+ addElement(static_cast<LVSymbol *>(Element));
+ else if (Element->getIsLine())
+ addElement(static_cast<LVLine *>(Element));
+ else
+ llvm_unreachable("Invalid Element.");
+}
+
+// Adds the line info item to the ones stored in the scope.
+void LVScope::addElement(LVLine *Line) {
+ assert(Line && "Invalid line.");
+ assert(!Line->getParent() && "Line already inserted");
+ if (!Lines)
+ Lines = new LVAutoLines();
+
+ // Add it to parent.
+ Lines->push_back(Line);
+ Line->setParent(this);
+
+ // Notify the reader about the new element being added.
+ getReaderCompileUnit()->addedElement(Line);
+
+ // All logical elements added to the children, are sorted by any of the
+ // following criterias: offset, name, line number, kind.
+ // Do not add the line records to the children, as they represent the
+ // logical view for the text section and any sorting will not preserve
+ // the original sequence.
+
+ // Indicate that this tree branch has lines.
+ traverseParents(&LVScope::getHasLines, &LVScope::setHasLines);
+}
+
+// Adds the scope to the child scopes and sets the parent in the child.
+void LVScope::addElement(LVScope *Scope) {
+ assert(Scope && "Invalid scope.");
+ assert(!Scope->getParent() && "Scope already inserted");
+ if (!Scopes)
+ Scopes = new LVAutoScopes();
+
+ // Add it to parent.
+ Scopes->push_back(Scope);
+ addToChildren(Scope);
+ Scope->setParent(this);
+
+ // Notify the reader about the new element being added.
+ getReaderCompileUnit()->addedElement(Scope);
+
+ // If the element is a global reference, mark its parent as having global
+ // references; that information is used, to print only those branches
+ // with global references.
+ if (Scope->getIsGlobalReference())
+ traverseParents(&LVScope::getHasGlobals, &LVScope::setHasGlobals);
+ else
+ traverseParents(&LVScope::getHasLocals, &LVScope::setHasLocals);
+
+ // Indicate that this tree branch has scopes.
+ traverseParents(&LVScope::getHasScopes, &LVScope::setHasScopes);
+}
+
+// Adds a symbol to the ones stored in the scope.
+void LVScope::addElement(LVSymbol *Symbol) {
+ assert(Symbol && "Invalid symbol.");
+ assert(!Symbol->getParent() && "Symbol already inserted");
+ if (!Symbols)
+ Symbols = new LVAutoSymbols();
+
+ // Add it to parent.
+ Symbols->push_back(Symbol);
+ addToChildren(Symbol);
+ Symbol->setParent(this);
+
+ // Notify the reader about the new element being added.
+ getReaderCompileUnit()->addedElement(Symbol);
+
+ // If the element is a global reference, mark its parent as having global
+ // references; that information is used, to print only those branches
+ // with global references.
+ if (Symbol->getIsGlobalReference())
+ traverseParents(&LVScope::getHasGlobals, &LVScope::setHasGlobals);
+ else
+ traverseParents(&LVScope::getHasLocals, &LVScope::setHasLocals);
+
+ // Indicate that this tree branch has symbols.
+ traverseParents(&LVScope::getHasSymbols, &LVScope::setHasSymbols);
+}
+
+// Adds a type to the ones stored in the scope.
+void LVScope::addElement(LVType *Type) {
+ assert(Type && "Invalid type.");
+ assert(!Type->getParent() && "Type already inserted");
+ if (!Types)
+ Types = new LVAutoTypes();
+
+ // Add it to parent.
+ Types->push_back(Type);
+ addToChildren(Type);
+ Type->setParent(this);
+
+ // Notify the reader about the new element being added.
+ getReaderCompileUnit()->addedElement(Type);
+
+ // If the element is a global reference, mark its parent as having global
+ // references; that information is used, to print only those branches
+ // with global references.
+ if (Type->getIsGlobalReference())
+ traverseParents(&LVScope::getHasGlobals, &LVScope::setHasGlobals);
+ else
+ traverseParents(&LVScope::getHasLocals, &LVScope::setHasLocals);
+
+ // Indicate that this tree branch has types.
+ traverseParents(&LVScope::getHasTypes, &LVScope::setHasTypes);
+}
+
+bool LVScope::removeElement(LVElement *Element) {
+ auto Predicate = [Element](LVElement *Item) -> bool {
+ return Item == Element;
+ };
+ auto RemoveElement = [Element, Predicate](auto &Container) -> bool {
+ auto Iter = std::remove_if(Container->begin(), Container->end(), Predicate);
+ if (Iter != Container->end()) {
+ Container->erase(Iter, Container->end());
+ Element->resetParent();
+ return true;
+ }
+ return false;
+ };
+
+ // As 'children' contains only (scopes, symbols and types), check if the
+ // element we are deleting is a line.
+ if (Element->getIsLine())
+ return RemoveElement(Lines);
+
+ if (RemoveElement(Children)) {
+ if (Element->getIsSymbol())
+ return RemoveElement(Symbols);
+ if (Element->getIsType())
+ return RemoveElement(Types);
+ if (Element->getIsScope())
+ return RemoveElement(Scopes);
+ llvm_unreachable("Invalid element.");
+ }
+
+ return false;
+}
+
+void LVScope::addMissingElements(LVScope *Reference) {
+ setAddedMissing();
+ if (!Reference)
+ return;
+
+ // Get abstract symbols for the given scope reference.
+ const LVSymbols *ReferenceSymbols = Reference->getSymbols();
+ if (!ReferenceSymbols)
+ return;
+
+ LVSymbols References;
+ References.append(ReferenceSymbols->begin(), ReferenceSymbols->end());
+
+ auto RemoveSymbol = [&](LVSymbols &Symbols, LVSymbol *Symbol) {
+ LVSymbols::iterator Iter = std::remove_if(
+ Symbols.begin(), Symbols.end(),
+ [Symbol](LVSymbol *Item) -> bool { return Item == Symbol; });
+ if (Iter != Symbols.end())
+ Symbols.erase(Iter, Symbols.end());
+ };
+
+ // Erase abstract symbols already in this scope from the collection of
+ // symbols in the referenced scope.
+ if (getSymbols())
+ for (const LVSymbol *Symbol : *getSymbols())
+ if (Symbol->getHasReferenceAbstract())
+ RemoveSymbol(References, Symbol->getReference());
+
+ // If we have elements left in 'References', those are the elements that
+ // need to be inserted in the current scope.
+ if (References.size()) {
+ LLVM_DEBUG({
+ dbgs() << "Insert Missing Inlined Elements\n"
+ << "Offset = " << hexSquareString(getOffset()) << " "
+ << "Abstract = " << hexSquareString(Reference->getOffset())
+ << "\n";
+ });
+ for (LVSymbol *Reference : References) {
+ LLVM_DEBUG({
+ dbgs() << "Missing Offset = " << hexSquareString(Reference->getOffset())
+ << "\n";
+ });
+ // We can't clone the abstract origin reference, as it contain extra
+ // information that is incorrect for the element to be inserted.
+ // As the symbol being added does not exist in the debug section,
+ // use its parent scope offset, to indicate its DIE location.
+ LVSymbol *Symbol = new LVSymbol();
+ addElement(Symbol);
+ Symbol->setOffset(getOffset());
+ Symbol->setIsOptimized();
+ Symbol->setReference(Reference);
+
+ // The symbol can be a constant, parameter or variable.
+ if (Reference->getIsConstant())
+ Symbol->setIsConstant();
+ else if (Reference->getIsParameter())
+ Symbol->setIsParameter();
+ else if (Reference->getIsVariable())
+ Symbol->setIsVariable();
+ else
+ llvm_unreachable("Invalid symbol kind.");
+ }
+ }
+}
+
+void LVScope::updateLevel(LVScope *Parent, bool Moved) {
+ // Update the level for the element itself and all its children, using the
+ // given scope parent as reference.
+ setLevel(Parent->getLevel() + 1);
+
+ // Update the children.
+ if (Children)
+ for (LVElement *Element : *Children)
+ Element->updateLevel(this, Moved);
+
+ // Update any lines.
+ if (Lines)
+ for (LVLine *Line : *Lines)
+ Line->updateLevel(this, Moved);
+}
+
+void LVScope::resolve() {
+ if (getIsResolved())
+ return;
+
+ // Resolve the element itself.
+ LVElement::resolve();
+
+ // Resolve the children.
+ if (Children)
+ for (LVElement *Element : *Children) {
+ if (getIsGlobalReference())
+ // If the scope is a global reference, mark all its children as well.
+ Element->setIsGlobalReference();
+ Element->resolve();
+ }
+}
+
+void LVScope::resolveName() {
+ if (getIsResolvedName())
+ return;
+ setIsResolvedName();
+
+ // If the scope is a template, resolve the template parameters and get
+ // the name for the template with the encoded arguments.
+ if (getIsTemplate())
+ resolveTemplate();
+ else {
+ if (LVElement *BaseType = getType()) {
+ BaseType->resolveName();
+ resolveFullname(BaseType);
+ }
+ }
+
+ // In the case of unnamed scopes, try to generate a name for it, using
+ // the parents name and the line information. In the case of compiler
+ // generated functions, use its linkage name if is available.
+ if (!isNamed()) {
+ if (getIsArtificial())
+ setName(getLinkageName());
+ else
+ generateName();
+ }
+
+ LVElement::resolveName();
+}
+
+void LVScope::resolveReferences() {
+ // The scopes can have the following references to other elements:
+ // A type:
+ // DW_AT_type -> Type or Scope
+ // DW_AT_import -> Type
+ // A Reference:
+ // DW_AT_specification -> Scope
+ // DW_AT_abstract_origin -> Scope
+ // DW_AT_extension -> Scope
+
+ // Resolve any referenced scope.
+ LVScope *Reference = getReference();
+ if (Reference) {
+ Reference->resolve();
+ // Recursively resolve the scope names.
+ resolveReferencesChain();
+ }
+
+ // Set the file/line information using the Debug Information entry.
+ setFile(Reference);
+
+ // Resolve any referenced type or scope.
+ if (LVElement *Element = getType())
+ Element->resolve();
+}
+
+void LVScope::resolveElements() {
+ // The current element represents the Root. Traverse each Compile Unit.
+ if (!Scopes)
+ return;
+
+ for (LVScope *Scope : *Scopes) {
+ LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(Scope);
+ getReader().setCompileUnit(CompileUnit);
+ CompileUnit->resolve();
+ }
+}
+
+StringRef LVScope::resolveReferencesChain() {
+ // If the scope has a DW_AT_specification or DW_AT_abstract_origin,
+ // follow the chain to resolve the name from those references.
+ if (getHasReference() && !isNamed())
+ setName(getReference()->resolveReferencesChain());
+
+ return getName();
+}
+
+// Get template parameter types.
+bool LVScope::getTemplateParameterTypes(LVTypes &Params) {
+ // Traverse the scope types and populate the given container with those
+ // types that are template parameters; that container will be used by
+ // 'encodeTemplateArguments' to resolve them.
+ if (const LVTypes *Types = getTypes())
+ for (LVType *Type : *Types)
+ if (Type->getIsTemplateParam()) {
+ Type->resolve();
+ Params.push_back(Type);
+ }
+
+ return !Params.empty();
+}
+
+// Resolve the template parameters/arguments relationship.
+void LVScope::resolveTemplate() {
+ if (getIsTemplateResolved())
+ return;
+ setIsTemplateResolved();
+
+ // Check if we need to encode the template arguments.
+ if (options().getAttributeEncoded()) {
+ LVTypes Params;
+ if (getTemplateParameterTypes(Params)) {
+ std::string EncodedArgs;
+ // Encode the arguments as part of the template name and update the
+ // template name, to reflect the encoded parameters.
+ encodeTemplateArguments(EncodedArgs, &Params);
+ setEncodedArgs(EncodedArgs.c_str());
+ }
+ }
+}
+
+// Get the qualified name for the template.
+void LVScope::getQualifiedName(std::string &QualifiedName) const {
+ if (getIsRoot() || getIsCompileUnit())
+ return;
+
+ if (LVScope *Parent = getParentScope())
+ Parent->getQualifiedName(QualifiedName);
+ if (!QualifiedName.empty())
+ QualifiedName.append("::");
+ QualifiedName.append(std::string(getName()));
+}
+
+// Encode the template arguments as part of the template name.
+void LVScope::encodeTemplateArguments(std::string &Name) const {
+ // Qualify only when we are expanding parameters that are template
+ // instances; the debugger will assume the current scope symbol as
+ // the qualifying tag for the symbol being generated, which gives:
+ // namespace std {
+ // ...
+ // set<float,std::less<float>,std::allocator<float>>
+ // ...
+ // }
+ // The 'set' symbol is assumed to have the qualified tag 'std'.
+
+ // We are resolving a template parameter which is another template. If
+ // it is already resolved, just get the qualified name and return.
+ std::string BaseName;
+ getQualifiedName(BaseName);
+ if (getIsTemplateResolved())
+ Name.append(BaseName);
+}
+
+void LVScope::encodeTemplateArguments(std::string &Name,
+ const LVTypes *Types) const {
+ // The encoded string will start with the scope name.
+ Name.append("<");
+
+ // The list of types are the template parameters.
+ if (Types) {
+ bool AddComma = false;
+ for (const LVType *Type : *Types) {
+ if (AddComma)
+ Name.append(", ");
+ Type->encodeTemplateArgument(Name);
+ AddComma = true;
+ }
+ }
+
+ Name.append(">");
+}
+
+bool LVScope::resolvePrinting() const {
+ bool Globals = options().getAttributeGlobal();
+ bool Locals = options().getAttributeLocal();
+ if ((Globals && Locals) || (!Globals && !Locals)) {
+ // Print both Global and Local.
+ } else {
+ // Check for Global or Local Objects.
+ if ((Globals && !(getHasGlobals() || getIsGlobalReference())) ||
+ (Locals && !(getHasLocals() || !getIsGlobalReference())))
+ return false;
+ }
+
+ // For the case of functions, skip it if is compiler generated.
+ if (getIsFunction() && getIsArtificial() &&
+ !options().getAttributeGenerated())
+ return false;
+
+ return true;
+}
+
+Error LVScope::doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
+ bool Full) const {
+ // During a view output splitting, use the output stream created by the
+ // split context, then switch to the reader output stream.
+ raw_ostream *StreamSplit = &OS;
+
+ // If 'Split', we use the scope name (CU name) as the ouput file; the
+ // delimiters in the pathname, must be replaced by a normal character.
+ if (getIsCompileUnit()) {
+ getReader().setCompileUnit(const_cast<LVScope *>(this));
+ if (Split) {
+ std::string ScopeName(getName());
+ if (std::error_code EC =
+ getReaderSplitContext().open(ScopeName, ".txt", OS))
+ return createStringError(EC, "Unable to create split output file %s",
+ ScopeName.c_str());
+ StreamSplit = static_cast<raw_ostream *>(&getReaderSplitContext().os());
+ }
+ }
+
+ // Ignore discarded or stripped scopes (functions).
+ bool DoPrint = (options().getAttributeDiscarded()) ? true : !getIsDiscarded();
+
+ // If we are in compare mode, the only conditions are related to the
+ // element being missing. In the case of elements comparison, we print the
+ // augmented view, that includes added elements.
+ // In print mode, we check other conditions, such as local, global, etc.
+ if (DoPrint) {
+ DoPrint =
+ getIsInCompare() ? options().getReportExecute() : resolvePrinting();
+ }
+
+ // At this point we have checked for very specific options, to decide if the
+ // element will be printed. Include the caller's test for element general
+ // print.
+ DoPrint = DoPrint && (Print || options().getOutputSplit());
+
+ if (DoPrint) {
+ // Print the element itself.
+ print(*StreamSplit, Full);
+
+ // Check if we have reached the requested lexical level specified in the
+ // command line options. Input file is level zero and the CU is level 1.
+ if ((getIsRoot() || options().getPrintAnyElement()) &&
+ options().getPrintFormatting() &&
+ getLevel() < options().getOutputLevel()) {
+ // Print the children.
+ if (Children)
+ for (const LVElement *Element : *Children) {
+ if (Match && !Element->getHasPattern())
+ continue;
+ if (Error Err =
+ Element->doPrint(Split, Match, Print, *StreamSplit, Full))
+ return Err;
+ }
+
+ // Print the line records.
+ if (Lines)
+ for (const LVLine *Line : *Lines) {
+ if (Match && !Line->getHasPattern())
+ continue;
+ if (Error Err =
+ Line->doPrint(Split, Match, Print, *StreamSplit, Full))
+ return Err;
+ }
+ }
+ }
+
+ // Done printing the compile unit. Print any requested summary and
+ // restore the original output context.
+ if (getIsCompileUnit()) {
+ if (options().getPrintSummary())
+ printSummary(*StreamSplit);
+ if (options().getPrintSizes())
+ printSizes(*StreamSplit);
+ if (Split) {
+ getReaderSplitContext().close();
+ StreamSplit = &getReader().outputStream();
+ }
+ }
+
+ return Error::success();
+}
+
+void LVScope::sort() {
+ // Preserve the lines order as they are associated with user code.
+ LVSortFunction SortFunction = getSortFunction();
+ if (SortFunction) {
+ std::function<void(LVScope * Parent, LVSortFunction SortFunction)> Sort =
+ [&](LVScope *Parent, LVSortFunction SortFunction) {
+ auto Traverse = [&](auto *Set, LVSortFunction SortFunction) {
+ if (Set)
+ std::stable_sort(Set->begin(), Set->end(), SortFunction);
+ };
+ Traverse(Parent->Types, SortFunction);
+ Traverse(Parent->Symbols, SortFunction);
+ Traverse(Parent->Scopes, SortFunction);
+ Traverse(Parent->Children, SortFunction);
+
+ if (Parent->Scopes)
+ for (LVScope *Scope : *Parent->Scopes)
+ Sort(Scope, SortFunction);
+ };
+
+ // Start traversing the scopes root and transform the element name.
+ Sort(this, SortFunction);
+ }
+}
+
+void LVScope::traverseParents(LVScopeGetFunction GetFunction,
+ LVScopeSetFunction SetFunction) {
+ // Traverse the parent tree.
+ LVScope *Parent = this;
+ while (Parent) {
+ // Terminates if the 'SetFunction' has been already executed.
+ if ((Parent->*GetFunction)())
+ break;
+ (Parent->*SetFunction)();
+ Parent = Parent->getParentScope();
+ }
+}
+
+void LVScope::traverseParentsAndChildren(LVObjectGetFunction GetFunction,
+ LVObjectSetFunction SetFunction) {
+ if (options().getReportParents()) {
+ // First traverse the parent tree.
+ LVScope *Parent = this;
+ while (Parent) {
+ // Terminates if the 'SetFunction' has been already executed.
+ if ((Parent->*GetFunction)())
+ break;
+ (Parent->*SetFunction)();
+ Parent = Parent->getParentScope();
+ }
+ }
+
+ std::function<void(LVScope * Scope)> TraverseChildren = [&](LVScope *Scope) {
+ auto Traverse = [&](const auto *Set) {
+ if (Set)
+ for (const auto &Entry : *Set)
+ (Entry->*SetFunction)();
+ };
+
+ (Scope->*SetFunction)();
+
+ Traverse(Scope->getTypes());
+ Traverse(Scope->getSymbols());
+ Traverse(Scope->getLines());
+
+ if (const LVScopes *Scopes = Scope->getScopes())
+ for (LVScope *Scope : *Scopes)
+ TraverseChildren(Scope);
+ };
+
+ if (options().getReportChildren())
+ TraverseChildren(this);
+}
+
+void LVScope::printEncodedArgs(raw_ostream &OS, bool Full) const {
+ if (options().getPrintFormatting() && options().getAttributeEncoded())
+ printAttributes(OS, Full, "{Encoded} ", const_cast<LVScope *>(this),
+ getEncodedArgs(), /*UseQuotes=*/false, /*PrintRef=*/false);
+}
+
+void LVScope::print(raw_ostream &OS, bool Full) const {
+ if (getIncludeInPrint() && getReader().doPrintScope(this)) {
+ // For a summary (printed elements), do not count the scope root.
+ if (!(getIsRoot()))
+ getReaderCompileUnit()->incrementPrintedScopes();
+ LVElement::print(OS, Full);
+ printExtra(OS, Full);
+ }
+}
+
+void LVScope::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind());
+ // Do not print any type or name for a lexical block.
+ if (!getIsBlock()) {
+ OS << " " << formattedName(getName());
+ if (!getIsAggregate())
+ OS << " -> " << typeOffsetAsString()
+ << formattedNames(getTypeQualifiedName(), typeAsString());
+ }
+ OS << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF Union/Structure/Class.
+//===----------------------------------------------------------------------===//
+void LVScopeAggregate::printExtra(raw_ostream &OS, bool Full) const {
+ LVScope::printExtra(OS, Full);
+ if (Full) {
+ if (getIsTemplateResolved())
+ printEncodedArgs(OS, Full);
+ LVScope *Reference = getReference();
+ if (Reference)
+ Reference->printReference(OS, Full, const_cast<LVScopeAggregate *>(this));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF Template alias.
+//===----------------------------------------------------------------------===//
+void LVScopeAlias::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> "
+ << typeOffsetAsString()
+ << formattedNames(getTypeQualifiedName(), typeAsString()) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF array (DW_TAG_array_type).
+//===----------------------------------------------------------------------===//
+void LVScopeArray::resolveExtra() {
+ // If the scope is an array, resolve the subrange entries and get those
+ // values encoded and assigned to the scope type.
+ // Encode the array subrange entries as part of the name.
+ if (getIsArrayResolved())
+ return;
+ setIsArrayResolved();
+
+ // There are 2 cases to represent the bounds information for an array:
+ // 1) DW_TAG_array_type
+ // DW_AT_type --> ref_type
+ // DW_TAG_subrange_type
+ // DW_AT_type --> ref_type (type of object)
+ // DW_AT_count --> value (number of elements in subrange)
+
+ // 2) DW_TAG_array_type
+ // DW_AT_type --> ref_type
+ // DW_TAG_subrange_type
+ // DW_AT_lower_bound --> value
+ // DW_AT_upper_bound --> value
+
+ // The idea is to represent the bounds as a string, depending on the format:
+ // 1) [count]
+ // 2) [lower][upper]
+
+ // Traverse scope types, looking for those types that are subranges.
+ LVTypes Subranges;
+ if (const LVTypes *Types = getTypes())
+ for (LVType *Type : *Types)
+ if (Type->getIsSubrange()) {
+ Type->resolve();
+ Subranges.push_back(Type);
+ }
+
+ // Use the subrange types to generate the high level name for the array.
+ // Check the type has been fully resolved.
+ if (LVElement *BaseType = getType()) {
+ BaseType->resolveName();
+ resolveFullname(BaseType);
+ }
+
+ // In 'resolveFullname' a check is done for double spaces in the type name.
+ std::stringstream ArrayInfo;
+ if (ElementType)
+ ArrayInfo << getTypeName().str() << " ";
+
+ for (const LVType *Type : Subranges) {
+ if (Type->getIsSubrangeCount())
+ // Check if we have DW_AT_count subrange style.
+ ArrayInfo << "[" << Type->getCount() << "]";
+ else {
+ // Get lower and upper subrange values.
+ unsigned LowerBound;
+ unsigned UpperBound;
+ std::tie(LowerBound, UpperBound) = Type->getBounds();
+
+ // The representation depends on the bound values. If the lower value
+ // is zero, treat the pair as the elements count. Otherwise, just use
+ // the pair, as they are representing arrays in languages other than
+ // C/C++ and the lower limit is not zero.
+ if (LowerBound)
+ ArrayInfo << "[" << LowerBound << ".." << UpperBound << "]";
+ else
+ ArrayInfo << "[" << UpperBound + 1 << "]";
+ }
+ }
+
+ // Update the scope name, to reflect the encoded subranges.
+ setName(ArrayInfo.str());
+}
+
+void LVScopeArray::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << typeOffsetAsString()
+ << formattedName(getName()) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// An object file (single or multiple CUs).
+//===----------------------------------------------------------------------===//
+void LVScopeCompileUnit::addSize(LVScope *Scope, LVOffset Lower,
+ LVOffset Upper) {
+ LLVM_DEBUG({
+ dbgs() << format(
+ "CU [0x%08x], Scope [0x%08x], Range [0x%08x:0x%08x], Size = %d\n",
+ getOffset(), Scope->getOffset(), Lower, Upper, Upper - Lower);
+ });
+
+ // There is no need to check for a previous entry, as we are traversing the
+ // debug information in sequential order.
+ LVOffset Size = Upper - Lower;
+ Sizes[Scope] = Size;
+ if (this == Scope)
+ // Record contribution size for the compilation unit.
+ CUContributionSize = Size;
+}
+
+LVLine *LVScopeCompileUnit::lineLowerBound(LVAddress Address) const {
+ LVAddressToLine::const_iterator Iter = AddressToLine.lower_bound(Address);
+ return (Iter != AddressToLine.end()) ? Iter->second : nullptr;
+}
+
+LVLine *LVScopeCompileUnit::lineUpperBound(LVAddress Address) const {
+ LVAddressToLine::const_iterator Iter = AddressToLine.upper_bound(Address);
+ if (Iter != AddressToLine.begin())
+ Iter = std::prev(Iter);
+ return (Iter != AddressToLine.end()) ? Iter->second : nullptr;
+}
+
+StringRef LVScopeCompileUnit::getFilename(size_t Index) const {
+ if (Index <= 0 || Index > Filenames.size())
+ return StringRef();
+ return getStringPool().getString(Filenames[Index - 1]);
+}
+
+void LVScopeCompileUnit::incrementPrintedLines() { ++Printed.Lines; }
+void LVScopeCompileUnit::incrementPrintedScopes() { ++Printed.Scopes; }
+void LVScopeCompileUnit::incrementPrintedSymbols() { ++Printed.Symbols; }
+void LVScopeCompileUnit::incrementPrintedTypes() { ++Printed.Types; }
+
+// Values are used by '--summary' option (allocated).
+void LVScopeCompileUnit::increment(LVLine *Line) {
+ if (Line->getIncludeInPrint())
+ ++Allocated.Lines;
+}
+void LVScopeCompileUnit::increment(LVScope *Scope) {
+ if (Scope->getIncludeInPrint())
+ ++Allocated.Scopes;
+}
+void LVScopeCompileUnit::increment(LVSymbol *Symbol) {
+ if (Symbol->getIncludeInPrint())
+ ++Allocated.Symbols;
+}
+void LVScopeCompileUnit::increment(LVType *Type) {
+ if (Type->getIncludeInPrint())
+ ++Allocated.Types;
+}
+
+// A new element has been added to the scopes tree. Take the following steps:
+// Increase the added element counters, for printing summary.
+void LVScopeCompileUnit::addedElement(LVLine *Line) { increment(Line); }
+void LVScopeCompileUnit::addedElement(LVScope *Scope) { increment(Scope); }
+void LVScopeCompileUnit::addedElement(LVSymbol *Symbol) { increment(Symbol); }
+void LVScopeCompileUnit::addedElement(LVType *Type) { increment(Type); }
+
+void LVScopeCompileUnit::printLocalNames(raw_ostream &OS, bool Full) const {
+ if (!options().getPrintFormatting())
+ return;
+
+ // Calculate an indentation value, to preserve a nice layout.
+ size_t Indentation = options().indentationSize() +
+ lineNumberAsString().length() +
+ indentAsString(getLevel() + 1).length() + 3;
+
+ enum class Option { Directory, File };
+ auto PrintNames = [&](Option Action) {
+ StringRef Kind = Action == Option::Directory ? "Directory" : "File";
+ std::set<std::string> UniqueNames;
+ for (size_t Index : Filenames) {
+ // In the case of missing directory name in the .debug_line table,
+ // the returned string has a leading '/'.
+ StringRef Name = getStringPool().getString(Index);
+ size_t Pos = Name.rfind('/');
+ if (Pos != std::string::npos)
+ Name = (Action == Option::File) ? Name.substr(Pos + 1)
+ : Name.substr(0, Pos);
+ // Collect only unique names.
+ UniqueNames.insert(std::string(Name));
+ }
+ for (const std::string &Name : UniqueNames)
+ OS << std::string(Indentation, ' ') << formattedKind(Kind) << " "
+ << formattedName(Name) << "\n";
+ };
+
+ if (options().getAttributeDirectories())
+ PrintNames(Option::Directory);
+ if (options().getAttributeFiles())
+ PrintNames(Option::File);
+}
+
+void LVScopeCompileUnit::printTotals(raw_ostream &OS) const {
+ OS << "\nTotals by lexical level:\n";
+ for (size_t Index = 1; Index <= MaxSeenLevel; ++Index)
+ OS << format("[%03d]: %10d (%6.2f%%)\n", Index, Totals[Index].first,
+ Totals[Index].second);
+}
+
+void LVScopeCompileUnit::printScopeSize(const LVScope *Scope, raw_ostream &OS) {
+ LVSizesMap::const_iterator Iter = Sizes.find(Scope);
+ if (Iter != Sizes.end()) {
+ LVOffset Size = Iter->second;
+ assert(CUContributionSize && "Invalid CU contribution size.");
+ // Get a percentage rounded to two decimal digits. This avoids
+ // implementation-defined rounding inside printing functions.
+ float Percentage =
+ rint((float(Size) / CUContributionSize) * 100.0 * 100.0) / 100.0;
+ OS << format("%10d (%6.2f%%) : ", Size, Percentage);
+ Scope->print(OS);
+
+ // Keep record of the total sizes at each lexical level.
+ LVLevel Level = Scope->getLevel();
+ if (Level > MaxSeenLevel)
+ MaxSeenLevel = Level;
+ if (Level >= Totals.size())
+ Totals.resize(2 * Level);
+ Totals[Level].first += Size;
+ Totals[Level].second += Percentage;
+ }
+}
+
+void LVScopeCompileUnit::printSizes(raw_ostream &OS) const {
+ // Recursively print the contributions for each scope.
+ std::function<void(const LVScope *Scope)> PrintScope =
+ [&](const LVScope *Scope) {
+ if (Scope->getLevel() < options().getOutputLevel()) {
+ if (const LVScopes *Scopes = Scope->getScopes())
+ for (const LVScope *Scope : *Scopes) {
+ printScopeSize(Scope, OS);
+ PrintScope(Scope);
+ }
+ }
+ };
+
+ bool PrintScopes = options().getPrintScopes();
+ if (!PrintScopes)
+ options().setPrintScopes();
+ getReader().setCompileUnit(const_cast<LVScopeCompileUnit *>(this));
+
+ OS << "\nScope Sizes:\n";
+ options().resetPrintFormatting();
+ options().setPrintOffset();
+
+ // Print the scopes regardless if the user has requested any scopes
+ // printing. Set the option just to allow printing the contributions.
+ printScopeSize(this, OS);
+ PrintScope(this);
+
+ // Print total scope sizes by level.
+ printTotals(OS);
+
+ options().resetPrintOffset();
+ options().setPrintFormatting();
+
+ if (!PrintScopes)
+ options().resetPrintScopes();
+}
+
+void LVScopeCompileUnit::printSummary(raw_ostream &OS) const {
+ printSummary(OS, Printed, "Printed");
+}
+
+// Print summary details for the scopes tree.
+void LVScopeCompileUnit::printSummary(raw_ostream &OS, const LVCounter &Counter,
+ const char *Header) const {
+ std::string Separator = std::string(29, '-');
+ auto PrintSeparator = [&]() { OS << Separator << "\n"; };
+ auto PrintHeadingRow = [&](const char *T, const char *U, const char *V) {
+ OS << format("%-9s%9s %9s\n", T, U, V);
+ };
+ auto PrintDataRow = [&](const char *T, unsigned U, unsigned V) {
+ OS << format("%-9s%9d %9d\n", T, U, V);
+ };
+
+ OS << "\n";
+ PrintSeparator();
+ PrintHeadingRow("Element", "Total", Header);
+ PrintSeparator();
+ PrintDataRow("Scopes", Allocated.Scopes, Counter.Scopes);
+ PrintDataRow("Symbols", Allocated.Symbols, Counter.Symbols);
+ PrintDataRow("Types", Allocated.Types, Counter.Types);
+ PrintDataRow("Lines", Allocated.Lines, Counter.Lines);
+ PrintSeparator();
+ PrintDataRow(
+ "Total",
+ Allocated.Scopes + Allocated.Symbols + Allocated.Lines + Allocated.Types,
+ Counter.Scopes + Counter.Symbols + Counter.Lines + Counter.Types);
+}
+
+void LVScopeCompileUnit::printMatchedElements(raw_ostream &OS,
+ bool UseMatchedElements) {
+ LVSortFunction SortFunction = getSortFunction();
+ if (SortFunction)
+ std::stable_sort(MatchedElements.begin(), MatchedElements.end(),
+ SortFunction);
+
+ // Check the type of elements required to be printed. 'MatchedElements'
+ // contains generic elements (lines, scopes, symbols, types). If we have a
+ // request to print any generic element, then allow the normal printing.
+ if (options().getPrintAnyElement()) {
+ if (UseMatchedElements)
+ OS << "\n";
+ print(OS);
+
+ if (UseMatchedElements) {
+ // Print the details for the matched elements.
+ for (const LVElement *Element : MatchedElements)
+ Element->print(OS);
+ } else {
+ // Print the view for the matched scopes.
+ for (const LVScope *Scope : MatchedScopes) {
+ Scope->print(OS);
+ if (const LVElements *Elements = Scope->getChildren())
+ for (LVElement *Element : *Elements)
+ Element->print(OS);
+ }
+ }
+
+ // Print any requested summary.
+ if (options().getPrintSummary()) {
+ // In the case of '--report=details' the matched elements are
+ // already counted; just proceed to print any requested summary.
+ // Otherwise, count them and print the summary.
+ if (!options().getReportList()) {
+ for (LVElement *Element : MatchedElements) {
+ if (!Element->getIncludeInPrint())
+ continue;
+ if (Element->getIsType())
+ ++Found.Types;
+ else if (Element->getIsSymbol())
+ ++Found.Symbols;
+ else if (Element->getIsScope())
+ ++Found.Scopes;
+ else if (Element->getIsLine())
+ ++Found.Lines;
+ else
+ assert(Element && "Invalid element.");
+ }
+ }
+ printSummary(OS, Found, "Printed");
+ }
+ }
+
+ // Check if we have a request to print sizes for the matched elements
+ // that are scopes.
+ if (options().getPrintSizes()) {
+ OS << "\n";
+ print(OS);
+
+ OS << "\nScope Sizes:\n";
+ printScopeSize(this, OS);
+ for (LVElement *Element : MatchedElements)
+ if (Element->getIsScope())
+ // Print sizes only for scopes.
+ printScopeSize(static_cast<LVScope *>(Element), OS);
+
+ printTotals(OS);
+ }
+}
+
+void LVScopeCompileUnit::print(raw_ostream &OS, bool Full) const {
+ // Reset counters for printed and found elements.
+ const_cast<LVScopeCompileUnit *>(this)->Found.reset();
+ const_cast<LVScopeCompileUnit *>(this)->Printed.reset();
+
+ if (getReader().doPrintScope(this) && options().getPrintFormatting())
+ OS << "\n";
+
+ LVScope::print(OS, Full);
+}
+
+void LVScopeCompileUnit::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " '" << getName() << "'\n";
+ if (options().getPrintFormatting() && options().getAttributeProducer())
+ printAttributes(OS, Full, "{Producer} ",
+ const_cast<LVScopeCompileUnit *>(this), getProducer(),
+ /*UseQuotes=*/true,
+ /*PrintRef=*/false);
+
+ // Reset file index, to allow its children to print the correct filename.
+ options().resetFilenameIndex();
+
+ // Print any files, directories, public names.
+ if (Full) {
+ printLocalNames(OS, Full);
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF enumeration (DW_TAG_enumeration_type).
+//===----------------------------------------------------------------------===//
+void LVScopeEnumeration::printExtra(raw_ostream &OS, bool Full) const {
+ // Print the full type name.
+ OS << formattedKind(kind()) << " " << (getIsEnumClass() ? "class " : "")
+ << formattedName(getName());
+ if (getHasType())
+ OS << " -> " << typeOffsetAsString()
+ << formattedNames(getTypeQualifiedName(), typeAsString());
+ OS << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF formal parameter pack (DW_TAG_GNU_formal_parameter_pack).
+//===----------------------------------------------------------------------===//
+void LVScopeFormalPack::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF function.
+//===----------------------------------------------------------------------===//
+void LVScopeFunction::resolveReferences() {
+ // Before we resolve any references to other elements, check if we have
+ // to insert missing elements, that have been stripped, which will help
+ // the logical view comparison.
+ if (options().getAttributeInserted() && getHasReferenceAbstract() &&
+ !getAddedMissing()) {
+ // Add missing elements at the function scope.
+ addMissingElements(getReference());
+ if (Scopes)
+ for (LVScope *Scope : *Scopes)
+ if (Scope->getHasReferenceAbstract() && !Scope->getAddedMissing())
+ Scope->addMissingElements(Scope->getReference());
+ }
+
+ LVScope::resolveReferences();
+
+ // The DWARF 'extern' attribute is generated at the class level.
+ // 0000003f DW_TAG_class_type "CLASS"
+ // 00000048 DW_TAG_subprogram "bar"
+ // DW_AT_external DW_FORM_flag_present
+ // 00000070 DW_TAG_subprogram "bar"
+ // DW_AT_specification DW_FORM_ref4 0x00000048
+ // If there is a reference linking the declaration and definition, mark
+ // the definition as extern, to facilitate the logical view comparison.
+ if (getHasReferenceSpecification()) {
+ LVScope *Reference = getReference();
+ if (Reference && Reference->getIsExternal()) {
+ Reference->resetIsExternal();
+ setIsExternal();
+ }
+ }
+
+ // Resolve the function associated type.
+ if (!getType())
+ if (LVScope *Reference = getReference())
+ setType(Reference->getType());
+}
+
+void LVScopeFunction::setName(StringRef ObjectName) {
+ LVScope::setName(ObjectName);
+ // Check for system generated functions.
+ getReader().isSystemEntry(this, ObjectName);
+}
+
+void LVScopeFunction::resolveExtra() {
+ // Check if we need to encode the template arguments.
+ if (getIsTemplate())
+ resolveTemplate();
+}
+
+void LVScopeFunction::printExtra(raw_ostream &OS, bool Full) const {
+ LVScope *Reference = getReference();
+
+ // Inline attributes based on the reference element.
+ uint32_t InlineCode =
+ Reference ? Reference->getInlineCode() : getInlineCode();
+
+ // Accessibility depends on the parent (class, structure).
+ uint32_t AccessCode = 0;
+ if (getIsMember())
+ AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private
+ : dwarf::DW_ACCESS_public;
+
+ std::string Attributes =
+ getIsCallSite()
+ ? ""
+ : formatAttributes(externalString(), accessibilityString(AccessCode),
+ inlineCodeString(InlineCode), virtualityString());
+
+ OS << formattedKind(kind()) << " " << Attributes << formattedName(getName())
+ << discriminatorAsString() << " -> " << typeOffsetAsString()
+ << formattedNames(getTypeQualifiedName(), typeAsString()) << "\n";
+
+ // Print any active ranges.
+ if (Full) {
+ if (getIsTemplateResolved())
+ printEncodedArgs(OS, Full);
+ if (Reference)
+ Reference->printReference(OS, Full, const_cast<LVScopeFunction *>(this));
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF inlined function (DW_TAG_inlined_function).
+//===----------------------------------------------------------------------===//
+void LVScopeFunctionInlined::resolveExtra() {
+ // Check if we need to encode the template arguments.
+ if (getIsTemplate())
+ resolveTemplate();
+}
+
+void LVScopeFunctionInlined::printExtra(raw_ostream &OS, bool Full) const {
+ LVScopeFunction::printExtra(OS, Full);
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF subroutine type.
+//===----------------------------------------------------------------------===//
+// Resolve a Subroutine Type (Callback).
+void LVScopeFunctionType::resolveExtra() {
+ if (getIsMemberPointerResolved())
+ return;
+ setIsMemberPointerResolved();
+
+ // The encoded string has the return type and the formal parameters type.
+ std::string Name(typeAsString());
+ Name.append(" (*)");
+ Name.append("(");
+
+ // Traverse the scope symbols, looking for those which are parameters.
+ if (const LVSymbols *Symbols = getSymbols()) {
+ bool AddComma = false;
+ for (LVSymbol *Symbol : *Symbols)
+ if (Symbol->getIsParameter()) {
+ Symbol->resolve();
+ if (LVElement *Type = Symbol->getType())
+ Type->resolveName();
+ if (AddComma)
+ Name.append(", ");
+ Name.append(std::string(Symbol->getTypeName()));
+ AddComma = true;
+ }
+ }
+
+ Name.append(")");
+
+ // Update the scope name, to reflect the encoded parameters.
+ setName(Name.c_str());
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF namespace (DW_TAG_namespace).
+//===----------------------------------------------------------------------===//
+void LVScopeNamespace::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
+
+ if (Full) {
+ if (LVScope *Reference = getReference())
+ Reference->printReference(OS, Full, const_cast<LVScopeNamespace *>(this));
+ }
+}
+
+void LVScopeRoot::print(raw_ostream &OS, bool Full) const {
+ OS << "\nLogical View:\n";
+ LVScope::print(OS, Full);
+}
+
+void LVScopeRoot::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << "";
+ if (options().getAttributeFormat())
+ OS << " -> " << getFileFormatName();
+ OS << "\n";
+}
+
+Error LVScopeRoot::doPrintMatches(bool Split, raw_ostream &OS,
+ bool UseMatchedElements) const {
+ // During a view output splitting, use the output stream created by the
+ // split context, then switch to the reader output stream.
+ static raw_ostream *StreamSplit = &OS;
+
+ if (Scopes) {
+ if (UseMatchedElements)
+ options().resetPrintFormatting();
+ print(OS);
+
+ for (LVScope *Scope : *Scopes) {
+ getReader().setCompileUnit(const_cast<LVScope *>(Scope));
+
+ // If 'Split', we use the scope name (CU name) as the ouput file; the
+ // delimiters in the pathname, must be replaced by a normal character.
+ if (Split) {
+ std::string ScopeName(Scope->getName());
+ if (std::error_code EC =
+ getReaderSplitContext().open(ScopeName, ".txt", OS))
+ return createStringError(EC, "Unable to create split output file %s",
+ ScopeName.c_str());
+ StreamSplit = static_cast<raw_ostream *>(&getReaderSplitContext().os());
+ }
+
+ Scope->printMatchedElements(*StreamSplit, UseMatchedElements);
+
+ // Done printing the compile unit. Restore the original output context.
+ if (Split) {
+ getReaderSplitContext().close();
+ StreamSplit = &getReader().outputStream();
+ }
+ }
+ if (UseMatchedElements)
+ options().setPrintFormatting();
+ }
+
+ return Error::success();
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF template parameter pack (DW_TAG_GNU_template_parameter_pack).
+//===----------------------------------------------------------------------===//
+void LVScopeTemplatePack::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
+}
--- /dev/null
+//===-- LVSort.cpp --------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Support for LVObject sorting.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Sort"
+
+//===----------------------------------------------------------------------===//
+// Callback functions to sort objects.
+//===----------------------------------------------------------------------===//
+// Callback comparator based on kind.
+LVSortValue llvm::logicalview::compareKind(const LVObject *LHS,
+ const LVObject *RHS) {
+ return std::string(LHS->kind()) < std::string(RHS->kind());
+}
+
+// Callback comparator based on line.
+LVSortValue llvm::logicalview::compareLine(const LVObject *LHS,
+ const LVObject *RHS) {
+ return LHS->getLineNumber() < RHS->getLineNumber();
+}
+
+// Callback comparator based on name.
+LVSortValue llvm::logicalview::compareName(const LVObject *LHS,
+ const LVObject *RHS) {
+ return LHS->getName() < RHS->getName();
+}
+
+// Callback comparator based on DIE offset.
+LVSortValue llvm::logicalview::compareOffset(const LVObject *LHS,
+ const LVObject *RHS) {
+ return LHS->getOffset() < RHS->getOffset();
+}
+
+// Callback comparator based on multiple keys (First: Kind).
+LVSortValue llvm::logicalview::sortByKind(const LVObject *LHS,
+ const LVObject *RHS) {
+ // Order in which the object attributes are used for comparison:
+ // kind, name, line number, offset.
+ std::tuple<std::string, StringRef, uint32_t, LVOffset> Left(
+ LHS->kind(), LHS->getName(), LHS->getLineNumber(), LHS->getOffset());
+ std::tuple<std::string, StringRef, uint32_t, LVOffset> Right(
+ RHS->kind(), RHS->getName(), RHS->getLineNumber(), RHS->getOffset());
+ return Left < Right;
+}
+
+// Callback comparator based on multiple keys (First: Line).
+LVSortValue llvm::logicalview::sortByLine(const LVObject *LHS,
+ const LVObject *RHS) {
+ // Order in which the object attributes are used for comparison:
+ // line number, name, kind, offset.
+ std::tuple<uint32_t, StringRef, std::string, LVOffset> Left(
+ LHS->getLineNumber(), LHS->getName(), LHS->kind(), LHS->getOffset());
+ std::tuple<uint32_t, StringRef, std::string, LVOffset> Right(
+ RHS->getLineNumber(), RHS->getName(), RHS->kind(), RHS->getOffset());
+ return Left < Right;
+}
+
+// Callback comparator based on multiple keys (First: Name).
+LVSortValue llvm::logicalview::sortByName(const LVObject *LHS,
+ const LVObject *RHS) {
+ // Order in which the object attributes are used for comparison:
+ // name, line number, kind, offset.
+ std::tuple<StringRef, uint32_t, std::string, LVOffset> Left(
+ LHS->getName(), LHS->getLineNumber(), LHS->kind(), LHS->getOffset());
+ std::tuple<StringRef, uint32_t, std::string, LVOffset> Right(
+ RHS->getName(), RHS->getLineNumber(), RHS->kind(), RHS->getOffset());
+ return Left < Right;
+}
+
+LVSortFunction llvm::logicalview::getSortFunction() {
+ using LVSortInfo = std::map<LVSortMode, LVSortFunction>;
+ static LVSortInfo SortInfo = {
+ {LVSortMode::None, nullptr}, {LVSortMode::Kind, sortByKind},
+ {LVSortMode::Line, sortByLine}, {LVSortMode::Name, sortByName},
+ {LVSortMode::Offset, compareOffset},
+ };
+
+ LVSortFunction SortFunction = nullptr;
+ LVSortInfo::iterator Iter = SortInfo.find(options().getSortMode());
+ if (Iter != SortInfo.end())
+ SortFunction = Iter->second;
+ return SortFunction;
+}
--- /dev/null
+//===-- LVSupport.cpp -----------------------------------------------------===//
+//
+// 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 implements the supporting functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVSupport.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <iomanip>
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Support"
+
+// Perform the following transformations to the given 'Path':
+// - all characters to lowercase.
+// - '\\' into '/' (Platform independent).
+// - '//' into '/'
+std::string llvm::logicalview::transformPath(StringRef Path) {
+ std::string Name(Path);
+ std::transform(Name.begin(), Name.end(), Name.begin(), tolower);
+ std::replace(Name.begin(), Name.end(), '\\', '/');
+
+ // Remove all duplicate slashes.
+ size_t Pos = 0;
+ while ((Pos = Name.find("//", Pos)) != std::string::npos)
+ Name.erase(Pos, 1);
+
+ return Name;
+}
+
+// Convert the given 'Path' to lowercase and change any matching character
+// from 'CharSet' into '_'.
+// The characters in 'CharSet' are:
+// '/', '\', '<', '>', '.', ':', '%', '*', '?', '|', '"', ' '.
+std::string llvm::logicalview::flattenedFilePath(StringRef Path) {
+ std::string Name(Path);
+ std::transform(Name.begin(), Name.end(), Name.begin(), tolower);
+
+ const char *CharSet = "/\\<>.:%*?|\" ";
+ char *Input = Name.data();
+ while (Input && *Input) {
+ Input = strpbrk(Input, CharSet);
+ if (Input)
+ *Input++ = '_';
+ };
+ return Name;
+}
--- /dev/null
+//===-- LVSymbol.cpp ------------------------------------------------------===//
+//
+// 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 implements the LVSymbol class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Symbol"
+
+namespace {
+const char *const KindCallSiteParameter = "CallSiteParameter";
+const char *const KindConstant = "Constant";
+const char *const KindInherits = "Inherits";
+const char *const KindMember = "Member";
+const char *const KindParameter = "Parameter";
+const char *const KindUndefined = "Undefined";
+const char *const KindUnspecified = "Unspecified";
+const char *const KindVariable = "Variable";
+} // end anonymous namespace
+
+// Return a string representation for the symbol kind.
+const char *LVSymbol::kind() const {
+ const char *Kind = KindUndefined;
+ if (getIsCallSiteParameter())
+ Kind = KindCallSiteParameter;
+ else if (getIsConstant())
+ Kind = KindConstant;
+ else if (getIsInheritance())
+ Kind = KindInherits;
+ else if (getIsMember())
+ Kind = KindMember;
+ else if (getIsParameter())
+ Kind = KindParameter;
+ else if (getIsUnspecified())
+ Kind = KindUnspecified;
+ else if (getIsVariable())
+ Kind = KindVariable;
+ return Kind;
+}
+
+void LVSymbol::resolveName() {
+ if (getIsResolvedName())
+ return;
+ setIsResolvedName();
+
+ LVElement::resolveName();
+}
+
+void LVSymbol::resolveReferences() {
+ // The symbols can have the following references to other elements:
+ // A Type:
+ // DW_AT_type -> Type or Scope
+ // DW_AT_import -> Type
+ // A Reference:
+ // DW_AT_specification -> Symbol
+ // DW_AT_abstract_origin -> Symbol
+ // DW_AT_extension -> Symbol
+
+ // Resolve any referenced symbol.
+ LVSymbol *Reference = getReference();
+ if (Reference) {
+ Reference->resolve();
+ // Recursively resolve the symbol names.
+ resolveReferencesChain();
+ }
+
+ // Set the file/line information using the Debug Information entry.
+ setFile(Reference);
+
+ // Resolve symbol type.
+ if (LVElement *Element = getType()) {
+ Element->resolve();
+
+ // In the case of demoted typedefs, use the underlying type.
+ if (Element->getIsTypedefReduced()) {
+ Element = Element->getType();
+ Element->resolve();
+ }
+
+ // If the type is a template parameter, get its type, which can
+ // point to a type or scope, depending on the argument instance.
+ setGenericType(Element);
+ }
+
+ // Resolve the variable associated type.
+ if (!getType() && Reference)
+ setType(Reference->getType());
+}
+
+StringRef LVSymbol::resolveReferencesChain() {
+ // If the symbol have a DW_AT_specification or DW_AT_abstract_origin,
+ // follow the chain to resolve the name from those references.
+ if (getHasReference() && !isNamed())
+ setName(getReference()->resolveReferencesChain());
+
+ return getName();
+}
+
+void LVSymbol::print(raw_ostream &OS, bool Full) const {
+ if (getIncludeInPrint() && getReader().doPrintSymbol(this)) {
+ getReaderCompileUnit()->incrementPrintedSymbols();
+ LVElement::print(OS, Full);
+ printExtra(OS, Full);
+ }
+}
+
+void LVSymbol::printExtra(raw_ostream &OS, bool Full) const {
+ // Accessibility depends on the parent (class, structure).
+ uint32_t AccessCode = 0;
+ if (getIsMember() || getIsInheritance())
+ AccessCode = getParentScope()->getIsClass() ? dwarf::DW_ACCESS_private
+ : dwarf::DW_ACCESS_public;
+
+ const LVSymbol *Symbol = getIsInlined() ? Reference : this;
+ std::string Attributes =
+ Symbol->getIsCallSiteParameter()
+ ? ""
+ : formatAttributes(Symbol->externalString(),
+ Symbol->accessibilityString(AccessCode),
+ virtualityString());
+
+ OS << formattedKind(Symbol->kind()) << " " << Attributes;
+ if (Symbol->getIsUnspecified())
+ OS << formattedName(Symbol->getName());
+ else {
+ if (Symbol->getIsInheritance())
+ OS << Symbol->typeOffsetAsString()
+ << formattedNames(Symbol->getTypeQualifiedName(),
+ Symbol->typeAsString());
+ else {
+ OS << formattedName(Symbol->getName());
+ // Print any bitfield information.
+ if (uint32_t Size = getBitSize())
+ OS << ":" << Size;
+ OS << " -> " << Symbol->typeOffsetAsString()
+ << formattedNames(Symbol->getTypeQualifiedName(),
+ Symbol->typeAsString());
+ }
+ }
+
+ // Print any initial value if any.
+ if (ValueIndex)
+ OS << " = " << formattedName(getValue());
+ OS << "\n";
+
+ if (Full && options().getPrintFormatting()) {
+ if (getLinkageNameIndex())
+ printLinkageName(OS, Full, const_cast<LVSymbol *>(this));
+ if (LVSymbol *Reference = getReference())
+ Reference->printReference(OS, Full, const_cast<LVSymbol *>(this));
+ }
+}
--- /dev/null
+//===-- LVType.cpp --------------------------------------------------------===//
+//
+// 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 implements the LVType class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Type"
+
+namespace {
+const char *const KindBaseType = "BaseType";
+const char *const KindConst = "Const";
+const char *const KindEnumerator = "Enumerator";
+const char *const KindImport = "Import";
+const char *const KindPointer = "Pointer";
+const char *const KindPointerMember = "PointerMember";
+const char *const KindReference = "Reference";
+const char *const KindRestrict = "Restrict";
+const char *const KindRvalueReference = "RvalueReference";
+const char *const KindSubrange = "Subrange";
+const char *const KindTemplateTemplate = "TemplateTemplate";
+const char *const KindTemplateType = "TemplateType";
+const char *const KindTemplateValue = "TemplateValue";
+const char *const KindTypeAlias = "TypeAlias";
+const char *const KindUndefined = "Undefined";
+const char *const KindUnaligned = "Unaligned";
+const char *const KindUnspecified = "Unspecified";
+const char *const KindVolatile = "Volatile";
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// DWARF Type.
+//===----------------------------------------------------------------------===//
+// Return a string representation for the type kind.
+const char *LVType::kind() const {
+ const char *Kind = KindUndefined;
+ if (getIsBase())
+ Kind = KindBaseType;
+ else if (getIsConst())
+ Kind = KindConst;
+ else if (getIsEnumerator())
+ Kind = KindEnumerator;
+ else if (getIsImport())
+ Kind = KindImport;
+ else if (getIsPointerMember())
+ Kind = KindPointerMember;
+ else if (getIsPointer())
+ Kind = KindPointer;
+ else if (getIsReference())
+ Kind = KindReference;
+ else if (getIsRestrict())
+ Kind = KindRestrict;
+ else if (getIsRvalueReference())
+ Kind = KindRvalueReference;
+ else if (getIsSubrange())
+ Kind = KindSubrange;
+ else if (getIsTemplateTypeParam())
+ Kind = KindTemplateType;
+ else if (getIsTemplateValueParam())
+ Kind = KindTemplateValue;
+ else if (getIsTemplateTemplateParam())
+ Kind = KindTemplateTemplate;
+ else if (getIsTypedef())
+ Kind = KindTypeAlias;
+ else if (getIsUnaligned())
+ Kind = KindUnaligned;
+ else if (getIsUnspecified())
+ Kind = KindUnspecified;
+ else if (getIsVolatile())
+ Kind = KindVolatile;
+ return Kind;
+}
+
+void LVType::resolveReferences() {
+ // Some DWARF tags are the representation of types. However, we associate
+ // some of them to scopes. The ones associated with types, do not have
+ // any reference tags, such as DW_AT_specification, DW_AT_abstract_origin,
+ // DW_AT_extension.
+
+ // Set the file/line information using the Debug Information entry.
+ setFile(/*Reference=*/nullptr);
+
+ if (LVElement *Element = getType())
+ Element->resolve();
+}
+
+void LVType::resolveName() {
+ if (getIsResolvedName())
+ return;
+ setIsResolvedName();
+
+ // The templates are recorded as normal DWARF objects relationships;
+ // the template parameters are preserved to show the types used during
+ // the instantiation; however if a compare have been requested, those
+ // parameters needs to be resolved, so no conflicts are generated.
+ // The following DWARF illustrates this issue:
+ //
+ // a) Template Parameters are preserved:
+ // {Class} 'ConstArray<AtomTable>'
+ // {Inherits} -> 'ArrayBase'
+ // {TemplateType} 'taTYPE' -> 'AtomTable'
+ // {Member} 'mData' -> '* taTYPE'
+ //
+ // b) Template Parameters are resolved:
+ // {Class} 'ConstArray<AtomTable>'
+ // {Inherits} -> 'ArrayBase'
+ // {TemplateType} 'taTYPE' -> 'AtomTable'
+ // {Member} 'mData' -> '* AtomTable'
+ //
+ // In (b), the {Member} type have been resolved to use the real type.
+
+ LVElement *BaseType = getType();
+ if (BaseType && options().getAttributeArgument())
+ if (BaseType->isTemplateParam())
+ BaseType = BaseType->getType();
+
+ if (BaseType && !BaseType->getIsResolvedName())
+ BaseType->resolveName();
+ resolveFullname(BaseType, getName());
+
+ // In the case of unnamed types, try to generate a name for it, using
+ // the parents name and the line information. Ignore the template parameters.
+ if (!isNamed() && !getIsTemplateParam())
+ generateName();
+
+ LVElement::resolveName();
+}
+
+StringRef LVType::resolveReferencesChain() {
+ // The types do not have a DW_AT_specification or DW_AT_abstract_origin
+ // reference. Just return the type name.
+ return getName();
+}
+
+void LVType::print(raw_ostream &OS, bool Full) const {
+ if (getIncludeInPrint() &&
+ (getIsReference() || getReader().doPrintType(this))) {
+ getReaderCompileUnit()->incrementPrintedTypes();
+ LVElement::print(OS, Full);
+ printExtra(OS, Full);
+ }
+}
+
+void LVType::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF typedef.
+//===----------------------------------------------------------------------===//
+// Return the underlying type for a typedef, which can be a type or scope.
+LVElement *LVTypeDefinition::getUnderlyingType() {
+ LVElement *BaseType = getTypeAsScope();
+ if (BaseType)
+ // Underlying type is a scope.
+ return BaseType;
+
+ LVType *Type = getTypeAsType();
+ assert(Type && "Type definition does not have a type.");
+
+ BaseType = Type;
+ while (Type->getIsTypedef()) {
+ BaseType = Type->getTypeAsScope();
+ if (BaseType)
+ // Underlying type is a scope.
+ return BaseType;
+
+ Type = Type->getTypeAsType();
+ if (Type)
+ BaseType = Type;
+ }
+
+ return BaseType;
+}
+
+void LVTypeDefinition::resolveExtra() {
+ // Set the reference to the typedef type.
+ if (options().getAttributeUnderlying()) {
+ setUnderlyingType(getUnderlyingType());
+ setIsTypedefReduced();
+ if (LVElement *Type = getType()) {
+ Type->resolveName();
+ resolveFullname(Type);
+ }
+ }
+
+ // For the case of typedef'd anonymous structures:
+ // typedef struct { ... } Name;
+ // Propagate the typedef name to the anonymous structure.
+ LVScope *Aggregate = getTypeAsScope();
+ if (Aggregate && Aggregate->getIsAnonymous())
+ Aggregate->setName(getName());
+}
+
+void LVTypeDefinition::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> "
+ << typeOffsetAsString()
+ << formattedName((getType() ? getType()->getName() : "")) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF enumerator (DW_TAG_enumerator).
+//===----------------------------------------------------------------------===//
+void LVTypeEnumerator::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " '" << getName()
+ << "' = " << formattedName(getValue()) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF import (DW_TAG_imported_module / DW_TAG_imported_declaration).
+//===----------------------------------------------------------------------===//
+void LVTypeImport::printExtra(raw_ostream &OS, bool Full) const {
+ std::string Attributes =
+ formatAttributes(virtualityString(), accessibilityString());
+
+ OS << formattedKind(kind()) << " " << typeOffsetAsString() << Attributes
+ << formattedName((getType() ? getType()->getName() : "")) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF Template parameter holder (type or param).
+//===----------------------------------------------------------------------===//
+LVTypeParam::LVTypeParam() : LVType() {
+ options().getAttributeTypename() ? setIncludeInPrint()
+ : resetIncludeInPrint();
+}
+
+// Encode the specific template argument.
+void LVTypeParam::encodeTemplateArgument(std::string &Name) const {
+ // The incoming type is a template parameter; we have 3 kinds of parameters:
+ // - type parameter: resolve the instance (type);
+ // - value parameter: resolve the constant value
+ // - template parameter: resolve the name of the template.
+ // If the parameter type is a template instance (STL sample), we need to
+ // expand the type (template template case). For the following variable
+ // declarations:
+ // std::type<float> a_float;
+ // std::type<int> a_int;
+ // We must generate names like:
+ // "std::type<float,std::less<float>,std::allocator<float>,false>"
+ // "std::type<int,std::less<int>,std::allocator<int>,false>"
+ // Instead of the incomplete names:
+ // "type<float,less,allocator,false>"
+ // "type<int,less,allocator,false>"
+
+ if (getIsTemplateTypeParam()) {
+ // Get the type instance recorded in the template type; it can be a
+ // reference to a type or to a scope.
+
+ if (getIsKindType()) {
+ // The argument types always are qualified.
+ Name.append(std::string(getTypeQualifiedName()));
+
+ LVType *ArgType = getTypeAsType();
+ // For template arguments that are typedefs, use the underlying type,
+ // which can be a type or scope.
+ if (ArgType->getIsTypedef()) {
+ LVObject *BaseType = ArgType->getUnderlyingType();
+ Name.append(std::string(BaseType->getName()));
+ } else {
+ Name.append(std::string(ArgType->getName()));
+ }
+ } else {
+ if (getIsKindScope()) {
+ LVScope *ArgScope = getTypeAsScope();
+ // If the scope is a template, we have to resolve that template,
+ // by recursively traversing its arguments.
+ if (ArgScope->getIsTemplate())
+ ArgScope->encodeTemplateArguments(Name);
+ else {
+ // The argument types always are qualified.
+ Name.append(std::string(getTypeQualifiedName()));
+ Name.append(std::string(ArgScope->getName()));
+ }
+ }
+ }
+ } else
+ // Template value parameter or template template parameter.
+ Name.append(getValue());
+}
+
+void LVTypeParam::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " " << formattedName(getName()) << " -> "
+ << typeOffsetAsString();
+
+ // Depending on the type of parameter, the print includes different
+ // information: type, value or reference to a template.
+ if (getIsTemplateTypeParam()) {
+ OS << formattedNames(getTypeQualifiedName(), getTypeName()) << "\n";
+ return;
+ }
+ if (getIsTemplateValueParam()) {
+ OS << formattedName(getValue()) << " " << formattedName(getName()) << "\n";
+ return;
+ }
+ if (getIsTemplateTemplateParam())
+ OS << formattedName(getValue()) << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DW_TAG_subrange_type
+//===----------------------------------------------------------------------===//
+void LVTypeSubrange::resolveExtra() {
+ // There are 2 cases to represent the bounds information for an array:
+ // 1) DW_TAG_subrange_type
+ // DW_AT_type --> ref_type (type of count)
+ // DW_AT_count --> value (number of elements in subrange)
+
+ // 2) DW_TAG_subrange_type
+ // DW_AT_lower_bound --> value
+ // DW_AT_upper_bound --> value
+
+ // The idea is to represent the bounds as a string, depending on the format:
+ // 1) [count]
+ // 2) [lower..upper]
+
+ // Subrange information.
+ std::string String;
+
+ // Check if we have DW_AT_count subrange style.
+ if (getIsSubrangeCount())
+ // Get count subrange value. Assume 0 if missing.
+ raw_string_ostream(String) << "[" << getCount() << "]";
+ else
+ raw_string_ostream(String)
+ << "[" << getLowerBound() << ".." << getUpperBound() << "]";
+
+ setName(String);
+}
+
+void LVTypeSubrange::printExtra(raw_ostream &OS, bool Full) const {
+ OS << formattedKind(kind()) << " -> " << typeOffsetAsString()
+ << formattedName(getTypeName()) << " " << formattedName(getName()) << "\n";
+}
add_llvm_unittest(DebugInfoLogicalViewTests
CommandLineOptionsTest.cpp
+ LogicalElementsTest.cpp
StringPoolTest.cpp
)
--- /dev/null
+//===- llvm/unittest/DebugInfo/LogicalView/LogicalElementsTest.cpp --------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+namespace {
+
+class ReaderTestElements : public LVReader {
+ // Types.
+ LVType *IntegerType = nullptr;
+ LVType *UnsignedType = nullptr;
+ LVType *GlobalType = nullptr;
+ LVType *LocalType = nullptr;
+ LVType *NestedType = nullptr;
+ LVTypeDefinition *TypeDefinitionOne = nullptr;
+ LVTypeDefinition *TypeDefinitionTwo = nullptr;
+ LVTypeEnumerator *EnumeratorOne = nullptr;
+ LVTypeEnumerator *EnumeratorTwo = nullptr;
+ LVTypeImport *TypeImport = nullptr;
+ LVTypeParam *TypeParam = nullptr;
+ LVTypeSubrange *TypeSubrange = nullptr;
+
+ // Scopes.
+ LVScope *NestedScope = nullptr;
+ LVScopeAggregate *Aggregate = nullptr;
+ LVScopeArray *Array = nullptr;
+ LVScopeEnumeration *Enumeration = nullptr;
+ LVScopeFunction *Function = nullptr;
+ LVScopeFunction *ClassFunction = nullptr;
+ LVScopeFunctionInlined *InlinedFunction = nullptr;
+ LVScopeNamespace *Namespace = nullptr;
+
+ // Symbols.
+ LVSymbol *GlobalVariable = nullptr;
+ LVSymbol *LocalVariable = nullptr;
+ LVSymbol *ClassMember = nullptr;
+ LVSymbol *NestedVariable = nullptr;
+ LVSymbol *Parameter = nullptr;
+
+ // Lines.
+ LVLine *LocalLine = nullptr;
+ LVLine *NestedLine = nullptr;
+
+protected:
+ void add(LVScope *Parent, LVElement *Element);
+ template <typename T> T *create() {
+ T *Element = new (std::nothrow) T();
+ EXPECT_NE(Element, nullptr);
+ return Element;
+ }
+ void set(LVElement *Element, StringRef Name, LVOffset Offset,
+ uint32_t LineNumber = 0, LVElement *Type = nullptr);
+
+public:
+ ReaderTestElements(ScopedPrinter &W) : LVReader("", "", W) {
+ setInstance(this);
+ }
+
+ Error createScopes() { return LVReader::createScopes(); }
+ Error printScopes() { return LVReader::printScopes(); }
+
+ void createElements();
+ void addElements();
+ void initElements();
+};
+
+// Helper function to add a logical element to a given scope.
+void ReaderTestElements::add(LVScope *Parent, LVElement *Child) {
+ Parent->addElement(Child);
+ EXPECT_EQ(Child->getParent(), Parent);
+ EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1);
+}
+
+// Helper function to set the initial values for a given logical element.
+void ReaderTestElements::set(LVElement *Element, StringRef Name,
+ LVOffset Offset, uint32_t LineNumber,
+ LVElement *Type) {
+ Element->setName(Name);
+ Element->setOffset(Offset);
+ Element->setLineNumber(LineNumber);
+ Element->setType(Type);
+ EXPECT_EQ(Element->getName(), Name);
+ EXPECT_EQ(Element->getOffset(), Offset);
+ EXPECT_EQ(Element->getLineNumber(), LineNumber);
+ EXPECT_EQ(Element->getType(), Type);
+}
+
+// Create the logical elements.
+void ReaderTestElements::createElements() {
+ // Create scope root.
+ Error Err = createScopes();
+ ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+ Root = getScopesRoot();
+ ASSERT_NE(Root, nullptr);
+
+ // Create the logical types.
+ IntegerType = create<LVType>();
+ UnsignedType = create<LVType>();
+ GlobalType = create<LVType>();
+ LocalType = create<LVType>();
+ NestedType = create<LVType>();
+ EnumeratorOne = create<LVTypeEnumerator>();
+ EnumeratorTwo = create<LVTypeEnumerator>();
+ TypeDefinitionOne = create<LVTypeDefinition>();
+ TypeDefinitionTwo = create<LVTypeDefinition>();
+ TypeSubrange = create<LVTypeSubrange>();
+ TypeParam = create<LVTypeParam>();
+ TypeImport = create<LVTypeImport>();
+
+ // Create the logical scopes.
+ NestedScope = create<LVScope>();
+ Aggregate = create<LVScopeAggregate>();
+ Array = create<LVScopeArray>();
+ CompileUnit = create<LVScopeCompileUnit>();
+ Enumeration = create<LVScopeEnumeration>();
+ Function = create<LVScopeFunction>();
+ ClassFunction = create<LVScopeFunction>();
+ InlinedFunction = create<LVScopeFunctionInlined>();
+ Namespace = create<LVScopeNamespace>();
+
+ // Create the logical symbols.
+ GlobalVariable = create<LVSymbol>();
+ LocalVariable = create<LVSymbol>();
+ ClassMember = create<LVSymbol>();
+ NestedVariable = create<LVSymbol>();
+ Parameter = create<LVSymbol>();
+
+ // Create the logical lines.
+ LocalLine = create<LVLine>();
+ NestedLine = create<LVLine>();
+}
+
+// Create the logical view adding the created logical elements.
+void ReaderTestElements::addElements() {
+ setCompileUnit(CompileUnit);
+
+ // Root
+ // CompileUnit
+ // IntegerType
+ // UnsignedType
+ // Array
+ // TypeSubrange
+ // Function
+ // Parameter
+ // LocalVariable
+ // LocalType
+ // LocalLine
+ // InlinedFunction
+ // TypeImport
+ // TypeParam
+ // NestedScope
+ // NestedVariable
+ // NestedType
+ // NestedLine
+ // GlobalVariable
+ // GlobalType
+ // Namespace
+ // Aggregate
+ // ClassMember
+ // ClassFunction
+ // Enumeration
+ // EnumeratorOne
+ // EnumeratorTwo
+ // TypeDefinitionOne
+ // TypeDefinitionTwo
+
+ add(Root, CompileUnit);
+ EXPECT_EQ(Root->lineCount(), 0u);
+ EXPECT_EQ(Root->scopeCount(), 1u);
+ EXPECT_EQ(Root->symbolCount(), 0u);
+ EXPECT_EQ(Root->typeCount(), 0u);
+
+ // Add elements to CompileUnit.
+ add(CompileUnit, IntegerType);
+ add(CompileUnit, UnsignedType);
+ add(CompileUnit, Array);
+ add(CompileUnit, Function);
+ add(CompileUnit, GlobalVariable);
+ add(CompileUnit, GlobalType);
+ add(CompileUnit, Namespace);
+ EXPECT_EQ(CompileUnit->lineCount(), 0u);
+ EXPECT_EQ(CompileUnit->scopeCount(), 3u);
+ EXPECT_EQ(CompileUnit->symbolCount(), 1u);
+ EXPECT_EQ(CompileUnit->typeCount(), 3u);
+
+ // Add elements to Namespace.
+ add(Namespace, Aggregate);
+ add(Namespace, Enumeration);
+ add(Namespace, TypeDefinitionOne);
+ add(Namespace, TypeDefinitionTwo);
+ EXPECT_EQ(Namespace->lineCount(), 0u);
+ EXPECT_EQ(Namespace->scopeCount(), 2u);
+ EXPECT_EQ(Namespace->symbolCount(), 0u);
+ EXPECT_EQ(Namespace->typeCount(), 2u);
+
+ // Add elements to Function.
+ add(Function, Parameter);
+ add(Function, LocalVariable);
+ add(Function, LocalType);
+ add(Function, LocalLine);
+ add(Function, InlinedFunction);
+ add(Function, TypeImport);
+ add(Function, TypeParam);
+ add(Function, NestedScope);
+ EXPECT_EQ(Function->lineCount(), 1u);
+ EXPECT_EQ(Function->scopeCount(), 2u);
+ EXPECT_EQ(Function->symbolCount(), 2u);
+ EXPECT_EQ(Function->typeCount(), 3u);
+
+ // Add elements to NestedScope.
+ add(NestedScope, NestedVariable);
+ add(NestedScope, NestedType);
+ add(NestedScope, NestedLine);
+ EXPECT_EQ(NestedScope->lineCount(), 1u);
+ EXPECT_EQ(NestedScope->scopeCount(), 0u);
+ EXPECT_EQ(NestedScope->symbolCount(), 1u);
+ EXPECT_EQ(NestedScope->typeCount(), 1u);
+
+ // Add elements to Enumeration.
+ add(Enumeration, EnumeratorOne);
+ add(Enumeration, EnumeratorTwo);
+ EXPECT_EQ(Enumeration->lineCount(), 0u);
+ EXPECT_EQ(Enumeration->scopeCount(), 0u);
+ EXPECT_EQ(Enumeration->symbolCount(), 0u);
+ EXPECT_EQ(Enumeration->typeCount(), 2u);
+
+ // Add elements to Aggregate.
+ add(Aggregate, ClassMember);
+ add(Aggregate, ClassFunction);
+ EXPECT_EQ(Aggregate->lineCount(), 0u);
+ EXPECT_EQ(Aggregate->scopeCount(), 1u);
+ EXPECT_EQ(Aggregate->symbolCount(), 1u);
+ EXPECT_EQ(Aggregate->typeCount(), 0u);
+
+ // Add elements to Array.
+ add(Array, TypeSubrange);
+ EXPECT_EQ(Array->lineCount(), 0u);
+ EXPECT_EQ(Array->scopeCount(), 0u);
+ EXPECT_EQ(Array->symbolCount(), 0u);
+ EXPECT_EQ(Array->typeCount(), 1u);
+}
+
+// Set initial values to logical elements.
+void ReaderTestElements::initElements() {
+ setFilename("LogicalElements.obj");
+ EXPECT_EQ(getFilename(), "LogicalElements.obj");
+
+ Root->setFileFormatName("FileFormat");
+ EXPECT_EQ(Root->getFileFormatName(), "FileFormat");
+
+ // Types.
+ set(IntegerType, "int", 0x1000);
+ set(UnsignedType, "unsigned", 0x1010);
+ set(GlobalType, "GlobalType", 0x1020, 1020);
+ set(LocalType, "LocalType", 0x1030, 1030);
+ set(NestedType, "NestedType", 0x1040, 1040);
+
+ set(TypeDefinitionOne, "INTEGER", 0x1040, 1040, IntegerType);
+ set(TypeDefinitionTwo, "INT", 0x1050, 1050, TypeDefinitionOne);
+ EXPECT_EQ(TypeDefinitionOne->getUnderlyingType(), IntegerType);
+ EXPECT_EQ(TypeDefinitionTwo->getUnderlyingType(), IntegerType);
+
+ set(EnumeratorOne, "one", 0x1060, 1060);
+ EnumeratorOne->setValue("blue");
+ EXPECT_EQ(EnumeratorOne->getValue(), "blue");
+
+ set(EnumeratorTwo, "two", 0x1070, 1070);
+ EnumeratorTwo->setValue("red");
+ EXPECT_EQ(EnumeratorTwo->getValue(), "red");
+
+ set(TypeSubrange, "", 0x1080, 1080, IntegerType);
+ TypeSubrange->setCount(5);
+ EXPECT_EQ(TypeSubrange->getCount(), 5);
+
+ TypeSubrange->setLowerBound(10);
+ TypeSubrange->setUpperBound(15);
+ EXPECT_EQ(TypeSubrange->getLowerBound(), 10);
+ EXPECT_EQ(TypeSubrange->getUpperBound(), 15);
+
+ TypeSubrange->setBounds(20, 25);
+ std::pair<unsigned, unsigned> Pair;
+ Pair = TypeSubrange->getBounds();
+ EXPECT_EQ(Pair.first, 20u);
+ EXPECT_EQ(Pair.second, 25u);
+
+ set(TypeParam, "INTEGER", 0x1090, 1090, UnsignedType);
+ TypeParam->setValue("10");
+ EXPECT_EQ(TypeParam->getValue(), "10");
+
+ set(TypeImport, "", 0x1090, 1090, Aggregate);
+ EXPECT_EQ(TypeImport->getType(), Aggregate);
+
+ // Scopes.
+ set(Aggregate, "Class", 0x2000, 2000);
+ set(Enumeration, "Colors", 0x2010, 2010);
+ set(Function, "function", 0x2020, 2020, GlobalType);
+ set(ClassFunction, "foo", 0x2030, 2030, TypeDefinitionTwo);
+ set(Namespace, "nsp", 0x2040, 2040);
+ set(NestedScope, "", 0x2050, 2050);
+ set(Array, "", 0x2060, 2060, UnsignedType);
+ set(InlinedFunction, "bar", 0x2070, 2070, TypeDefinitionOne);
+ set(CompileUnit, "test.cpp", 0x2080, 2080);
+
+ // Symbols.
+ set(GlobalVariable, "GlobalVariable", 0x3000, 3000);
+ set(LocalVariable, "LocalVariable", 0x3010, 3010, TypeDefinitionOne);
+ set(ClassMember, "Member", 0x3020, 3020, IntegerType);
+ set(Parameter, "Param", 0x3030, 3030, UnsignedType);
+ set(NestedVariable, "NestedVariable", 0x3040, 3040);
+
+ // Lines.
+ set(LocalLine, "", 0x4000, 4000);
+ set(NestedLine, "", 0x4010, 4010);
+}
+
+TEST(LogicalViewTest, LogicalElements) {
+ ScopedPrinter W(outs());
+ ReaderTestElements Reader(W);
+
+ Reader.createElements();
+ Reader.addElements();
+ Reader.initElements();
+}
+
+} // namespace