[llvm] e28b935 - [llvm-debuginfo-analyzer] (03/09) - Logical elements

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 19 22:20:07 PDT 2022


Author: Carlos Alberto Enciso
Date: 2022-10-20T06:19:20+01:00
New Revision: e28b9357b14c84f1b48646b64eed01fb19dad250

URL: https://github.com/llvm/llvm-project/commit/e28b9357b14c84f1b48646b64eed01fb19dad250
DIFF: https://github.com/llvm/llvm-project/commit/e28b9357b14c84f1b48646b64eed01fb19dad250.diff

LOG: [llvm-debuginfo-analyzer] (03/09) - Logical elements

llvm-debuginfo-analyzer is a command line tool that processes debug
info contained in a binary file and produces a debug information
format agnostic “Logical View”, which is a high-level semantic
representation of the debug info, independent of the low-level
format.

The code has been divided into the following patches:

1) Interval tree
2) Driver and documentation
3) Logical elements
4) Locations and ranges
5) Select elements
6) Warning and internal options
7) Compare elements
8) ELF Reader
9) CodeView Reader

Full details:
https://discourse.llvm.org/t/llvm-dev-rfc-llvm-dva-debug-information-visual-analyzer/62570

This patch:

Logical elements
- All basic functionality for the logical elements:
  LVScope, LVLine, LVSymbol, LVType.
- The logical reader:
  LVReader.h

Reviewed By: psamolysov, probinson

Differential Revision: https://reviews.llvm.org/D125778

Added: 
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
    llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVSupport.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
    llvm/unittests/DebugInfo/LogicalView/LogicalElementsTest.cpp

Modified: 
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
    llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
    llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
index a622c499b48a..6bd06da94289 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVElement.h
@@ -16,37 +16,320 @@
 
 #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

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
index 552e9bb792cb..98ec61549fe3 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLine.h
@@ -34,6 +34,100 @@ enum class LVLineKind {
 };
 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
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
index 462d929bad33..d15449cff358 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
@@ -14,17 +14,164 @@
 #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.
@@ -41,17 +188,118 @@ class LVObject {
 
 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 
diff erent '--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

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
new file mode 100644
index 000000000000..141588006b39
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -0,0 +1,164 @@
+//===-- 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

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 0ce2d7e2538e..909c701c96f8 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -16,6 +16,7 @@
 
 #include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
+#include <map>
 #include <set>
 
 namespace llvm {
@@ -50,6 +51,536 @@ enum class LVScopeKind {
 };
 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
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
index d5ed3f965810..93ce6de3ff0b 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
@@ -16,6 +16,8 @@
 namespace llvm {
 namespace logicalview {
 
+class LVObject;
+
 // Object Sorting Mode.
 enum class LVSortMode {
   None = 0, // No given sort.
@@ -25,6 +27,23 @@ enum class LVSortMode {
   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
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 0df64842d903..19781f68660f 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -26,6 +26,89 @@
 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) {
@@ -45,6 +128,36 @@ inline std::string hexSquareString(uint64_t Value) {
   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
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
index 52b46f8a117b..32b115804293 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
@@ -31,6 +31,97 @@ enum class LVSymbolKind {
 };
 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
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
index a288a16bd732..eae8942c3c31 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVType.h
@@ -45,6 +45,200 @@ enum class LVTypeKind {
 };
 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
 

diff  --git a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
index 783b62c275ab..cec32ff6f701 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -4,7 +4,16 @@ macro(add_lv_impl_folder group)
 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

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
new file mode 100644
index 000000000000..8d7c09f6a2dc
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -0,0 +1,464 @@
+//===-- 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);
+  }
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
new file mode 100644
index 000000000000..9d94f6d33b92
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLine.cpp
@@ -0,0 +1,126 @@
+//===-- 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";
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
new file mode 100644
index 000000000000..79eea66c94d0
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVObject.cpp
@@ -0,0 +1,143 @@
+//===-- 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();
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
new file mode 100644
index 000000000000..335053159362
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -0,0 +1,177 @@
+//===-- 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 
diff erent 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 
diff erent 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");
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
new file mode 100644
index 000000000000..61c5c5894f31
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -0,0 +1,1334 @@
+//===-- 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";
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
new file mode 100644
index 000000000000..48d2b8a85454
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
@@ -0,0 +1,99 @@
+//===-- 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;
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSupport.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSupport.cpp
new file mode 100644
index 000000000000..9fa1f28eb089
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSupport.cpp
@@ -0,0 +1,56 @@
+//===-- 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;
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
new file mode 100644
index 000000000000..d2b2c97ecf1d
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
@@ -0,0 +1,164 @@
+//===-- 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));
+  }
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
new file mode 100644
index 000000000000..625b9768a447
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVType.cpp
@@ -0,0 +1,346 @@
+//===-- 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 
diff erent
+  // 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";
+}

diff  --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
index f376c4a39775..c98c12563504 100644
--- a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
@@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(DebugInfoLogicalViewTests
   CommandLineOptionsTest.cpp
+  LogicalElementsTest.cpp
   StringPoolTest.cpp
   )
 

diff  --git a/llvm/unittests/DebugInfo/LogicalView/LogicalElementsTest.cpp b/llvm/unittests/DebugInfo/LogicalView/LogicalElementsTest.cpp
new file mode 100644
index 000000000000..b19029fd1239
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/LogicalElementsTest.cpp
@@ -0,0 +1,342 @@
+//===- 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


        


More information about the llvm-commits mailing list