[llvm] 4f06d46 - [llvm-debuginfo-analyzer] (08/09) - ELF Reader

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 26 21:39:05 PDT 2022


Author: Carlos Alberto Enciso
Date: 2022-10-27T05:37:51+01:00
New Revision: 4f06d46f465c8239ed0863abdd78f7ee1fbb42b4

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

LOG: [llvm-debuginfo-analyzer] (08/09) - ELF Reader

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:

This is a high level summary of the changes in this patch.

ELF Reader
- Support for ELF/DWARF.
  LVBinaryReader, LVELFReader

Reviewed By: psamolysov, probinson

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

Added: 
    llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
    llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
    llvm/include/llvm/DebugInfo/LogicalView/Readers/LVELFReader.h
    llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
    llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
    llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-gcc.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-gcc.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-gcc.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-gcc.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-gcc.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-incorrect-instructions-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-clang.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-gcc.o
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
    llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test
    llvm/unittests/DebugInfo/LogicalView/ELFReaderTest.cpp
    llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang.o
    llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-gcc.o

Modified: 
    llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
    llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
    llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
    llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
    llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
    llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
    llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
    llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
    llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp
    llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt

Removed: 
    llvm/tools/llvm-debuginfo-analyzer/LLVMBuild.txt


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
index 86f90135f8d4e..a932662ae04e7 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugLine.h
@@ -268,6 +268,11 @@ class DWARFDebugLine {
                                    DILineInfoSpecifier::FileLineInfoKind Kind,
                                    DILineInfo &Result) const;
 
+    /// Extracts directory name by its Entry in include directories table
+    /// in prologue. Returns true on success.
+    bool getDirectoryForEntry(const FileNameEntry &Entry,
+                              std::string &Directory) const;
+
     void dump(raw_ostream &OS, DIDumpOptions DumpOptions) const;
     void clear();
 

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
index c4d81047a4dca..ea18642350884 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFExpression.h
@@ -164,6 +164,11 @@ class DWARFExpression {
 
   StringRef getData() const { return Data.getData(); }
 
+  static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
+                                    DIDumpOptions DumpOpts, uint8_t Opcode,
+                                    const uint64_t Operands[2],
+                                    const MCRegisterInfo *MRI, bool isEH);
+
 private:
   DataExtractor Data;
   uint8_t AddressSize;

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index be95e706a5825..e0ee437deb688 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -430,11 +430,11 @@ class DWARFUnit {
     return DWARFDie(this, &DieArray[0]);
   }
 
-  DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly = true) {
-    parseDWO();
-    if (DWO)
-      return DWO->getUnitDIE(ExtractUnitDIEOnly);
-    return getUnitDIE(ExtractUnitDIEOnly);
+  DWARFDie getNonSkeletonUnitDIE(bool ExtractUnitDIEOnly = true,
+                                 StringRef DWOAlternativeLocation = {}) {
+    parseDWO(DWOAlternativeLocation);
+    return DWO ? DWO->getUnitDIE(ExtractUnitDIEOnly)
+               : getUnitDIE(ExtractUnitDIEOnly);
   }
 
   const char *getCompilationDir();
@@ -569,7 +569,10 @@ class DWARFUnit {
 
   /// parseDWO - Parses .dwo file for current compile unit. Returns true if
   /// it was actually constructed.
-  bool parseDWO();
+  /// The \p AlternativeLocation specifies an alternative location to get
+  /// the DWARF context for the DWO object; this is the case when it has
+  /// been moved from its original location.
+  bool parseDWO(StringRef AlternativeLocation = {});
 };
 
 inline bool isCompileUnit(const std::unique_ptr<DWARFUnit> &U) {

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
index 49d342426dd45..94edd83be336b 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
@@ -19,6 +19,8 @@
 namespace llvm {
 namespace logicalview {
 
+using LVLineRange = std::pair<LVLine *, LVLine *>;
+
 // The DW_AT_data_member_location attribute is a simple member offset.
 const LVSmall LVLocationMemberOffset = 0;
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
index bc368d9eaa794..a097372bccfd0 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
@@ -33,6 +33,7 @@ constexpr Tag DW_TAG_unaligned = Tag(dwarf::DW_TAG_hi_user + 1);
 namespace llvm {
 namespace logicalview {
 
+using LVSectionIndex = uint64_t;
 using LVAddress = uint64_t;
 using LVHalf = uint16_t;
 using LVLevel = uint32_t;

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 06bb983debb57..ed1807ce8bf8c 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -16,6 +16,7 @@
 
 #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVRange.h"
+#include "llvm/Support/Errc.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/ToolOutputFile.h"
@@ -24,6 +25,8 @@
 namespace llvm {
 namespace logicalview {
 
+constexpr LVSectionIndex UndefinedSectionIndex = 0;
+
 class LVScopeCompileUnit;
 class LVObject;
 
@@ -79,6 +82,9 @@ class LVReader {
   raw_ostream &OS;
   LVScopeCompileUnit *CompileUnit = nullptr;
 
+  // Only for ELF format. The CodeView is handled in a 
diff erent way.
+  LVSectionIndex DotTextSectionIndex = UndefinedSectionIndex;
+
   // Record Compilation Unit entry.
   void addCompileUnitOffset(LVOffset Offset, LVScopeCompileUnit *CompileUnit) {
     CompileUnits.emplace(Offset, CompileUnit);
@@ -93,6 +99,23 @@ class LVReader {
     return Error::success();
   }
 
+  // Return a pathname composed by: parent_path(InputFilename)/filename(From).
+  // This is useful when a type server (PDB file associated with an object
+  // file or a precompiled header file) or a DWARF split object have been
+  // moved from their original location. That is the case when running
+  // regression tests, where object files are created in one location and
+  // executed in a 
diff erent location.
+  std::string createAlternativePath(StringRef From) {
+    // During the reader initialization, any backslashes in 'InputFilename'
+    // are converted to forward slashes.
+    SmallString<128> Path;
+    sys::path::append(Path, sys::path::Style::posix,
+                      sys::path::parent_path(InputFilename),
+                      sys::path::filename(sys::path::convert_to_slash(
+                          From, sys::path::Style::windows)));
+    return std::string(Path);
+  }
+
   virtual Error printScopes();
   virtual Error printMatchedElements(bool UseMatchedElements);
   virtual void sortScopes() {}
@@ -139,7 +162,12 @@ class LVReader {
     return {};
   }
 
-  virtual bool isSystemEntry(LVElement *Element, StringRef Name = {}) {
+  LVSectionIndex getDotTextSectionIndex() const { return DotTextSectionIndex; }
+  virtual LVSectionIndex getSectionIndex(LVScope *Scope) {
+    return getDotTextSectionIndex();
+  }
+
+  virtual bool isSystemEntry(LVElement *Element, StringRef Name = {}) const {
     return false;
   };
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 01a560479aa39..fa21fd2e863d4 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -17,6 +17,7 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
+#include "llvm/Object/ObjectFile.h"
 #include <list>
 #include <map>
 #include <set>
@@ -24,6 +25,11 @@
 namespace llvm {
 namespace logicalview {
 
+// Name address, Code size.
+using LVNameInfo = std::pair<LVAddress, uint64_t>;
+using LVPublicNames = std::map<LVScope *, LVNameInfo>;
+using LVPublicAddresses = std::map<LVAddress, LVNameInfo>;
+
 class LVRange;
 
 enum class LVScopeKind {
@@ -392,6 +398,12 @@ class LVScopeCompileUnit final : public LVScope {
   // Names (files and directories) used by the Compile Unit.
   std::vector<size_t> Filenames;
 
+  // As the .debug_pubnames section has been removed in DWARF5, we have a
+  // similar functionality, which is used by the decoded functions. We use
+  // the low-pc and high-pc for those scopes that are marked as public, in
+  // order to support DWARF and CodeView.
+  LVPublicNames PublicNames;
+
   // Toolchain producer.
   size_t ProducerIndex = 0;
 
@@ -410,9 +422,10 @@ class LVScopeCompileUnit final : public LVScope {
 
   // 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.
+  // giving its exact or closest address. To support comdat functions, all
+  // addresses for the same section are recorded in the same map.
   using LVAddressToLine = std::map<LVAddress, LVLine *>;
-  LVAddressToLine AddressToLine;
+  LVDoubleMap<LVSectionIndex, LVAddress, LVLine *> SectionMappings;
 
   // DWARF Tags (Tag, Element list).
   LVTagOffsetsMap DebugTags;
@@ -456,6 +469,10 @@ class LVScopeCompileUnit final : public LVScope {
   // in the 'Totals' vector are valid values.
   LVLevel MaxSeenLevel = 0;
 
+  // Get the line located at the given address.
+  LVLine *lineLowerBound(LVAddress Address, LVScope *Scope) const;
+  LVLine *lineUpperBound(LVAddress Address, LVScope *Scope) const;
+
   void printScopeSize(const LVScope *Scope, raw_ostream &OS);
   void printScopeSize(const LVScope *Scope, raw_ostream &OS) const {
     (const_cast<LVScopeCompileUnit *>(this))->printScopeSize(Scope, OS);
@@ -483,9 +500,28 @@ class LVScopeCompileUnit final : public LVScope {
     return static_cast<LVScope *>(const_cast<LVScopeCompileUnit *>(this));
   }
 
-  // Get the line located at the given address.
-  LVLine *lineLowerBound(LVAddress Address) const;
-  LVLine *lineUpperBound(LVAddress Address) const;
+  // Add line to address mapping.
+  void addMapping(LVLine *Line, LVSectionIndex SectionIndex);
+  LVLineRange lineRange(LVLocation *Location) const;
+
+  LVNameInfo NameNone = {UINT64_MAX, 0};
+  void addPublicName(LVScope *Scope, LVAddress LowPC, LVAddress HighPC) {
+    PublicNames.emplace(std::piecewise_construct, std::forward_as_tuple(Scope),
+                        std::forward_as_tuple(LowPC, HighPC - LowPC));
+  }
+  const LVNameInfo &findPublicName(LVScope *Scope) {
+    LVPublicNames::iterator Iter = PublicNames.find(Scope);
+    return (Iter != PublicNames.end()) ? Iter->second : NameNone;
+  }
+  const LVPublicNames &getPublicNames() const { return PublicNames; }
+
+  // The base address of the scope for any of the debugging information
+  // entries listed, is given by either the DW_AT_low_pc attribute or the
+  // first address in the first range entry in the list of ranges given by
+  // the DW_AT_ranges attribute.
+  LVAddress getBaseAddress() const {
+    return Ranges ? Ranges->front()->getLowerAddress() : 0;
+  }
 
   StringRef getCompilationDirectory() const {
     return getStringPool().getString(CompilationDirectoryIndex);

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 15caa8f6e44ed..bff1499c1a60f 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -21,6 +21,7 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cctype>
+#include <map>
 #include <sstream>
 
 namespace llvm {
@@ -163,6 +164,85 @@ template <typename MapType> void deleteList(MapType &Map) {
     delete Entry.second;
 }
 
+// Double map data structure.
+template <typename FirstKeyType, typename SecondKeyType, typename ValueType>
+class LVDoubleMap {
+  static_assert(std::is_pointer<ValueType>::value,
+                "ValueType must be a pointer.");
+  using LVSecondMapType = std::map<SecondKeyType, ValueType>;
+  using LVFirstMapType = std::map<FirstKeyType, LVSecondMapType *>;
+  using LVAuxMapType = std::map<SecondKeyType, FirstKeyType>;
+  using LVValueTypes = std::vector<ValueType>;
+  LVFirstMapType FirstMap;
+  LVAuxMapType AuxMap;
+
+public:
+  LVDoubleMap() = default;
+  ~LVDoubleMap() {
+    for (auto &Entry : FirstMap)
+      delete Entry.second;
+  }
+
+  void add(FirstKeyType FirstKey, SecondKeyType SecondKey, ValueType Value) {
+    LVSecondMapType *SecondMap = nullptr;
+    typename LVFirstMapType::iterator FirstIter = FirstMap.find(FirstKey);
+    if (FirstIter == FirstMap.end()) {
+      SecondMap = new LVSecondMapType();
+      FirstMap.emplace(FirstKey, SecondMap);
+    } else {
+      SecondMap = FirstIter->second;
+    }
+
+    assert(SecondMap && "SecondMap is null.");
+    if (SecondMap && SecondMap->find(SecondKey) == SecondMap->end())
+      SecondMap->emplace(SecondKey, Value);
+
+    typename LVAuxMapType::iterator AuxIter = AuxMap.find(SecondKey);
+    if (AuxIter == AuxMap.end()) {
+      AuxMap.emplace(SecondKey, FirstKey);
+    }
+  }
+
+  LVSecondMapType *findMap(FirstKeyType FirstKey) const {
+    typename LVFirstMapType::const_iterator FirstIter = FirstMap.find(FirstKey);
+    if (FirstIter == FirstMap.end())
+      return nullptr;
+
+    LVSecondMapType *SecondMap = FirstIter->second;
+    return SecondMap;
+  }
+
+  ValueType find(FirstKeyType FirstKey, SecondKeyType SecondKey) const {
+    LVSecondMapType *SecondMap = findMap(FirstKey);
+    if (!SecondMap)
+      return nullptr;
+
+    typename LVSecondMapType::const_iterator SecondIter =
+        SecondMap->find(SecondKey);
+    return (SecondIter != SecondMap->end()) ? SecondIter->second : nullptr;
+  }
+
+  ValueType find(SecondKeyType SecondKey) const {
+    typename LVAuxMapType::const_iterator AuxIter = AuxMap.find(SecondKey);
+    if (AuxIter == AuxMap.end())
+      return nullptr;
+    return find(AuxIter->second, SecondKey);
+  }
+
+  // Return a vector with all the 'ValueType' values.
+  LVValueTypes find() const {
+    LVValueTypes Values;
+    if (FirstMap.empty())
+      return Values;
+    for (typename LVFirstMapType::const_reference FirstEntry : FirstMap) {
+      LVSecondMapType *SecondMap = FirstEntry.second;
+      for (typename LVSecondMapType::const_reference SecondEntry : *SecondMap)
+        Values.push_back(SecondEntry.second);
+    }
+    return Values;
+  }
+};
+
 // Unified and flattened pathnames.
 std::string transformPath(StringRef Path);
 std::string flattenedFilePath(StringRef Path);

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
new file mode 100644
index 0000000000000..3030e9f24ed82
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/LVReaderHandler.h
@@ -0,0 +1,100 @@
+//===-- LVReaderHandler.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 class implements the Reader handler.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVREADERHANDLER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVREADERHANDLER_H
+
+#include "llvm/ADT/PointerUnion.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace logicalview {
+
+using LVReaders = std::vector<LVReader *>;
+using ArgVector = std::vector<std::string>;
+using PdbOrObj = PointerUnion<object::ObjectFile *, pdb::PDBFile *>;
+
+// This class performs the following tasks:
+// - Creates a logical reader for every binary file in the command line,
+//   that parses the debug information and creates a high level logical
+//   view representation containing scopes, symbols, types and lines.
+// - Prints and compares the logical views.
+//
+// The supported binary formats are: ELF, Mach-O and CodeView.
+class LVReaderHandler {
+  ArgVector &Objects;
+  ScopedPrinter &W;
+  raw_ostream &OS;
+  LVReaders TheReaders;
+
+  Error createReaders();
+  void destroyReaders();
+  Error printReaders();
+  Error compareReaders();
+
+  Error handleArchive(LVReaders &Readers, StringRef Filename,
+                      object::Archive &Arch);
+  Error handleBuffer(LVReaders &Readers, StringRef Filename,
+                     MemoryBufferRef Buffer, StringRef ExePath = {});
+  Error handleFile(LVReaders &Readers, StringRef Filename,
+                   StringRef ExePath = {});
+  Error handleMach(LVReaders &Readers, StringRef Filename,
+                   object::MachOUniversalBinary &Mach);
+  Error handleObject(LVReaders &Readers, StringRef Filename,
+                     object::Binary &Binary);
+
+  Error createReader(StringRef Filename, LVReaders &Readers, PdbOrObj &Input,
+                     StringRef FileFormatName, StringRef ExePath = {});
+
+public:
+  LVReaderHandler() = delete;
+  LVReaderHandler(ArgVector &Objects, ScopedPrinter &W,
+                  LVOptions &ReaderOptions)
+      : Objects(Objects), W(W), OS(W.getOStream()) {
+    setOptions(&ReaderOptions);
+  }
+  LVReaderHandler(const LVReaderHandler &) = delete;
+  LVReaderHandler &operator=(const LVReaderHandler &) = delete;
+  ~LVReaderHandler() { destroyReaders(); }
+
+  Error createReader(StringRef Filename, LVReaders &Readers) {
+    return handleFile(Readers, Filename);
+  }
+  Error process();
+
+  Expected<LVReader *> createReader(StringRef Pathname) {
+    LVReaders Readers;
+    if (Error Err = createReader(Pathname, Readers))
+      return std::move(Err);
+    return Readers[0];
+  }
+  void deleteReader(LVReader *Reader) { delete Reader; }
+
+  void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const { print(dbgs()); }
+#endif
+};
+
+} // end namespace logicalview
+} // namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVREADERHANDLER_H

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
new file mode 100644
index 0000000000000..8c3cce9286a33
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h
@@ -0,0 +1,180 @@
+//===-- LVBinaryReader.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 LVBinaryReader class, which is used to describe a
+// binary reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/ObjectFile.h"
+
+namespace llvm {
+namespace logicalview {
+
+constexpr bool UpdateHighAddress = false;
+
+// Logical scope, Section address, Section index, IsComdat.
+struct LVSymbolTableEntry final {
+  LVScope *Scope = nullptr;
+  LVAddress Address = 0;
+  LVSectionIndex SectionIndex = 0;
+  bool IsComdat = false;
+  LVSymbolTableEntry() = default;
+  LVSymbolTableEntry(LVScope *Scope, LVAddress Address,
+                     LVSectionIndex SectionIndex, bool IsComdat)
+      : Scope(Scope), Address(Address), SectionIndex(SectionIndex),
+        IsComdat(IsComdat) {}
+};
+
+// Function names extracted from the object symbol table.
+class LVSymbolTable final {
+  using LVSymbolNames = std::map<std::string, LVSymbolTableEntry>;
+  LVSymbolNames SymbolNames;
+
+public:
+  LVSymbolTable() = default;
+
+  void add(StringRef Name, LVScope *Function, LVSectionIndex SectionIndex = 0);
+  void add(StringRef Name, LVAddress Address, LVSectionIndex SectionIndex,
+           bool IsComdat);
+  LVSectionIndex update(LVScope *Function);
+
+  const LVSymbolTableEntry &getEntry(StringRef Name);
+  LVAddress getAddress(StringRef Name);
+  LVSectionIndex getIndex(StringRef Name);
+  bool getIsComdat(StringRef Name);
+
+  void print(raw_ostream &OS);
+};
+
+class LVBinaryReader : public LVReader {
+  // Function names extracted from the object symbol table.
+  LVSymbolTable SymbolTable;
+
+  // Instruction lines for a logical scope. These instructions are fetched
+  // during its merge with the debug lines.
+  LVDoubleMap<LVSectionIndex, LVScope *, LVLines *> ScopeInstructions;
+
+  // Links the scope with its first assembler address line.
+  LVDoubleMap<LVSectionIndex, LVAddress, LVScope *> AssemblerMappings;
+
+  // Mapping from virtual address to section.
+  // The virtual address refers to the address where the section is loaded.
+  using LVSectionAddresses = std::map<LVSectionIndex, object::SectionRef>;
+  LVSectionAddresses SectionAddresses;
+
+  void addSectionAddress(const object::SectionRef &Section) {
+    if (SectionAddresses.find(Section.getAddress()) == SectionAddresses.end())
+      SectionAddresses.emplace(Section.getAddress(), Section);
+  }
+
+  // Scopes with ranges for current compile unit. It is used to find a line
+  // giving its exact or closest address. To support comdat functions, all
+  // addresses for the same section are recorded in the same map.
+  using LVSectionRanges = std::map<LVSectionIndex, LVRange *>;
+  LVSectionRanges SectionRanges;
+
+  // Image base and virtual address for Executable file.
+  uint64_t ImageBaseAddress = 0;
+  uint64_t VirtualAddress = 0;
+
+  // Object sections with machine code.
+  using LVSections = std::map<LVSectionIndex, object::SectionRef>;
+  LVSections Sections;
+
+protected:
+  // It contains the LVLineDebug elements representing the logical lines for
+  // the current compile unit, created by parsing the debug line section.
+  LVLines CULines;
+
+  std::unique_ptr<const MCRegisterInfo> MRI;
+  std::unique_ptr<const MCAsmInfo> MAI;
+  std::unique_ptr<const MCSubtargetInfo> STI;
+  std::unique_ptr<const MCInstrInfo> MII;
+  std::unique_ptr<const MCDisassembler> MD;
+  std::unique_ptr<MCContext> MC;
+  std::unique_ptr<MCInstPrinter> MIP;
+
+  // Loads all info for the architecture of the provided object file.
+  Error loadGenericTargetInfo(StringRef TheTriple, StringRef TheFeatures);
+
+  virtual void mapRangeAddress(const object::ObjectFile &Obj) {}
+  virtual void mapRangeAddress(const object::ObjectFile &Obj,
+                               const object::SectionRef &Section,
+                               bool IsComdat) {}
+
+  // Create a mapping from virtual address to section.
+  void mapVirtualAddress(const object::ObjectFile &Obj);
+  void mapVirtualAddress(const object::COFFObjectFile &COFFObj);
+
+  Expected<std::pair<LVSectionIndex, object::SectionRef>>
+  getSection(LVScope *Scope, LVAddress Address, LVSectionIndex SectionIndex);
+
+  void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope);
+  void addSectionRange(LVSectionIndex SectionIndex, LVScope *Scope,
+                       LVAddress LowerAddress, LVAddress UpperAddress);
+  LVRange *getSectionRanges(LVSectionIndex SectionIndex);
+
+  Error createInstructions();
+  Error createInstructions(LVScope *Function, LVSectionIndex SectionIndex);
+  Error createInstructions(LVScope *Function, LVSectionIndex SectionIndex,
+                           const LVNameInfo &NameInfo);
+
+  void processLines(LVLines *DebugLines, LVSectionIndex SectionIndex);
+  void processLines(LVLines *DebugLines, LVSectionIndex SectionIndex,
+                    LVScope *Function);
+
+public:
+  LVBinaryReader() = delete;
+  LVBinaryReader(StringRef Filename, StringRef FileFormatName, ScopedPrinter &W,
+                 LVBinaryType BinaryType)
+      : LVReader(Filename, FileFormatName, W, BinaryType) {}
+  LVBinaryReader(const LVBinaryReader &) = delete;
+  LVBinaryReader &operator=(const LVBinaryReader &) = delete;
+  virtual ~LVBinaryReader();
+
+  void addToSymbolTable(StringRef Name, LVScope *Function,
+                        LVSectionIndex SectionIndex = 0);
+  void addToSymbolTable(StringRef Name, LVAddress Address,
+                        LVSectionIndex SectionIndex, bool IsComdat);
+  LVSectionIndex updateSymbolTable(LVScope *Function);
+
+  const LVSymbolTableEntry &getSymbolTableEntry(StringRef Name);
+  LVAddress getSymbolTableAddress(StringRef Name);
+  LVSectionIndex getSymbolTableIndex(StringRef Name);
+  bool getSymbolTableIsComdat(StringRef Name);
+
+  LVSectionIndex getSectionIndex(LVScope *Scope) override {
+    return Scope ? getSymbolTableIndex(Scope->getLinkageName())
+                 : DotTextSectionIndex;
+  }
+
+  void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const { print(dbgs()); }
+#endif
+};
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVBINARYREADER_H

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVELFReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVELFReader.h
new file mode 100644
index 0000000000000..4ab17eca5f92b
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Readers/LVELFReader.h
@@ -0,0 +1,154 @@
+//===-- LVELFReader.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 LVELFReader class, which is used to describe a
+// debug information (DWARF) reader.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVELFREADER_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVELFREADER_H
+
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h"
+#include <unordered_set>
+
+namespace llvm {
+namespace logicalview {
+
+class LVElement;
+class LVLine;
+class LVScopeCompileUnit;
+class LVSymbol;
+class LVType;
+
+using AttributeSpec = DWARFAbbreviationDeclaration::AttributeSpec;
+
+class LVELFReader final : public LVBinaryReader {
+  object::ObjectFile &Obj;
+
+  // Indicates if ranges data are available; in the case of split DWARF any
+  // reference to ranges is valid only if the skeleton DIE has been loaded.
+  bool RangesDataAvailable = false;
+  LVAddress CUBaseAddress = 0;
+  LVAddress CUHighAddress = 0;
+
+  // Current elements during the processing of a DIE.
+  LVElement *CurrentElement = nullptr;
+  LVScope *CurrentScope = nullptr;
+  LVSymbol *CurrentSymbol = nullptr;
+  LVType *CurrentType = nullptr;
+  LVOffset CurrentOffset = 0;
+  LVOffset CurrentEndOffset = 0;
+
+  // In DWARF v4, the files are 1-indexed.
+  // In DWARF v5, the files are 0-indexed.
+  // The ELF reader expects the indexes as 1-indexed.
+  bool IncrementFileIndex = false;
+
+  // Address ranges collected for current DIE.
+  std::vector<LVAddressRange> CurrentRanges;
+
+  // Symbols with locations for current compile unit.
+  LVSymbols SymbolsWithLocations;
+
+  // Global Offsets (Offset, Element).
+  LVOffsetElementMap GlobalOffsets;
+
+  // Low PC and High PC values for DIE being processed.
+  LVAddress CurrentLowPC = 0;
+  LVAddress CurrentHighPC = 0;
+  bool FoundLowPC = false;
+  bool FoundHighPC = false;
+
+  // Cross references (Elements).
+  using LVElementSet = std::unordered_set<LVElement *>;
+  using LVElementEntry = std::pair<LVElement *, LVElementSet>;
+  using LVElementReference = std::unordered_map<LVOffset, LVElementEntry>;
+  LVElementReference ElementTable;
+
+  Error loadTargetInfo(const object::ObjectFile &Obj);
+
+  void mapRangeAddress(const object::ObjectFile &Obj) override;
+
+  LVElement *createElement(dwarf::Tag Tag);
+  void traverseDieAndChildren(DWARFDie &DIE, LVScope *Parent,
+                              DWARFDie &SkeletonDie);
+  // Process the attributes for the given DIE.
+  LVScope *processOneDie(const DWARFDie &InputDIE, LVScope *Parent,
+                         DWARFDie &SkeletonDie);
+  void processOneAttribute(const DWARFDie &Die, LVOffset *OffsetPtr,
+                           const AttributeSpec &AttrSpec);
+  void createLineAndFileRecords(const DWARFDebugLine::LineTable *Lines);
+  void processLocationGaps();
+
+  // Add offset to global map.
+  void addGlobalOffset(LVOffset Offset) {
+    if (GlobalOffsets.find(Offset) == GlobalOffsets.end())
+      // Just associate the DIE offset with a null element, as we do not
+      // know if the referenced element has been created.
+      GlobalOffsets.emplace(Offset, nullptr);
+  }
+
+  // Remove offset from global map.
+  void removeGlobalOffset(LVOffset Offset) {
+    LVOffsetElementMap::iterator Iter = GlobalOffsets.find(Offset);
+    if (Iter != GlobalOffsets.end())
+      GlobalOffsets.erase(Iter);
+  }
+
+  // Get the location information for DW_AT_data_member_location.
+  void processLocationMember(dwarf::Attribute Attr,
+                             const DWARFFormValue &FormValue,
+                             const DWARFDie &Die, uint64_t OffsetOnEntry);
+  void processLocationList(dwarf::Attribute Attr,
+                           const DWARFFormValue &FormValue, const DWARFDie &Die,
+                           uint64_t OffsetOnEntry,
+                           bool CallSiteLocation = false);
+  void updateReference(dwarf::Attribute Attr, const DWARFFormValue &FormValue);
+
+  // Get an element given the DIE offset.
+  LVElement *getElementForOffset(LVOffset offset, LVElement *Element);
+
+protected:
+  Error createScopes() override;
+  void sortScopes() override;
+
+public:
+  LVELFReader() = delete;
+  LVELFReader(StringRef Filename, StringRef FileFormatName,
+              object::ObjectFile &Obj, ScopedPrinter &W)
+      : LVBinaryReader(Filename, FileFormatName, W, LVBinaryType::ELF),
+        Obj(Obj) {}
+  LVELFReader(const LVELFReader &) = delete;
+  LVELFReader &operator=(const LVELFReader &) = delete;
+  ~LVELFReader() = default;
+
+  LVAddress getCUBaseAddress() const { return CUBaseAddress; }
+  void setCUBaseAddress(LVAddress Address) { CUBaseAddress = Address; }
+  LVAddress getCUHighAddress() const { return CUHighAddress; }
+  void setCUHighAddress(LVAddress Address) { CUHighAddress = Address; }
+
+  const LVSymbols &GetSymbolsWithLocations() const {
+    return SymbolsWithLocations;
+  }
+
+  std::string getRegisterName(LVSmall Opcode, uint64_t Operands[2]) override;
+
+  void print(raw_ostream &OS) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const { print(dbgs()); }
+#endif
+};
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_READERS_LVELFREADER_H

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
index 5ea4c4cded7f2..96f7529014df5 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -1419,6 +1419,24 @@ bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
   return true;
 }
 
+bool DWARFDebugLine::LineTable::getDirectoryForEntry(
+    const FileNameEntry &Entry, std::string &Directory) const {
+  if (Prologue.getVersion() >= 5) {
+    if (Entry.DirIdx < Prologue.IncludeDirectories.size()) {
+      Directory =
+          dwarf::toString(Prologue.IncludeDirectories[Entry.DirIdx], "");
+      return true;
+    }
+    return false;
+  }
+  if (0 < Entry.DirIdx && Entry.DirIdx <= Prologue.IncludeDirectories.size()) {
+    Directory =
+        dwarf::toString(Prologue.IncludeDirectories[Entry.DirIdx - 1], "");
+    return true;
+  }
+  return false;
+}
+
 // We want to supply the Unit associated with a .debug_line[.dwo] table when
 // we dump it, if possible, but still dump the table even if there isn't a Unit.
 // Therefore, collect up handles on all the Units that point into the

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
index e19f5b8138fa0..17b180f55001c 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -225,10 +225,9 @@ static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,
   }
 }
 
-static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
-                                  DIDumpOptions DumpOpts, uint8_t Opcode,
-                                  const uint64_t Operands[2],
-                                  const MCRegisterInfo *MRI, bool isEH) {
+bool DWARFExpression::prettyPrintRegisterOp(
+    DWARFUnit *U, raw_ostream &OS, DIDumpOptions DumpOpts, uint8_t Opcode,
+    const uint64_t Operands[2], const MCRegisterInfo *MRI, bool isEH) {
   if (!MRI)
     return false;
 

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 58b59df4cb414..dfa2e9cc8c1eb 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -587,7 +587,7 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
   return Error::success();
 }
 
-bool DWARFUnit::parseDWO() {
+bool DWARFUnit::parseDWO(StringRef DWOAlternativeLocation) {
   if (IsDWO)
     return false;
   if (DWO.get())
@@ -611,8 +611,17 @@ bool DWARFUnit::parseDWO() {
   if (!DWOId)
     return false;
   auto DWOContext = Context.getDWOContext(AbsolutePath);
-  if (!DWOContext)
-    return false;
+  if (!DWOContext) {
+    // Use the alternative location to get the DWARF context for the DWO object.
+    if (DWOAlternativeLocation.empty())
+      return false;
+    // If the alternative context does not correspond to the original DWO object
+    // (
diff erent hashes), the below 'getDWOCompileUnitForHash' call will catch
+    // the issue, with a returned null context.
+    DWOContext = Context.getDWOContext(DWOAlternativeLocation);
+    if (!DWOContext)
+      return false;
+  }
 
   DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId);
   if (!DWOCU)

diff  --git a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
index b6f9fb832c382..e1b193c3126c6 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -19,9 +19,16 @@ add_lv_impl_folder(Core
   Core/LVType.cpp
   )
 
+add_lv_impl_folder(Readers
+  LVReaderHandler.cpp
+  Readers/LVBinaryReader.cpp
+  Readers/LVELFReader.cpp
+  )
+
 list(APPEND LIBLV_ADDITIONAL_HEADER_DIRS
   "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/LogicalView"
   "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/LogicalView/Core"
+  "${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/LogicalView/Readers"
   )
 
 add_llvm_component_library(LLVMDebugInfoLogicalView

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
index 79046287595e5..8ef4df4beecb1 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVElement.cpp
@@ -516,3 +516,15 @@ void LVElement::printLinkageName(raw_ostream &OS, bool Full,
                     /*UseQuotes=*/true, /*PrintRef=*/false);
   }
 }
+
+void LVElement::printLinkageName(raw_ostream &OS, bool Full, LVElement *Parent,
+                                 LVScope *Scope) const {
+  if (options().getPrintFormatting() && options().getAttributeLinkage()) {
+    LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
+    std::string Text = (Twine(" 0x") + Twine::utohexstr(SectionIndex) +
+                        Twine(" '") + Twine(getLinkageName()) + Twine("'"))
+                           .str();
+    printAttributes(OS, Full, "{Linkage} ", Parent, Text,
+                    /*UseQuotes=*/false, /*PrintRef=*/false);
+  }
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
index 3a414deb5355f..115b903c6c7f9 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
@@ -469,9 +469,9 @@ bool LVLocation::validateRanges() {
   if (!hasAssociatedRange())
     return true;
 
-  LVScopeCompileUnit *Scope = getReader().getCompileUnit();
-  LVLine *LowLine = Scope->lineLowerBound(getLowerAddress());
-  LVLine *HighLine = Scope->lineUpperBound(getUpperAddress());
+  LVLineRange Range = getReaderCompileUnit()->lineRange(this);
+  LVLine *LowLine = Range.first;
+  LVLine *HighLine = Range.second;
   if (LowLine)
     setLowerLine(LowLine);
   else {

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index fc021c15e7d86..dd5530e07330a 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -1252,20 +1252,43 @@ void LVScopeCompileUnit::processRangeLocationCoverage(
   }
 }
 
-LVLine *LVScopeCompileUnit::lineLowerBound(LVAddress Address) const {
-  LVAddressToLine::const_iterator Iter = AddressToLine.lower_bound(Address);
-  return (Iter != AddressToLine.end()) ? Iter->second : nullptr;
+void LVScopeCompileUnit::addMapping(LVLine *Line, LVSectionIndex SectionIndex) {
+  LVAddress Address = Line->getOffset();
+  SectionMappings.add(SectionIndex, Address, Line);
 }
 
-LVLine *LVScopeCompileUnit::lineUpperBound(LVAddress Address) const {
-  if (AddressToLine.empty())
+LVLine *LVScopeCompileUnit::lineLowerBound(LVAddress Address,
+                                           LVScope *Scope) const {
+  LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
+  LVAddressToLine *Map = SectionMappings.findMap(SectionIndex);
+  if (!Map || Map->empty())
     return nullptr;
-  LVAddressToLine::const_iterator Iter = AddressToLine.upper_bound(Address);
-  if (Iter != AddressToLine.begin())
+  LVAddressToLine::const_iterator Iter = Map->lower_bound(Address);
+  return (Iter != Map->end()) ? Iter->second : nullptr;
+}
+
+LVLine *LVScopeCompileUnit::lineUpperBound(LVAddress Address,
+                                           LVScope *Scope) const {
+  LVSectionIndex SectionIndex = getReader().getSectionIndex(Scope);
+  LVAddressToLine *Map = SectionMappings.findMap(SectionIndex);
+  if (!Map || Map->empty())
+    return nullptr;
+  LVAddressToLine::const_iterator Iter = Map->upper_bound(Address);
+  if (Iter != Map->begin())
     Iter = std::prev(Iter);
   return Iter->second;
 }
 
+LVLineRange LVScopeCompileUnit::lineRange(LVLocation *Location) const {
+  // The parent of a location can be a symbol or a scope.
+  LVElement *Element = Location->getParent();
+  LVScope *Parent = Element->getIsScope() ? static_cast<LVScope *>(Element)
+                                          : Element->getParentScope();
+  LVLine *LowLine = lineLowerBound(Location->getLowerAddress(), Parent);
+  LVLine *HighLine = lineUpperBound(Location->getUpperAddress(), Parent);
+  return LVLineRange(LowLine, HighLine);
+}
+
 StringRef LVScopeCompileUnit::getFilename(size_t Index) const {
   if (Index <= 0 || Index > Filenames.size())
     return StringRef();
@@ -1403,6 +1426,30 @@ void LVScopeCompileUnit::printLocalNames(raw_ostream &OS, bool Full) const {
     PrintNames(Option::Directory);
   if (options().getAttributeFiles())
     PrintNames(Option::File);
+  if (options().getAttributePublics()) {
+    StringRef Kind = "Public";
+    // The public names are indexed by 'LVScope *'. We want to print
+    // them by logical element address, to show the scopes layout.
+    using OffsetSorted = std::map<LVAddress, LVPublicNames::const_iterator>;
+    OffsetSorted SortedNames;
+    for (LVPublicNames::const_iterator Iter = PublicNames.begin();
+         Iter != PublicNames.end(); ++Iter)
+      SortedNames.emplace(Iter->first->getOffset(), Iter);
+
+    LVPublicNames::const_iterator Iter;
+    for (OffsetSorted::reference Entry : SortedNames) {
+      Iter = Entry.second;
+      OS << std::string(Indentation, ' ') << formattedKind(Kind) << " "
+         << formattedName((*Iter).first->getName());
+      if (options().getAttributeOffset()) {
+        LVAddress Address = (*Iter).second.first;
+        size_t Size = (*Iter).second.second;
+        OS << " [" << hexString(Address) << ":" << hexString(Address + Size)
+           << "]";
+      }
+      OS << "\n";
+    }
+  }
 }
 
 void LVScopeCompileUnit::printWarnings(raw_ostream &OS, bool Full) const {
@@ -1848,6 +1895,9 @@ void LVScopeFunction::printExtra(raw_ostream &OS, bool Full) const {
     if (getIsTemplateResolved())
       printEncodedArgs(OS, Full);
     printActiveRanges(OS, Full);
+    if (getLinkageNameIndex())
+      printLinkageName(OS, Full, const_cast<LVScopeFunction *>(this),
+                       const_cast<LVScopeFunction *>(this));
     if (Reference)
       Reference->printReference(OS, Full, const_cast<LVScopeFunction *>(this));
   }

diff  --git a/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
new file mode 100644
index 0000000000000..35dc30fd601fc
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/LVReaderHandler.cpp
@@ -0,0 +1,194 @@
+//===-- LVReaderHandler.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 class implements the Reader Handler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVCompare.h"
+#include "llvm/DebugInfo/LogicalView/Readers/LVELFReader.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::pdb;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "ReaderHandler"
+
+Error LVReaderHandler::process() {
+  if (Error Err = createReaders())
+    return Err;
+  if (Error Err = printReaders())
+    return Err;
+  if (Error Err = compareReaders())
+    return Err;
+
+  return Error::success();
+}
+
+void LVReaderHandler::destroyReaders() {
+  LLVM_DEBUG(dbgs() << "destroyReaders\n");
+  for (const LVReader *Reader : TheReaders)
+    delete Reader;
+}
+
+Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers,
+                                    PdbOrObj &Input, StringRef FileFormatName,
+                                    StringRef ExePath) {
+  auto CreateOneReader = [&]() -> LVReader * {
+    if (Input.is<ObjectFile *>()) {
+      ObjectFile &Obj = *Input.get<ObjectFile *>();
+      if (Obj.isELF() || Obj.isMachO())
+        return new LVELFReader(Filename, FileFormatName, Obj, W);
+    }
+    return nullptr;
+  };
+
+  LVReader *Reader = CreateOneReader();
+  if (!Reader)
+    return createStringError(errc::invalid_argument,
+                             "unable to create reader for: '%s'",
+                             Filename.str().c_str());
+
+  Readers.push_back(Reader);
+  return Reader->doLoad();
+}
+
+Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename,
+                                     Archive &Arch) {
+  Error Err = Error::success();
+  for (const Archive::Child &Child : Arch.children(Err)) {
+    Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef();
+    if (Error Err = BuffOrErr.takeError())
+      return createStringError(errorToErrorCode(std::move(Err)), "%s",
+                               Filename.str().c_str());
+    Expected<StringRef> NameOrErr = Child.getName();
+    if (Error Err = NameOrErr.takeError())
+      return createStringError(errorToErrorCode(std::move(Err)), "%s",
+                               Filename.str().c_str());
+    std::string Name = (Filename + "(" + NameOrErr.get() + ")").str();
+    if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get()))
+      return createStringError(errorToErrorCode(std::move(Err)), "%s",
+                               Filename.str().c_str());
+  }
+
+  return Error::success();
+}
+
+Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename,
+                                    MemoryBufferRef Buffer, StringRef ExePath) {
+  Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer);
+  if (errorToErrorCode(BinOrErr.takeError())) {
+    return createStringError(errc::not_supported,
+                             "Binary object format in '%s' is not supported.",
+                             Filename.str().c_str());
+  }
+  return handleObject(Readers, Filename, *BinOrErr.get());
+}
+
+Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename,
+                                  StringRef ExePath) {
+  // Convert any Windows backslashes into forward slashes to get the path.
+  std::string ConvertedPath =
+      sys::path::convert_to_slash(Filename, sys::path::Style::windows);
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
+      MemoryBuffer::getFileOrSTDIN(ConvertedPath);
+  if (BuffOrErr.getError()) {
+    return createStringError(errc::bad_file_descriptor,
+                             "File '%s' does not exist.",
+                             ConvertedPath.c_str());
+  }
+  std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
+  return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath);
+}
+
+Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename,
+                                  MachOUniversalBinary &Mach) {
+  for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) {
+    std::string ObjName = (Twine(Filename) + Twine("(") +
+                           Twine(ObjForArch.getArchFlagName()) + Twine(")"))
+                              .str();
+    if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr =
+            ObjForArch.getAsObjectFile()) {
+      MachOObjectFile &Obj = **MachOOrErr;
+      PdbOrObj Input = &Obj;
+      if (Error Err =
+              createReader(Filename, Readers, Input, Obj.getFileFormatName()))
+        return Err;
+      continue;
+    } else
+      consumeError(MachOOrErr.takeError());
+    if (Expected<std::unique_ptr<Archive>> ArchiveOrErr =
+            ObjForArch.getAsArchive()) {
+      if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get()))
+        return Err;
+      continue;
+    } else
+      consumeError(ArchiveOrErr.takeError());
+  }
+  return Error::success();
+}
+
+Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename,
+                                    Binary &Binary) {
+  if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary))
+    return createReader(Filename, Readers, Input,
+                        Input.get<ObjectFile *>()->getFileFormatName());
+
+  if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary))
+    return handleMach(Readers, Filename, *Fat);
+
+  if (Archive *Arch = dyn_cast<Archive>(&Binary))
+    return handleArchive(Readers, Filename, *Arch);
+
+  return createStringError(errc::not_supported,
+                           "Binary object format in '%s' is not supported.",
+                           Filename.str().c_str());
+}
+
+Error LVReaderHandler::createReaders() {
+  LLVM_DEBUG(dbgs() << "createReaders\n");
+  for (std::string &Object : Objects) {
+    LVReaders Readers;
+    if (Error Err = createReader(Object, Readers))
+      return Err;
+    TheReaders.insert(TheReaders.end(), Readers.begin(), Readers.end());
+  }
+
+  return Error::success();
+}
+
+Error LVReaderHandler::printReaders() {
+  LLVM_DEBUG(dbgs() << "printReaders\n");
+  if (options().getPrintExecute())
+    for (LVReader *Reader : TheReaders)
+      if (Error Err = Reader->doPrint())
+        return Err;
+
+  return Error::success();
+}
+
+Error LVReaderHandler::compareReaders() {
+  LLVM_DEBUG(dbgs() << "compareReaders\n");
+  size_t ReadersCount = TheReaders.size();
+  if (options().getCompareExecute() && ReadersCount >= 2) {
+    // If we have more than 2 readers, compare them by pairs.
+    size_t ViewPairs = ReadersCount / 2;
+    LVCompare Compare(OS);
+    for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) {
+      if (Error Err = Compare.execute(TheReaders[Index], TheReaders[Index + 1]))
+        return Err;
+      Index += 2;
+    }
+  }
+
+  return Error::success();
+}
+
+void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; }

diff  --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
new file mode 100644
index 0000000000000..1a6e9509ea057
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVBinaryReader.cpp
@@ -0,0 +1,816 @@
+//===-- LVBinaryReader.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 LVBinaryReader class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Readers/LVBinaryReader.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "BinaryReader"
+
+// Function names extracted from the object symbol table.
+void LVSymbolTable::add(StringRef Name, LVScope *Function,
+                        LVSectionIndex SectionIndex) {
+  std::string SymbolName(Name);
+  if (SymbolNames.find(SymbolName) == SymbolNames.end()) {
+    SymbolNames.emplace(
+        std::piecewise_construct, std::forward_as_tuple(SymbolName),
+        std::forward_as_tuple(Function, 0, SectionIndex, false));
+  } else {
+    // Update a recorded entry with its logical scope and section index.
+    SymbolNames[SymbolName].Scope = Function;
+    if (SectionIndex)
+      SymbolNames[SymbolName].SectionIndex = SectionIndex;
+  }
+
+  if (Function && SymbolNames[SymbolName].IsComdat)
+    Function->setIsComdat();
+
+  LLVM_DEBUG({ print(dbgs()); });
+}
+
+void LVSymbolTable::add(StringRef Name, LVAddress Address,
+                        LVSectionIndex SectionIndex, bool IsComdat) {
+  std::string SymbolName(Name);
+  if (SymbolNames.find(SymbolName) == SymbolNames.end())
+    SymbolNames.emplace(
+        std::piecewise_construct, std::forward_as_tuple(SymbolName),
+        std::forward_as_tuple(nullptr, Address, SectionIndex, IsComdat));
+  else
+    // Update a recorded symbol name with its logical scope.
+    SymbolNames[SymbolName].Address = Address;
+
+  LVScope *Function = SymbolNames[SymbolName].Scope;
+  if (Function && IsComdat)
+    Function->setIsComdat();
+  LLVM_DEBUG({ print(dbgs()); });
+}
+
+LVSectionIndex LVSymbolTable::update(LVScope *Function) {
+  LVSectionIndex SectionIndex = getReader().getDotTextSectionIndex();
+  StringRef Name = Function->getLinkageName();
+  if (Name.empty())
+    Name = Function->getName();
+  std::string SymbolName(Name);
+
+  if (SymbolName.empty() || (SymbolNames.find(SymbolName) == SymbolNames.end()))
+    return SectionIndex;
+
+  // Update a recorded entry with its logical scope, only if the scope has
+  // ranges. That is the case when in DWARF there are 2 DIEs connected via
+  // the DW_AT_specification.
+  if (Function->getHasRanges()) {
+    SymbolNames[SymbolName].Scope = Function;
+    SectionIndex = SymbolNames[SymbolName].SectionIndex;
+  } else {
+    SectionIndex = UndefinedSectionIndex;
+  }
+
+  if (SymbolNames[SymbolName].IsComdat)
+    Function->setIsComdat();
+
+  LLVM_DEBUG({ print(dbgs()); });
+  return SectionIndex;
+}
+
+const LVSymbolTableEntry &LVSymbolTable::getEntry(StringRef Name) {
+  static LVSymbolTableEntry Empty = LVSymbolTableEntry();
+  LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name));
+  return Iter != SymbolNames.end() ? Iter->second : Empty;
+}
+LVAddress LVSymbolTable::getAddress(StringRef Name) {
+  LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name));
+  return Iter != SymbolNames.end() ? Iter->second.Address : 0;
+}
+LVSectionIndex LVSymbolTable::getIndex(StringRef Name) {
+  LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name));
+  return Iter != SymbolNames.end() ? Iter->second.SectionIndex
+                                   : getReader().getDotTextSectionIndex();
+}
+bool LVSymbolTable::getIsComdat(StringRef Name) {
+  LVSymbolNames::iterator Iter = SymbolNames.find(std::string(Name));
+  return Iter != SymbolNames.end() ? Iter->second.IsComdat : false;
+}
+
+void LVSymbolTable::print(raw_ostream &OS) {
+  OS << "Symbol Table\n";
+  for (LVSymbolNames::reference Entry : SymbolNames) {
+    LVSymbolTableEntry &SymbolName = Entry.second;
+    LVScope *Scope = SymbolName.Scope;
+    LVOffset Offset = Scope ? Scope->getOffset() : 0;
+    OS << "Index: " << hexValue(SymbolName.SectionIndex, 5)
+       << " Comdat: " << (SymbolName.IsComdat ? "Y" : "N")
+       << " Scope: " << hexValue(Offset)
+       << " Address: " << hexValue(SymbolName.Address)
+       << " Name: " << Entry.first << "\n";
+  }
+}
+
+void LVBinaryReader::addToSymbolTable(StringRef Name, LVScope *Function,
+                                      LVSectionIndex SectionIndex) {
+  SymbolTable.add(Name, Function, SectionIndex);
+}
+void LVBinaryReader::addToSymbolTable(StringRef Name, LVAddress Address,
+                                      LVSectionIndex SectionIndex,
+                                      bool IsComdat) {
+  SymbolTable.add(Name, Address, SectionIndex, IsComdat);
+}
+LVSectionIndex LVBinaryReader::updateSymbolTable(LVScope *Function) {
+  return SymbolTable.update(Function);
+}
+
+const LVSymbolTableEntry &LVBinaryReader::getSymbolTableEntry(StringRef Name) {
+  return SymbolTable.getEntry(Name);
+}
+LVAddress LVBinaryReader::getSymbolTableAddress(StringRef Name) {
+  return SymbolTable.getAddress(Name);
+}
+LVSectionIndex LVBinaryReader::getSymbolTableIndex(StringRef Name) {
+  return SymbolTable.getIndex(Name);
+}
+bool LVBinaryReader::getSymbolTableIsComdat(StringRef Name) {
+  return SymbolTable.getIsComdat(Name);
+}
+
+void LVBinaryReader::mapVirtualAddress(const object::ObjectFile &Obj) {
+  for (const object::SectionRef &Section : Obj.sections()) {
+    if (!Section.isText() || Section.isVirtual() || !Section.getSize())
+      continue;
+
+    // Record section information required for symbol resolution.
+    // Note: The section index returned by 'getIndex()' is one based.
+    Sections.emplace(Section.getIndex(), Section);
+    addSectionAddress(Section);
+
+    // Identify the ".text" section.
+    Expected<StringRef> SectionNameOrErr = Section.getName();
+    if (!SectionNameOrErr) {
+      consumeError(SectionNameOrErr.takeError());
+      continue;
+    }
+    if ((*SectionNameOrErr).equals(".text") ||
+        (*SectionNameOrErr).equals(".code"))
+      DotTextSectionIndex = Section.getIndex();
+  }
+
+  // Process the symbol table.
+  mapRangeAddress(Obj);
+
+  LLVM_DEBUG({
+    dbgs() << "\nSections Information:\n";
+    for (LVSections::reference Entry : Sections) {
+      LVSectionIndex SectionIndex = Entry.first;
+      const object::SectionRef Section = Entry.second;
+      Expected<StringRef> SectionNameOrErr = Section.getName();
+      if (!SectionNameOrErr)
+        consumeError(SectionNameOrErr.takeError());
+      dbgs() << "\nIndex: " << format_decimal(SectionIndex, 3)
+             << " Name: " << *SectionNameOrErr << "\n"
+             << "Size: " << hexValue(Section.getSize()) << "\n"
+             << "VirtualAddress: " << hexValue(VirtualAddress) << "\n"
+             << "SectionAddress: " << hexValue(Section.getAddress()) << "\n";
+    }
+    dbgs() << "\nObject Section Information:\n";
+    for (LVSectionAddresses::const_reference Entry : SectionAddresses)
+      dbgs() << "[" << hexValue(Entry.first) << ":"
+             << hexValue(Entry.first + Entry.second.getSize())
+             << "] Size: " << hexValue(Entry.second.getSize()) << "\n";
+  });
+}
+
+Error LVBinaryReader::loadGenericTargetInfo(StringRef TheTriple,
+                                            StringRef TheFeatures) {
+  std::string TargetLookupError;
+  const Target *TheTarget =
+      TargetRegistry::lookupTarget(std::string(TheTriple), TargetLookupError);
+  if (!TheTarget)
+    return createStringError(errc::invalid_argument, TargetLookupError.c_str());
+
+  // Register information.
+  MCRegisterInfo *RegisterInfo = TheTarget->createMCRegInfo(TheTriple);
+  if (!RegisterInfo)
+    return createStringError(errc::invalid_argument,
+                             "no register info for target " + TheTriple);
+  MRI.reset(RegisterInfo);
+
+  // Assembler properties and features.
+  MCTargetOptions MCOptions;
+  MCAsmInfo *AsmInfo(TheTarget->createMCAsmInfo(*MRI, TheTriple, MCOptions));
+  if (!AsmInfo)
+    return createStringError(errc::invalid_argument,
+                             "no assembly info for target " + TheTriple);
+  MAI.reset(AsmInfo);
+
+  // Target subtargets.
+  StringRef CPU;
+  MCSubtargetInfo *SubtargetInfo(
+      TheTarget->createMCSubtargetInfo(TheTriple, CPU, TheFeatures));
+  if (!SubtargetInfo)
+    return createStringError(errc::invalid_argument,
+                             "no subtarget info for target " + TheTriple);
+  STI.reset(SubtargetInfo);
+
+  // Instructions Info.
+  MCInstrInfo *InstructionInfo(TheTarget->createMCInstrInfo());
+  if (!InstructionInfo)
+    return createStringError(errc::invalid_argument,
+                             "no instruction info for target " + TheTriple);
+  MII.reset(InstructionInfo);
+
+  MC = std::make_unique<MCContext>(Triple(TheTriple), MAI.get(), MRI.get(),
+                                   STI.get());
+
+  // Assembler.
+  MCDisassembler *DisAsm(TheTarget->createMCDisassembler(*STI, *MC));
+  if (!DisAsm)
+    return createStringError(errc::invalid_argument,
+                             "no disassembler for target " + TheTriple);
+  MD.reset(DisAsm);
+
+  MCInstPrinter *InstructionPrinter(TheTarget->createMCInstPrinter(
+      Triple(TheTriple), AsmInfo->getAssemblerDialect(), *MAI, *MII, *MRI));
+  if (!InstructionPrinter)
+    return createStringError(errc::invalid_argument,
+                             "no target assembly language printer for target " +
+                                 TheTriple);
+  MIP.reset(InstructionPrinter);
+  InstructionPrinter->setPrintImmHex(true);
+
+  return Error::success();
+}
+
+Expected<std::pair<uint64_t, object::SectionRef>>
+LVBinaryReader::getSection(LVScope *Scope, LVAddress Address,
+                           LVSectionIndex SectionIndex) {
+  // Return the 'text' section with the code for this logical scope.
+  // COFF: SectionIndex is zero. Use 'SectionAddresses' data.
+  // ELF: SectionIndex is the section index in the file.
+  if (SectionIndex) {
+    LVSections::iterator Iter = Sections.find(SectionIndex);
+    if (Iter == Sections.end()) {
+      return createStringError(errc::invalid_argument,
+                               "invalid section index for: '%s'",
+                               Scope->getName().str().c_str());
+    }
+    const object::SectionRef Section = Iter->second;
+    return std::make_pair(Section.getAddress(), Section);
+  }
+
+  // Ensure a valid starting address for the public names.
+  LVSectionAddresses::const_iterator Iter =
+      SectionAddresses.upper_bound(Address);
+  if (Iter == SectionAddresses.begin())
+    return createStringError(errc::invalid_argument,
+                             "invalid section address for: '%s'",
+                             Scope->getName().str().c_str());
+
+  // Get section that contains the code for this function.
+  Iter = SectionAddresses.lower_bound(Address);
+  if (Iter != SectionAddresses.begin())
+    --Iter;
+  return std::make_pair(Iter->first, Iter->second);
+}
+
+void LVBinaryReader::addSectionRange(LVSectionIndex SectionIndex,
+                                     LVScope *Scope) {
+  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+  ScopesWithRanges->addEntry(Scope);
+}
+
+void LVBinaryReader::addSectionRange(LVSectionIndex SectionIndex,
+                                     LVScope *Scope, LVAddress LowerAddress,
+                                     LVAddress UpperAddress) {
+  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+  ScopesWithRanges->addEntry(Scope, LowerAddress, UpperAddress);
+}
+
+LVRange *LVBinaryReader::getSectionRanges(LVSectionIndex SectionIndex) {
+  LVRange *Range = nullptr;
+  // Check if we already have a mapping for this section index.
+  LVSectionRanges::iterator IterSection = SectionRanges.find(SectionIndex);
+  if (IterSection == SectionRanges.end()) {
+    Range = new LVRange();
+    SectionRanges.emplace(SectionIndex, Range);
+  } else {
+    Range = IterSection->second;
+  }
+  assert(Range && "Range is null.");
+  return Range;
+}
+
+LVBinaryReader::~LVBinaryReader() {
+  // Delete the lines created by 'createInstructions'.
+  std::vector<LVLines *> AllInstructionLines = ScopeInstructions.find();
+  for (LVLines *Entry : AllInstructionLines)
+    delete Entry;
+  // Delete the ranges created by 'getSectionRanges'.
+  for (LVSectionRanges::reference Entry : SectionRanges)
+    delete Entry.second;
+}
+
+Error LVBinaryReader::createInstructions(LVScope *Scope,
+                                         LVSectionIndex SectionIndex,
+                                         const LVNameInfo &NameInfo) {
+  assert(Scope && "Scope is null.");
+
+  // Skip stripped functions.
+  if (Scope->getIsDiscarded())
+    return Error::success();
+
+  // Find associated address and size for the given function entry point.
+  LVAddress Address = NameInfo.first;
+  uint64_t Size = NameInfo.second;
+
+  LLVM_DEBUG({
+    dbgs() << "\nPublic Name instructions: '" << Scope->getName() << "' / '"
+           << Scope->getLinkageName() << "'\n"
+           << "DIE Offset: " << hexValue(Scope->getOffset()) << " Range: ["
+           << hexValue(Address) << ":" << hexValue(Address + Size) << "]\n";
+  });
+
+  Expected<std::pair<uint64_t, const object::SectionRef>> SectionOrErr =
+      getSection(Scope, Address, SectionIndex);
+  if (!SectionOrErr)
+    return SectionOrErr.takeError();
+  const object::SectionRef Section = (*SectionOrErr).second;
+  uint64_t SectionAddress = (*SectionOrErr).first;
+
+  Expected<StringRef> SectionContentsOrErr = Section.getContents();
+  if (!SectionContentsOrErr)
+    return SectionOrErr.takeError();
+
+  // There are cases where the section size is smaller than the [LowPC,HighPC]
+  // range; it causes us to decode invalid addresses. The recorded size in the
+  // logical scope is one less than the real size.
+  LLVM_DEBUG({
+    dbgs() << " Size: " << hexValue(Size)
+           << ", Section Size: " << hexValue(Section.getSize()) << "\n";
+  });
+  Size = std::min(Size + 1, Section.getSize());
+
+  ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(*SectionContentsOrErr);
+  uint64_t Offset = Address - SectionAddress;
+  uint8_t const *Begin = Bytes.data() + Offset;
+  uint8_t const *End = Bytes.data() + Offset + Size;
+
+  LLVM_DEBUG({
+    Expected<StringRef> SectionNameOrErr = Section.getName();
+    if (!SectionNameOrErr)
+      consumeError(SectionNameOrErr.takeError());
+    else
+      dbgs() << "Section Index: " << hexValue(Section.getIndex()) << " ["
+             << hexValue((uint64_t)Section.getAddress()) << ":"
+             << hexValue((uint64_t)Section.getAddress() + Section.getSize(), 10)
+             << "] Name: '" << *SectionNameOrErr << "'\n"
+             << "Begin: " << hexValue((uint64_t)Begin)
+             << ", End: " << hexValue((uint64_t)End) << "\n";
+  });
+
+  // Address for first instruction line.
+  LVAddress FirstAddress = Address;
+  LVLines *Instructions = new LVLines();
+
+  while (Begin < End) {
+    MCInst Instruction;
+    uint64_t BytesConsumed = 0;
+    SmallVector<char, 64> InsnStr;
+    raw_svector_ostream Annotations(InsnStr);
+    MCDisassembler::DecodeStatus const S =
+        MD->getInstruction(Instruction, BytesConsumed,
+                           ArrayRef<uint8_t>(Begin, End), Address, outs());
+    switch (S) {
+    case MCDisassembler::Fail:
+      LLVM_DEBUG({ dbgs() << "Invalid instruction\n"; });
+      if (BytesConsumed == 0)
+        // Skip invalid bytes
+        BytesConsumed = 1;
+      break;
+    case MCDisassembler::SoftFail:
+      LLVM_DEBUG({ dbgs() << "Potentially undefined instruction:"; });
+      LLVM_FALLTHROUGH;
+    case MCDisassembler::Success: {
+      std::string Buffer;
+      raw_string_ostream Stream(Buffer);
+      StringRef AnnotationsStr = Annotations.str();
+      MIP.get()->printInst(&Instruction, Address, AnnotationsStr, *STI, Stream);
+      LLVM_DEBUG({
+        std::string BufferCodes;
+        raw_string_ostream StreamCodes(BufferCodes);
+        StreamCodes << format_bytes(
+            ArrayRef<uint8_t>(Begin, Begin + BytesConsumed), None, 16, 16);
+        dbgs() << "[" << hexValue((uint64_t)Begin) << "] "
+               << "Size: " << format_decimal(BytesConsumed, 2) << " ("
+               << formatv("{0}",
+                          fmt_align(StreamCodes.str(), AlignStyle::Left, 32))
+               << ") " << hexValue((uint64_t)Address) << ": " << Stream.str()
+               << "\n";
+      });
+      // Here we add logical lines to the Instructions. Later on,
+      // the 'processLines()' function will move each created logical line
+      // to its enclosing logical scope, using the debug ranges information
+      // and they will be released when its scope parent is deleted.
+      LVLineAssembler *Line = new LVLineAssembler();
+      Line->setAddress(Address);
+      Line->setName(StringRef(Stream.str()).trim());
+      Instructions->push_back(Line);
+      break;
+    }
+    }
+    Address += BytesConsumed;
+    Begin += BytesConsumed;
+  }
+
+  LLVM_DEBUG({
+    size_t Index = 0;
+    dbgs() << "\nSectionIndex: " << format_decimal(SectionIndex, 3)
+           << " Scope DIE: " << hexValue(Scope->getOffset()) << "\n"
+           << "Address: " << hexValue(FirstAddress)
+           << format(" - Collected instructions lines: %d\n",
+                     Instructions->size());
+    for (const LVLine *Line : *Instructions)
+      dbgs() << format_decimal(++Index, 5) << ": "
+             << hexValue(Line->getOffset()) << ", (" << Line->getName()
+             << ")\n";
+  });
+
+  // The scope in the assembler names is linked to its own instructions.
+  ScopeInstructions.add(SectionIndex, Scope, Instructions);
+  AssemblerMappings.add(SectionIndex, FirstAddress, Scope);
+
+  return Error::success();
+}
+
+Error LVBinaryReader::createInstructions(LVScope *Function,
+                                         LVSectionIndex SectionIndex) {
+  if (!options().getPrintInstructions())
+    return Error::success();
+
+  LVNameInfo Name = CompileUnit->findPublicName(Function);
+  if (Name.first != LVAddress(UINT64_MAX))
+    return createInstructions(Function, SectionIndex, Name);
+
+  return Error::success();
+}
+
+Error LVBinaryReader::createInstructions() {
+  if (!options().getPrintInstructions())
+    return Error::success();
+
+  LLVM_DEBUG({
+    size_t Index = 1;
+    dbgs() << "\nPublic Names (Scope):\n";
+    for (LVPublicNames::const_reference Name : CompileUnit->getPublicNames()) {
+      LVScope *Scope = Name.first;
+      const LVNameInfo &NameInfo = Name.second;
+      LVAddress Address = NameInfo.first;
+      uint64_t Size = NameInfo.second;
+      dbgs() << format_decimal(Index++, 5) << ": "
+             << "DIE Offset: " << hexValue(Scope->getOffset()) << " Range: ["
+             << hexValue(Address) << ":" << hexValue(Address + Size) << "] "
+             << "Name: '" << Scope->getName() << "' / '"
+             << Scope->getLinkageName() << "'\n";
+    }
+  });
+
+  // For each public name in the current compile unit, create the line
+  // records that represent the executable instructions.
+  for (LVPublicNames::const_reference Name : CompileUnit->getPublicNames()) {
+    LVScope *Scope = Name.first;
+    // The symbol table extracted from the object file always contains a
+    // non-empty name (linkage name). However, the logical scope does not
+    // guarantee to have a name for the linkage name (main is one case).
+    // For those cases, set the linkage name the same as the name.
+    if (!Scope->getLinkageNameIndex())
+      Scope->setLinkageName(Scope->getName());
+    LVSectionIndex SectionIndex = getSymbolTableIndex(Scope->getLinkageName());
+    if (Error Err = createInstructions(Scope, SectionIndex, Name.second))
+      return Err;
+  }
+
+  return Error::success();
+}
+
+// During the traversal of the debug information sections, we created the
+// logical lines representing the disassembled instructions from the text
+// section and the logical lines representing the line records from the
+// debug line section. Using the ranges associated with the logical scopes,
+// we will allocate those logical lines to their logical scopes.
+void LVBinaryReader::processLines(LVLines *DebugLines,
+                                  LVSectionIndex SectionIndex,
+                                  LVScope *Function) {
+  assert(DebugLines && "DebugLines is null.");
+
+  // Just return if this compilation unit does not have any line records
+  // and no instruction lines were created.
+  if (DebugLines->empty() && !options().getPrintInstructions())
+    return;
+
+  // Merge the debug lines and instruction lines using their text address;
+  // the logical line representing the debug line record is followed by the
+  // line(s) representing the disassembled instructions, whose addresses are
+  // equal or greater that the line address and less than the address of the
+  // next debug line record.
+  LLVM_DEBUG({
+    size_t Index = 1;
+    size_t PerLine = 4;
+    dbgs() << format("\nProcess debug lines: %d\n", DebugLines->size());
+    for (const LVLine *Line : *DebugLines) {
+      dbgs() << format_decimal(Index, 5) << ": " << hexValue(Line->getOffset())
+             << ", (" << Line->getLineNumber() << ")"
+             << ((Index % PerLine) ? "  " : "\n");
+      ++Index;
+    }
+    dbgs() << ((Index % PerLine) ? "\n" : "");
+  });
+
+  bool TraverseLines = true;
+  LVLines::iterator Iter = DebugLines->begin();
+  while (TraverseLines && Iter != DebugLines->end()) {
+    uint64_t DebugAddress = (*Iter)->getAddress();
+
+    // Get the function with an entry point that matches this line and
+    // its associated assembler entries. In the case of COMDAT, the input
+    // 'Function' is not null. Use it to find its address ranges.
+    LVScope *Scope = Function;
+    if (!Function) {
+      Scope = AssemblerMappings.find(SectionIndex, DebugAddress);
+      if (!Scope) {
+        ++Iter;
+        continue;
+      }
+    }
+
+    // Get the associated instructions for the found 'Scope'.
+    LVLines InstructionLines;
+    LVLines *Lines = ScopeInstructions.find(SectionIndex, Scope);
+    if (Lines)
+      InstructionLines = std::move(*Lines);
+
+    LLVM_DEBUG({
+      size_t Index = 0;
+      dbgs() << "\nSectionIndex: " << format_decimal(SectionIndex, 3)
+             << " Scope DIE: " << hexValue(Scope->getOffset()) << "\n"
+             << format("Process instructions lines: %d\n",
+                       InstructionLines.size());
+      for (const LVLine *Line : InstructionLines)
+        dbgs() << format_decimal(++Index, 5) << ": "
+               << hexValue(Line->getOffset()) << ", (" << Line->getName()
+               << ")\n";
+    });
+
+    // Continue with next debug line if there are not instructions lines.
+    if (InstructionLines.empty()) {
+      ++Iter;
+      continue;
+    }
+
+    for (LVLine *InstructionLine : InstructionLines) {
+      uint64_t InstructionAddress = InstructionLine->getAddress();
+      LLVM_DEBUG({
+        dbgs() << "Instruction address: " << hexValue(InstructionAddress)
+               << "\n";
+      });
+      if (TraverseLines) {
+        while (Iter != DebugLines->end()) {
+          DebugAddress = (*Iter)->getAddress();
+          LLVM_DEBUG({
+            bool IsDebug = (*Iter)->getIsLineDebug();
+            dbgs() << "Line " << (IsDebug ? "dbg:" : "ins:") << " ["
+                   << hexValue(DebugAddress) << "]";
+            if (IsDebug)
+              dbgs() << format(" %d", (*Iter)->getLineNumber());
+            dbgs() << "\n";
+          });
+          // Instruction address before debug line.
+          if (InstructionAddress < DebugAddress) {
+            LLVM_DEBUG({
+              dbgs() << "Inserted instruction address: "
+                     << hexValue(InstructionAddress) << " before line: "
+                     << format("%d", (*Iter)->getLineNumber()) << " ["
+                     << hexValue(DebugAddress) << "]\n";
+            });
+            Iter = DebugLines->insert(Iter, InstructionLine);
+            // The returned iterator points to the inserted instruction.
+            // Skip it and point to the line acting as reference.
+            ++Iter;
+            break;
+          }
+          ++Iter;
+        }
+        if (Iter == DebugLines->end()) {
+          // We have reached the end of the source lines and the current
+          // instruction line address is greater than the last source line.
+          TraverseLines = false;
+          DebugLines->push_back(InstructionLine);
+        }
+      } else {
+        DebugLines->push_back(InstructionLine);
+      }
+    }
+  }
+
+  LLVM_DEBUG({
+    dbgs() << format("Lines after merge: %d\n", DebugLines->size());
+    size_t Index = 0;
+    for (const LVLine *Line : *DebugLines) {
+      dbgs() << format_decimal(++Index, 5) << ": "
+             << hexValue(Line->getOffset()) << ", ("
+             << ((Line->getIsLineDebug())
+                     ? Line->lineNumberAsStringStripped(/*ShowZero=*/true)
+                     : Line->getName())
+             << ")\n";
+    }
+  });
+
+  // If this compilation unit does not have line records, traverse its scopes
+  // and take any collected instruction lines as the working set in order
+  // to move them to their associated scope.
+  if (DebugLines->empty()) {
+    if (const LVScopes *Scopes = CompileUnit->getScopes())
+      for (LVScope *Scope : *Scopes) {
+        if (Scope->getIsArtificial())
+          continue;
+        LVLines *Lines = ScopeInstructions.find(Scope);
+        if (Lines) {
+
+          LLVM_DEBUG({
+            size_t Index = 0;
+            dbgs() << "\nSectionIndex: " << format_decimal(SectionIndex, 3)
+                   << " Scope DIE: " << hexValue(Scope->getOffset()) << "\n"
+                   << format("Instructions lines: %d\n", Lines->size());
+            for (const LVLine *Line : *Lines)
+              dbgs() << format_decimal(++Index, 5) << ": "
+                     << hexValue(Line->getOffset()) << ", (" << Line->getName()
+                     << ")\n";
+          });
+
+          DebugLines->append(*Lines);
+          Lines->clear();
+        }
+      }
+  }
+
+  LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+  ScopesWithRanges->startSearch();
+
+  // Process collected lines.
+  LVScope *Scope;
+  for (LVLine *Line : *DebugLines) {
+    // Using the current line address, get its associated lexical scope and
+    // add the line information to it.
+    Scope = ScopesWithRanges->getEntry(Line->getAddress());
+    if (!Scope) {
+      // If missing scope, use the compile unit.
+      Scope = CompileUnit;
+      LLVM_DEBUG({
+        dbgs() << "Adding line to CU: " << hexValue(Line->getOffset()) << ", ("
+               << ((Line->getIsLineDebug())
+                       ? Line->lineNumberAsStringStripped(/*ShowZero=*/true)
+                       : Line->getName())
+               << ")\n";
+      });
+    }
+
+    // Add line object to scope.
+    Scope->addElement(Line);
+
+    // Report any line zero.
+    if (options().getWarningLines() && Line->getIsLineDebug() &&
+        !Line->getLineNumber())
+      CompileUnit->addLineZero(Line);
+
+    // Some compilers generate ranges in the compile unit; other compilers
+    // only DW_AT_low_pc/DW_AT_high_pc. In order to correctly map global
+    // variables, we need to generate the map ranges for the compile unit.
+    // If we use the ranges stored at the scope level, there are cases where
+    // the address referenced by a symbol location, is not in the enclosing
+    // scope, but in an outer one. By using the ranges stored in the compile
+    // unit, we can catch all those addresses.
+    if (Line->getIsLineDebug())
+      CompileUnit->addMapping(Line, SectionIndex);
+
+    // Resolve any given pattern.
+    patterns().resolvePatternMatch(Line);
+  }
+
+  ScopesWithRanges->endSearch();
+}
+
+void LVBinaryReader::processLines(LVLines *DebugLines,
+                                  LVSectionIndex SectionIndex) {
+  assert(DebugLines && "DebugLines is null.");
+  if (DebugLines->empty() && !ScopeInstructions.findMap(SectionIndex))
+    return;
+
+  // If the Compile Unit does not contain comdat functions, use the whole
+  // set of debug lines, as the addresses don't have conflicts.
+  if (!CompileUnit->getHasComdatScopes()) {
+    processLines(DebugLines, SectionIndex, nullptr);
+    return;
+  }
+
+  // Find the indexes for the lines whose address is zero.
+  std::vector<size_t> AddressZero;
+  LVLines::iterator It =
+      std::find_if(std::begin(*DebugLines), std::end(*DebugLines),
+                   [](LVLine *Line) { return !Line->getAddress(); });
+  while (It != std::end(*DebugLines)) {
+    AddressZero.emplace_back(std::distance(std::begin(*DebugLines), It));
+    It = std::find_if(std::next(It), std::end(*DebugLines),
+                      [](LVLine *Line) { return !Line->getAddress(); });
+  }
+
+  // If the set of debug lines does not contain any line with address zero,
+  // use the whole set. It means we are dealing with an initialization
+  // section from a fully linked binary.
+  if (AddressZero.empty()) {
+    processLines(DebugLines, SectionIndex, nullptr);
+    return;
+  }
+
+  // The Compile unit contains comdat functions. Traverse the collected
+  // debug lines and identify logical groups based on their start and
+  // address. Each group starts with a zero address.
+  // Begin, End, Address, IsDone.
+  using LVBucket = std::tuple<size_t, size_t, LVAddress, bool>;
+  std::vector<LVBucket> Buckets;
+
+  LVAddress Address;
+  size_t Begin = 0;
+  size_t End = 0;
+  size_t Index = 0;
+  for (Index = 0; Index < AddressZero.size() - 1; ++Index) {
+    Begin = AddressZero[Index];
+    End = AddressZero[Index + 1] - 1;
+    Address = (*DebugLines)[End]->getAddress();
+    Buckets.emplace_back(Begin, End, Address, false);
+  }
+
+  // Add the last bucket.
+  if (Index) {
+    Begin = AddressZero[Index];
+    End = DebugLines->size() - 1;
+    Address = (*DebugLines)[End]->getAddress();
+    Buckets.emplace_back(Begin, End, Address, false);
+  }
+
+  LLVM_DEBUG({
+    dbgs() << "\nDebug Lines buckets: " << Buckets.size() << "\n";
+    for (LVBucket &Bucket : Buckets) {
+      dbgs() << "Begin: " << format_decimal(std::get<0>(Bucket), 5) << ", "
+             << "End: " << format_decimal(std::get<1>(Bucket), 5) << ", "
+             << "Address: " << hexValue(std::get<2>(Bucket)) << "\n";
+    }
+  });
+
+  // Traverse the sections and buckets looking for matches on the section
+  // sizes. In the unlikely event of 
diff erent buckets with the same size
+  // process them in order and mark them as done.
+  LVLines Group;
+  for (LVSections::reference Entry : Sections) {
+    LVSectionIndex SectionIndex = Entry.first;
+    const object::SectionRef Section = Entry.second;
+    uint64_t Size = Section.getSize();
+    LLVM_DEBUG({
+      dbgs() << "\nSection Index: " << format_decimal(SectionIndex, 3)
+             << " , Section Size: " << hexValue(Section.getSize())
+             << " , Section Address: " << hexValue(Section.getAddress())
+             << "\n";
+    });
+
+    for (LVBucket &Bucket : Buckets) {
+      if (std::get<3>(Bucket))
+        // Already done for previous section.
+        continue;
+      if (Size == std::get<2>(Bucket)) {
+        // We have a match on the section size.
+        Group.clear();
+        LVLines::iterator IterStart = DebugLines->begin() + std::get<0>(Bucket);
+        LVLines::iterator IterEnd =
+            DebugLines->begin() + std::get<1>(Bucket) + 1;
+        for (LVLines::iterator Iter = IterStart; Iter < IterEnd; ++Iter)
+          Group.push_back(*Iter);
+        processLines(&Group, SectionIndex, /*Function=*/nullptr);
+        std::get<3>(Bucket) = true;
+        break;
+      }
+    }
+  }
+}
+
+void LVBinaryReader::print(raw_ostream &OS) const {
+  OS << "LVBinaryReader\n";
+  LLVM_DEBUG(dbgs() << "PrintReader\n");
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
new file mode 100644
index 0000000000000..6a7e28939d3fd
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Readers/LVELFReader.cpp
@@ -0,0 +1,1235 @@
+//===-- LVELFReader.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 LVELFReader class.
+// It supports ELF and Mach-O formats.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Readers/LVELFReader.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "ElfReader"
+
+LVElement *LVELFReader::createElement(dwarf::Tag Tag) {
+  CurrentScope = nullptr;
+  CurrentSymbol = nullptr;
+  CurrentType = nullptr;
+  CurrentRanges.clear();
+
+  if (!options().getPrintSymbols()) {
+    switch (Tag) {
+    // As the command line options did not specify a request to print
+    // logical symbols (--print=symbols or --print=all or --print=elements),
+    // skip its creation.
+    case dwarf::DW_TAG_formal_parameter:
+    case dwarf::DW_TAG_unspecified_parameters:
+    case dwarf::DW_TAG_member:
+    case dwarf::DW_TAG_variable:
+    case dwarf::DW_TAG_inheritance:
+    case dwarf::DW_TAG_constant:
+    case dwarf::DW_TAG_call_site_parameter:
+    case dwarf::DW_TAG_GNU_call_site_parameter:
+      return nullptr;
+    default:
+      break;
+    }
+  }
+
+  switch (Tag) {
+  // Types.
+  case dwarf::DW_TAG_base_type:
+    CurrentType = new LVType();
+    CurrentType->setIsBase();
+    if (options().getAttributeBase())
+      CurrentType->setIncludeInPrint();
+    return CurrentType;
+  case dwarf::DW_TAG_const_type:
+    CurrentType = new LVType();
+    CurrentType->setIsConst();
+    CurrentType->setName("const");
+    return CurrentType;
+  case dwarf::DW_TAG_enumerator:
+    CurrentType = new LVTypeEnumerator();
+    return CurrentType;
+  case dwarf::DW_TAG_imported_declaration:
+    CurrentType = new LVTypeImport();
+    CurrentType->setIsImportDeclaration();
+    return CurrentType;
+  case dwarf::DW_TAG_imported_module:
+    CurrentType = new LVTypeImport();
+    CurrentType->setIsImportModule();
+    return CurrentType;
+  case dwarf::DW_TAG_pointer_type:
+    CurrentType = new LVType();
+    CurrentType->setIsPointer();
+    CurrentType->setName("*");
+    return CurrentType;
+  case dwarf::DW_TAG_ptr_to_member_type:
+    CurrentType = new LVType();
+    CurrentType->setIsPointerMember();
+    CurrentType->setName("*");
+    return CurrentType;
+  case dwarf::DW_TAG_reference_type:
+    CurrentType = new LVType();
+    CurrentType->setIsReference();
+    CurrentType->setName("&");
+    return CurrentType;
+  case dwarf::DW_TAG_restrict_type:
+    CurrentType = new LVType();
+    CurrentType->setIsRestrict();
+    CurrentType->setName("restrict");
+    return CurrentType;
+  case dwarf::DW_TAG_rvalue_reference_type:
+    CurrentType = new LVType();
+    CurrentType->setIsRvalueReference();
+    CurrentType->setName("&&");
+    return CurrentType;
+  case dwarf::DW_TAG_subrange_type:
+    CurrentType = new LVTypeSubrange();
+    return CurrentType;
+  case dwarf::DW_TAG_template_value_parameter:
+    CurrentType = new LVTypeParam();
+    CurrentType->setIsTemplateValueParam();
+    return CurrentType;
+  case dwarf::DW_TAG_template_type_parameter:
+    CurrentType = new LVTypeParam();
+    CurrentType->setIsTemplateTypeParam();
+    return CurrentType;
+  case dwarf::DW_TAG_GNU_template_template_param:
+    CurrentType = new LVTypeParam();
+    CurrentType->setIsTemplateTemplateParam();
+    return CurrentType;
+  case dwarf::DW_TAG_typedef:
+    CurrentType = new LVTypeDefinition();
+    return CurrentType;
+  case dwarf::DW_TAG_unspecified_type:
+    CurrentType = new LVType();
+    CurrentType->setIsUnspecified();
+    return CurrentType;
+  case dwarf::DW_TAG_volatile_type:
+    CurrentType = new LVType();
+    CurrentType->setIsVolatile();
+    CurrentType->setName("volatile");
+    return CurrentType;
+
+  // Symbols.
+  case dwarf::DW_TAG_formal_parameter:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsParameter();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_unspecified_parameters:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsUnspecified();
+    CurrentSymbol->setName("...");
+    return CurrentSymbol;
+  case dwarf::DW_TAG_member:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsMember();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_variable:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsVariable();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_inheritance:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsInheritance();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_call_site_parameter:
+  case dwarf::DW_TAG_GNU_call_site_parameter:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsCallSiteParameter();
+    return CurrentSymbol;
+  case dwarf::DW_TAG_constant:
+    CurrentSymbol = new LVSymbol();
+    CurrentSymbol->setIsConstant();
+    return CurrentSymbol;
+
+  // Scopes.
+  case dwarf::DW_TAG_catch_block:
+    CurrentScope = new LVScope();
+    CurrentScope->setIsCatchBlock();
+    return CurrentScope;
+  case dwarf::DW_TAG_lexical_block:
+    CurrentScope = new LVScope();
+    CurrentScope->setIsLexicalBlock();
+    return CurrentScope;
+  case dwarf::DW_TAG_try_block:
+    CurrentScope = new LVScope();
+    CurrentScope->setIsTryBlock();
+    return CurrentScope;
+  case dwarf::DW_TAG_compile_unit:
+  case dwarf::DW_TAG_skeleton_unit:
+    CurrentScope = new LVScopeCompileUnit();
+    CompileUnit = static_cast<LVScopeCompileUnit *>(CurrentScope);
+    return CurrentScope;
+  case dwarf::DW_TAG_inlined_subroutine:
+    CurrentScope = new LVScopeFunctionInlined();
+    return CurrentScope;
+  case dwarf::DW_TAG_namespace:
+    CurrentScope = new LVScopeNamespace();
+    return CurrentScope;
+  case dwarf::DW_TAG_template_alias:
+    CurrentScope = new LVScopeAlias();
+    return CurrentScope;
+  case dwarf::DW_TAG_array_type:
+    CurrentScope = new LVScopeArray();
+    return CurrentScope;
+  case dwarf::DW_TAG_call_site:
+  case dwarf::DW_TAG_GNU_call_site:
+    CurrentScope = new LVScopeFunction();
+    CurrentScope->setIsCallSite();
+    return CurrentScope;
+  case dwarf::DW_TAG_entry_point:
+    CurrentScope = new LVScopeFunction();
+    CurrentScope->setIsEntryPoint();
+    return CurrentScope;
+  case dwarf::DW_TAG_subprogram:
+    CurrentScope = new LVScopeFunction();
+    CurrentScope->setIsSubprogram();
+    return CurrentScope;
+  case dwarf::DW_TAG_subroutine_type:
+    CurrentScope = new LVScopeFunctionType();
+    return CurrentScope;
+  case dwarf::DW_TAG_label:
+    CurrentScope = new LVScopeFunction();
+    CurrentScope->setIsLabel();
+    return CurrentScope;
+  case dwarf::DW_TAG_class_type:
+    CurrentScope = new LVScopeAggregate();
+    CurrentScope->setIsClass();
+    return CurrentScope;
+  case dwarf::DW_TAG_structure_type:
+    CurrentScope = new LVScopeAggregate();
+    CurrentScope->setIsStructure();
+    return CurrentScope;
+  case dwarf::DW_TAG_union_type:
+    CurrentScope = new LVScopeAggregate();
+    CurrentScope->setIsUnion();
+    return CurrentScope;
+  case dwarf::DW_TAG_enumeration_type:
+    CurrentScope = new LVScopeEnumeration();
+    return CurrentScope;
+  case dwarf::DW_TAG_GNU_formal_parameter_pack:
+    CurrentScope = new LVScopeFormalPack();
+    return CurrentScope;
+  case dwarf::DW_TAG_GNU_template_parameter_pack:
+    CurrentScope = new LVScopeTemplatePack();
+    return CurrentScope;
+  default:
+    // Collect TAGs not implemented.
+    if (options().getInternalTag() && Tag)
+      CompileUnit->addDebugTag(Tag, CurrentOffset);
+    break;
+  }
+  return nullptr;
+}
+
+void LVELFReader::processOneAttribute(const DWARFDie &Die, LVOffset *OffsetPtr,
+                                      const AttributeSpec &AttrSpec) {
+  uint64_t OffsetOnEntry = *OffsetPtr;
+  DWARFUnit *U = Die.getDwarfUnit();
+  const DWARFFormValue &FormValue =
+      DWARFFormValue::createFromUnit(AttrSpec.Form, U, OffsetPtr);
+
+  // We are processing .debug_info section, implicit_const attribute
+  // values are not really stored here, but in .debug_abbrev section.
+  auto GetAsUnsignedConstant = [&]() -> int64_t {
+    return AttrSpec.isImplicitConst() ? AttrSpec.getImplicitConstValue()
+                                      : *FormValue.getAsUnsignedConstant();
+  };
+
+  auto GetFlag = [](const DWARFFormValue &FormValue) -> bool {
+    return FormValue.isFormClass(DWARFFormValue::FC_Flag);
+  };
+
+  auto GetBoundValue = [](const DWARFFormValue &FormValue) -> int64_t {
+    switch (FormValue.getForm()) {
+    case dwarf::DW_FORM_ref_addr:
+    case dwarf::DW_FORM_ref1:
+    case dwarf::DW_FORM_ref2:
+    case dwarf::DW_FORM_ref4:
+    case dwarf::DW_FORM_ref8:
+    case dwarf::DW_FORM_ref_udata:
+    case dwarf::DW_FORM_ref_sig8:
+      return *FormValue.getAsReferenceUVal();
+    case dwarf::DW_FORM_data1:
+    case dwarf::DW_FORM_flag:
+    case dwarf::DW_FORM_data2:
+    case dwarf::DW_FORM_data4:
+    case dwarf::DW_FORM_data8:
+    case dwarf::DW_FORM_udata:
+    case dwarf::DW_FORM_ref_sup4:
+    case dwarf::DW_FORM_ref_sup8:
+      return *FormValue.getAsUnsignedConstant();
+    case dwarf::DW_FORM_sdata:
+      return *FormValue.getAsSignedConstant();
+    default:
+      return 0;
+    }
+  };
+
+  LLVM_DEBUG({
+    dbgs() << "     " << hexValue(OffsetOnEntry)
+           << formatv(" {0}", AttrSpec.Attr) << "\n";
+  });
+
+  switch (AttrSpec.Attr) {
+  case dwarf::DW_AT_accessibility:
+    CurrentElement->setAccessibilityCode(*FormValue.getAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_artificial:
+    CurrentElement->setIsArtificial();
+    break;
+  case dwarf::DW_AT_bit_size:
+    CurrentElement->setBitSize(*FormValue.getAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_call_file:
+    CurrentElement->setCallFilenameIndex(GetAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_call_line:
+    CurrentElement->setCallLineNumber(IncrementFileIndex
+                                          ? GetAsUnsignedConstant() + 1
+                                          : GetAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_comp_dir:
+    CompileUnit->setCompilationDirectory(dwarf::toStringRef(FormValue));
+    break;
+  case dwarf::DW_AT_const_value:
+    if (FormValue.isFormClass(DWARFFormValue::FC_Block)) {
+      ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+      // Store the expression as a hexadecimal string.
+      CurrentElement->setValue(
+          llvm::toHex(llvm::toStringRef(Expr), /*LowerCase=*/true));
+    } else if (FormValue.isFormClass(DWARFFormValue::FC_Constant)) {
+      // In the case of negative values, generate the string representation
+      // for a positive value prefixed with the negative sign.
+      if (FormValue.getForm() == dwarf::DW_FORM_sdata) {
+        std::stringstream Stream;
+        int64_t Value = *FormValue.getAsSignedConstant();
+        if (Value < 0) {
+          Stream << "-";
+          Value = std::abs(Value);
+        }
+        Stream << hexString(Value, 2);
+        CurrentElement->setValue(Stream.str());
+      } else
+        CurrentElement->setValue(
+            hexString(*FormValue.getAsUnsignedConstant(), 2));
+    } else
+      CurrentElement->setValue(dwarf::toStringRef(FormValue));
+    break;
+  case dwarf::DW_AT_count:
+    CurrentElement->setCount(*FormValue.getAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_decl_line:
+    CurrentElement->setLineNumber(GetAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_decl_file:
+    CurrentElement->setFilenameIndex(IncrementFileIndex
+                                         ? GetAsUnsignedConstant() + 1
+                                         : GetAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_enum_class:
+    if (GetFlag(FormValue))
+      CurrentElement->setIsEnumClass();
+    break;
+  case dwarf::DW_AT_external:
+    if (GetFlag(FormValue))
+      CurrentElement->setIsExternal();
+    break;
+  case dwarf::DW_AT_GNU_discriminator:
+    CurrentElement->setDiscriminator(*FormValue.getAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_inline:
+    CurrentElement->setInlineCode(*FormValue.getAsUnsignedConstant());
+    break;
+  case dwarf::DW_AT_lower_bound:
+    CurrentElement->setLowerBound(GetBoundValue(FormValue));
+    break;
+  case dwarf::DW_AT_name:
+    CurrentElement->setName(dwarf::toStringRef(FormValue));
+    break;
+  case dwarf::DW_AT_linkage_name:
+  case dwarf::DW_AT_MIPS_linkage_name:
+    CurrentElement->setLinkageName(dwarf::toStringRef(FormValue));
+    break;
+  case dwarf::DW_AT_producer:
+    if (options().getAttributeProducer())
+      CurrentElement->setProducer(dwarf::toStringRef(FormValue));
+    break;
+  case dwarf::DW_AT_upper_bound:
+    CurrentElement->setUpperBound(GetBoundValue(FormValue));
+    break;
+  case dwarf::DW_AT_virtuality:
+    CurrentElement->setVirtualityCode(*FormValue.getAsUnsignedConstant());
+    break;
+
+  case dwarf::DW_AT_abstract_origin:
+  case dwarf::DW_AT_call_origin:
+  case dwarf::DW_AT_extension:
+  case dwarf::DW_AT_import:
+  case dwarf::DW_AT_specification:
+  case dwarf::DW_AT_type:
+    updateReference(AttrSpec.Attr, FormValue);
+    break;
+
+  case dwarf::DW_AT_low_pc:
+    if (options().getGeneralCollectRanges()) {
+      FoundLowPC = true;
+      // For toolchains that support the removal of unused code, the linker
+      // marks functions that have been removed, by setting the value for the
+      // low_pc to the max address.
+      if (Optional<uint64_t> Value = FormValue.getAsAddress()) {
+        CurrentLowPC = Value.value();
+      } else {
+        uint64_t UValue = FormValue.getRawUValue();
+        if (U->getAddrOffsetSectionItem(UValue)) {
+          CurrentLowPC = *FormValue.getAsAddress();
+        } else {
+          FoundLowPC = false;
+          // We are dealing with an index into the .debug_addr section.
+          LLVM_DEBUG({
+            dbgs() << format("indexed (%8.8x) address = ", (uint32_t)UValue);
+          });
+        }
+      }
+      if (FoundLowPC) {
+        if (CurrentLowPC == MaxAddress)
+          CurrentElement->setIsDiscarded();
+        if (CurrentElement->isCompileUnit())
+          setCUBaseAddress(CurrentLowPC);
+      }
+    }
+    break;
+
+  case dwarf::DW_AT_high_pc:
+    if (options().getGeneralCollectRanges()) {
+      FoundHighPC = true;
+      if (Optional<uint64_t> Address = FormValue.getAsAddress())
+        // High PC is an address.
+        CurrentHighPC = *Address;
+      if (Optional<uint64_t> Offset = FormValue.getAsUnsignedConstant())
+        // High PC is an offset from LowPC.
+        CurrentHighPC = CurrentLowPC + *Offset;
+      // Store the real upper limit for the address range.
+      if (UpdateHighAddress && CurrentHighPC > 0)
+        --CurrentHighPC;
+      if (CurrentElement->isCompileUnit())
+        setCUHighAddress(CurrentHighPC);
+    }
+    break;
+
+  case dwarf::DW_AT_ranges:
+    if (RangesDataAvailable && options().getGeneralCollectRanges()) {
+      auto GetRanges = [](const DWARFFormValue &FormValue,
+                          DWARFUnit *U) -> Expected<DWARFAddressRangesVector> {
+        if (FormValue.getForm() == dwarf::DW_FORM_rnglistx)
+          return U->findRnglistFromIndex(*FormValue.getAsSectionOffset());
+        return U->findRnglistFromOffset(*FormValue.getAsSectionOffset());
+      };
+      Expected<DWARFAddressRangesVector> RangesOrError =
+          GetRanges(FormValue, U);
+      if (!RangesOrError) {
+        LLVM_DEBUG({
+          std::string TheError(toString(RangesOrError.takeError()));
+          dbgs() << format("error decoding address ranges = ",
+                           TheError.c_str());
+        });
+        consumeError(RangesOrError.takeError());
+        break;
+      }
+      // The address ranges are absolute. There is no need to add any addend.
+      DWARFAddressRangesVector Ranges = RangesOrError.get();
+      for (DWARFAddressRange &Range : Ranges) {
+        // This seems to be a tombstone for empty ranges.
+        if (Range.LowPC == Range.HighPC)
+          continue;
+        // Store the real upper limit for the address range.
+        if (UpdateHighAddress && Range.HighPC > 0)
+          --Range.HighPC;
+        // Add the pair of addresses.
+        CurrentScope->addObject(Range.LowPC, Range.HighPC);
+        // If the scope is the CU, do not update the ranges set.
+        if (!CurrentElement->isCompileUnit())
+          CurrentRanges.emplace_back(Range.LowPC, Range.HighPC);
+      }
+    }
+    break;
+
+  // Get the location list for the symbol.
+  case dwarf::DW_AT_data_member_location:
+    if (options().getAttributeAnyLocation())
+      processLocationMember(AttrSpec.Attr, FormValue, Die, OffsetOnEntry);
+    break;
+
+  // Get the location list for the symbol.
+  case dwarf::DW_AT_location:
+  case dwarf::DW_AT_string_length:
+  case dwarf::DW_AT_use_location:
+    if (options().getAttributeAnyLocation() && CurrentSymbol)
+      processLocationList(AttrSpec.Attr, FormValue, Die, OffsetOnEntry);
+    break;
+
+  case dwarf::DW_AT_call_data_value:
+  case dwarf::DW_AT_call_value:
+  case dwarf::DW_AT_GNU_call_site_data_value:
+  case dwarf::DW_AT_GNU_call_site_value:
+    if (options().getAttributeAnyLocation() && CurrentSymbol)
+      processLocationList(AttrSpec.Attr, FormValue, Die, OffsetOnEntry,
+                          /*CallSiteLocation=*/true);
+    break;
+
+  default:
+    break;
+  }
+}
+
+LVScope *LVELFReader::processOneDie(const DWARFDie &InputDIE, LVScope *Parent,
+                                    DWARFDie &SkeletonDie) {
+  // If the input DIE corresponds to the compile unit, it can be:
+  // a) Simple DWARF: a standard DIE. Ignore the skeleton DIE (is empty).
+  // b) Split DWARF: the DIE for the split DWARF. The skeleton is the DIE
+  //    for the skeleton DWARF. Process both DIEs.
+  const DWARFDie &DIE = SkeletonDie.isValid() ? SkeletonDie : InputDIE;
+  DWARFDataExtractor DebugInfoData =
+      DIE.getDwarfUnit()->getDebugInfoExtractor();
+  LVOffset Offset = DIE.getOffset();
+
+  // Reset values for the current DIE.
+  CurrentLowPC = 0;
+  CurrentHighPC = 0;
+  CurrentOffset = Offset;
+  CurrentEndOffset = 0;
+  FoundLowPC = false;
+  FoundHighPC = false;
+
+  // Process supported attributes.
+  if (DebugInfoData.isValidOffset(Offset)) {
+
+    LLVM_DEBUG({
+      dbgs() << "DIE: " << hexValue(Offset) << formatv(" {0}", DIE.getTag())
+             << "\n";
+    });
+
+    // Create the logical view element for the current DIE.
+    dwarf::Tag Tag = DIE.getTag();
+    CurrentElement = createElement(Tag);
+    if (!CurrentElement)
+      return CurrentScope;
+
+    CurrentElement->setTag(Tag);
+    CurrentElement->setOffset(Offset);
+
+    if (options().getAttributeAnySource() && CurrentElement->isCompileUnit())
+      addCompileUnitOffset(Offset,
+                           static_cast<LVScopeCompileUnit *>(CurrentElement));
+
+    // Insert the newly created element into the element symbol table. If the
+    // element is in the list, it means there are previously created elements
+    // referencing this element.
+    if (ElementTable.find(Offset) == ElementTable.end()) {
+      // No previous references to this offset.
+      ElementTable.emplace(
+          std::piecewise_construct, std::forward_as_tuple(Offset),
+          std::forward_as_tuple(CurrentElement, LVElementSet()));
+    } else {
+      // There are previous references to this element. We need to update the
+      // element and all the references pointing to this element.
+      LVElementEntry &Reference = ElementTable[Offset];
+      Reference.first = CurrentElement;
+      // Traverse the element set and update the elements (backtracking).
+      // Using the bit associated with 'type' or 'reference' allows us to set
+      // the correct target.
+      for (LVElement *Target : Reference.second)
+        Target->getHasReference() ? Target->setReference(CurrentElement)
+                                  : Target->setType(CurrentElement);
+      // Clear the pending elements.
+      Reference.second.clear();
+    }
+
+    // Add the current element to its parent as there are attributes
+    // (locations) that require the scope level.
+    if (CurrentScope)
+      Parent->addElement(CurrentScope);
+    else if (CurrentSymbol)
+      Parent->addElement(CurrentSymbol);
+    else if (CurrentType)
+      Parent->addElement(CurrentType);
+
+    // Process the attributes for the given DIE.
+    auto ProcessAttributes = [&](const DWARFDie &TheDIE,
+                                 DWARFDataExtractor &DebugData) {
+      CurrentEndOffset = Offset;
+      uint32_t abbrCode = DebugData.getULEB128(&CurrentEndOffset);
+      if (abbrCode) {
+        if (const DWARFAbbreviationDeclaration *AbbrevDecl =
+                TheDIE.getAbbreviationDeclarationPtr())
+          if (AbbrevDecl)
+            for (const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec :
+                 AbbrevDecl->attributes())
+              processOneAttribute(TheDIE, &CurrentEndOffset, AttrSpec);
+      }
+    };
+
+    ProcessAttributes(DIE, DebugInfoData);
+
+    // If the input DIE is for a compile unit, process its attributes in
+    // the case of split DWARF, to override any common attribute values.
+    if (SkeletonDie.isValid()) {
+      DWARFDataExtractor DebugInfoData =
+          InputDIE.getDwarfUnit()->getDebugInfoExtractor();
+      LVOffset Offset = InputDIE.getOffset();
+      if (DebugInfoData.isValidOffset(Offset))
+        ProcessAttributes(InputDIE, DebugInfoData);
+    }
+  }
+
+  if (CurrentScope) {
+    if (CurrentScope->getCanHaveRanges()) {
+      // If the scope has ranges, they are already added to the scope.
+      // Add any collected LowPC/HighPC values.
+      bool IsCompileUnit = CurrentScope->getIsCompileUnit();
+      if (FoundLowPC && FoundHighPC) {
+        CurrentScope->addObject(CurrentLowPC, CurrentHighPC);
+        if (!IsCompileUnit) {
+          // If the scope is a function, add it to the public names.
+          if ((options().getAttributePublics() ||
+               options().getPrintAnyLine()) &&
+              CurrentScope->getIsFunction() &&
+              !CurrentScope->getIsInlinedFunction())
+            CompileUnit->addPublicName(CurrentScope, CurrentLowPC,
+                                       CurrentHighPC);
+        }
+      }
+
+      // Look for scopes with ranges and no linkage name information that
+      // are referencing another scopes via DW_AT_specification. They are
+      // possible candidates for a comdat scope.
+      if (CurrentScope->getHasRanges() &&
+          !CurrentScope->getLinkageNameIndex() &&
+          CurrentScope->getHasReferenceSpecification()) {
+        // Get the linkage name in order to search for a possible comdat.
+        Optional<DWARFFormValue> LinkageDIE =
+            DIE.findRecursively(dwarf::DW_AT_linkage_name);
+        if (LinkageDIE.has_value()) {
+          StringRef Name(dwarf::toStringRef(LinkageDIE));
+          if (!Name.empty())
+            CurrentScope->setLinkageName(Name);
+        }
+      }
+
+      // If the current scope is in the 'LinkageNames' table, update its
+      // logical scope. For other scopes, always we will assume the default
+      // ".text" section index.
+      LVSectionIndex SectionIndex = updateSymbolTable(CurrentScope);
+      if (CurrentScope->getIsComdat())
+        CompileUnit->setHasComdatScopes();
+
+      // Update section index contained ranges.
+      if (SectionIndex) {
+        if (!CurrentRanges.empty()) {
+          for (LVAddressRange &Range : CurrentRanges)
+            addSectionRange(SectionIndex, CurrentScope, Range.first,
+                            Range.second);
+          CurrentRanges.clear();
+        }
+        // If the scope is the CU, do not update the ranges set.
+        if (FoundLowPC && FoundHighPC && !IsCompileUnit) {
+          addSectionRange(SectionIndex, CurrentScope, CurrentLowPC,
+                          CurrentHighPC);
+        }
+      }
+    }
+    // Mark member functions.
+    if (Parent->getIsAggregate())
+      CurrentScope->setIsMember();
+  }
+
+  // Keep track of symbols with locations.
+  if (options().getAttributeAnyLocation() && CurrentSymbol &&
+      CurrentSymbol->getHasLocation())
+    SymbolsWithLocations.push_back(CurrentSymbol);
+
+  // If we have template parameters, mark the parent as template.
+  if (CurrentType && CurrentType->getIsTemplateParam())
+    Parent->setIsTemplate();
+
+  return CurrentScope;
+}
+
+void LVELFReader::traverseDieAndChildren(DWARFDie &DIE, LVScope *Parent,
+                                         DWARFDie &SkeletonDie) {
+  // Process the current DIE.
+  LVScope *Scope = processOneDie(DIE, Parent, SkeletonDie);
+  if (Scope) {
+    LVOffset Lower = DIE.getOffset();
+    LVOffset Upper = CurrentEndOffset;
+    DWARFDie DummyDie;
+    // Traverse the children chain.
+    DWARFDie Child = DIE.getFirstChild();
+    while (Child) {
+      traverseDieAndChildren(Child, Scope, DummyDie);
+      Upper = Child.getOffset();
+      Child = Child.getSibling();
+    }
+    // Calculate contributions to the debug info section.
+    if (options().getPrintSizes() && Upper)
+      CompileUnit->addSize(Scope, Lower, Upper);
+  }
+}
+
+void LVELFReader::processLocationGaps() {
+  if (options().getAttributeAnyLocation())
+    for (LVSymbol *Symbol : SymbolsWithLocations)
+      Symbol->fillLocationGaps();
+}
+
+void LVELFReader::createLineAndFileRecords(
+    const DWARFDebugLine::LineTable *Lines) {
+  if (!Lines)
+    return;
+
+  // Get the source filenames.
+  if (!Lines->Prologue.FileNames.empty())
+    for (const DWARFDebugLine::FileNameEntry &Entry :
+         Lines->Prologue.FileNames) {
+      std::string Directory;
+      if (Lines->getDirectoryForEntry(Entry, Directory))
+        Directory = transformPath(Directory);
+      if (Directory.empty())
+        Directory = std::string(CompileUnit->getCompilationDirectory());
+      std::string File = transformPath(dwarf::toStringRef(Entry.Name));
+      std::string String;
+      raw_string_ostream(String) << Directory << "/" << File;
+      CompileUnit->addFilename(String);
+    }
+
+  // In DWARF5 the file indexes start at 0;
+  bool IncrementIndex = Lines->Prologue.getVersion() >= 5;
+
+  // Get the source lines.
+  if ((options().getAttributeRange() || options().getPrintLines()) &&
+      Lines->Rows.size())
+    for (const DWARFDebugLine::Row &Row : Lines->Rows) {
+      // Here we collect logical debug lines in CULines. Later on,
+      // the 'processLines()' function will move each created logical line
+      // to its enclosing logical scope, using the debug ranges information
+      // and they will be released when its scope parent is deleted.
+      LVLineDebug *Line = new LVLineDebug();
+      CULines.push_back(Line);
+      Line->setAddress(Row.Address.Address);
+      Line->setFilename(
+          CompileUnit->getFilename(IncrementIndex ? Row.File + 1 : Row.File));
+      Line->setLineNumber(Row.Line);
+      if (Row.Discriminator)
+        Line->setDiscriminator(Row.Discriminator);
+      if (Row.IsStmt)
+        Line->setIsNewStatement();
+      if (Row.BasicBlock)
+        Line->setIsBasicBlock();
+      if (Row.EndSequence)
+        Line->setIsEndSequence();
+      if (Row.EpilogueBegin)
+        Line->setIsEpilogueBegin();
+      if (Row.PrologueEnd)
+        Line->setIsPrologueEnd();
+      LLVM_DEBUG({
+        dbgs() << "Address: " << hexValue(Line->getAddress())
+               << " Line: " << Line->lineNumberAsString(/*ShowZero=*/true)
+               << "\n";
+      });
+    }
+}
+
+std::string LVELFReader::getRegisterName(LVSmall Opcode, uint64_t Operands[2]) {
+  // The 'prettyPrintRegisterOp' function uses the DWARFUnit to support
+  // DW_OP_regval_type. At this point we are operating on a logical view
+  // item, with no access to the underlying DWARF data used by LLVM.
+  // We do not support DW_OP_regval_type here.
+  if (Opcode == dwarf::DW_OP_regval_type)
+    return {};
+
+  std::string string;
+  raw_string_ostream Stream(string);
+  DIDumpOptions DumpOpts;
+  DWARFExpression::prettyPrintRegisterOp(/*U=*/nullptr, Stream, DumpOpts,
+                                         Opcode, Operands, MRI.get(),
+                                         /*isEH=*/false);
+  return Stream.str();
+}
+
+Error LVELFReader::createScopes() {
+  LLVM_DEBUG({
+    W.startLine() << "\n";
+    W.printString("File", Obj.getFileName().str());
+    W.printString("Format", FileFormatName);
+  });
+
+  if (Error Err = LVReader::createScopes())
+    return Err;
+
+  // As the DwarfContext object is valid only during the scopes creation,
+  // we need to create our own Target information, to be used during the
+  // logical view printing, in the case of instructions being requested.
+  std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(Obj);
+  if (!DwarfContext)
+    return createStringError(errc::invalid_argument,
+                             "Could not create DWARF information: %s",
+                             getFilename().str().c_str());
+
+  if (Error Err = loadTargetInfo(Obj))
+    return Err;
+
+  // Create a mapping for virtual addresses.
+  mapVirtualAddress(Obj);
+
+  // Select the correct compile unit range, depending if we are dealing with
+  // a standard or split DWARF object.
+  DWARFContext::compile_unit_range CompileUnits =
+      DwarfContext->getNumCompileUnits() ? DwarfContext->compile_units()
+                                         : DwarfContext->dwo_compile_units();
+  for (const std::unique_ptr<DWARFUnit> &CU : CompileUnits) {
+
+    // Deduction of index used for the line records.
+    //
+    // For the following test case: test.cpp
+    //  void foo(void ParamPtr) { }
+
+    // Both GCC and Clang generate DWARF-5 .debug_line layout.
+
+    // * GCC (GNU C++17 11.3.0) - All DW_AT_decl_file use index 1.
+    //
+    //   .debug_info:
+    //     format = DWARF32, version = 0x0005
+    //     DW_TAG_compile_unit
+    //       DW_AT_name	("test.cpp")
+    //       DW_TAG_subprogram ("foo")
+    //         DW_AT_decl_file (1)
+    //         DW_TAG_formal_parameter ("ParamPtr")
+    //           DW_AT_decl_file (1)
+    //   .debug_line:
+    //     Line table prologue: format (DWARF32), version (5)
+    //     include_directories[0] = "..."
+    //     file_names[0]: name ("test.cpp"), dir_index (0)
+    //     file_names[1]: name ("test.cpp"), dir_index (0)
+
+    // * Clang (14.0.6) - All DW_AT_decl_file use index 0.
+    //
+    //   .debug_info:
+    //     format = DWARF32, version = 0x0005
+    //     DW_AT_producer	("clang version 14.0.6")
+    //     DW_AT_name	("test.cpp")
+    //
+    //     DW_TAG_subprogram ("foo")
+    //       DW_AT_decl_file (0)
+    //       DW_TAG_formal_parameter ("ParamPtr")
+    //         DW_AT_decl_file (0)
+    //   .debug_line:
+    //     Line table prologue: format (DWARF32), version (5)
+    //     include_directories[0] = "..."
+    //     file_names[0]: name ("test.cpp"), dir_index (0)
+
+    // From DWARFDebugLine::getFileNameByIndex documentation:
+    //   In Dwarf 4, the files are 1-indexed.
+    //   In Dwarf 5, the files are 0-indexed.
+    // Additional discussions here:
+    // https://www.mail-archive.com/dwarf-discuss@lists.dwarfstd.org/msg00883.html
+
+    // The ELF Reader is expecting the files are 1-indexed, so using
+    // the .debug_line header information decide if the indexed require
+    // an internal adjustment.
+
+    // For the case of GCC (DWARF5), if the entries[0] and [1] are the
+    // same, do not perform any adjustment.
+    auto DeduceIncrementFileIndex = [&]() -> bool {
+      if (CU->getVersion() < 5)
+        // DWARF-4 or earlier -> Don't increment index.
+        return false;
+
+      if (const DWARFDebugLine::LineTable *LT =
+              CU->getContext().getLineTableForUnit(CU.get())) {
+        // Check if there are at least 2 entries and if they are the same.
+        if (LT->hasFileAtIndex(0) && LT->hasFileAtIndex(1)) {
+          const DWARFDebugLine::FileNameEntry &EntryZero =
+              LT->Prologue.getFileNameEntry(0);
+          const DWARFDebugLine::FileNameEntry &EntryOne =
+              LT->Prologue.getFileNameEntry(1);
+          // Check directory indexes.
+          if (EntryZero.DirIdx != EntryOne.DirIdx)
+            // DWARF-5 -> Increment index.
+            return true;
+          // Check filename.
+          std::string FileZero;
+          std::string FileOne;
+          StringRef None;
+          LT->getFileNameByIndex(
+              0, None, DILineInfoSpecifier::FileLineInfoKind::RawValue,
+              FileZero);
+          LT->getFileNameByIndex(
+              1, None, DILineInfoSpecifier::FileLineInfoKind::RawValue,
+              FileOne);
+          return FileZero.compare(FileOne);
+        }
+      }
+
+      // DWARF-5 -> Increment index.
+      return true;
+    };
+    // The ELF reader expects the indexes as 1-indexed.
+    IncrementFileIndex = DeduceIncrementFileIndex();
+
+    DWARFDie UnitDie = CU->getUnitDIE();
+    SmallString<16> DWOAlternativeLocation;
+    if (UnitDie) {
+      Optional<const char *> DWOFileName =
+          CU->getVersion() >= 5
+              ? dwarf::toString(UnitDie.find(dwarf::DW_AT_dwo_name))
+              : dwarf::toString(UnitDie.find(dwarf::DW_AT_GNU_dwo_name));
+      StringRef From(DWOFileName.has_value() ? DWOFileName.value() : "");
+      DWOAlternativeLocation = createAlternativePath(From);
+    }
+
+    // The current CU can be a normal compile unit (standard) or a skeleton
+    // compile unit (split). For both cases, the returned die, will be used
+    // to create the logical scopes.
+    DWARFDie CUDie = CU->getNonSkeletonUnitDIE(
+        /*ExtractUnitDIEOnly=*/false,
+        /*DWOAlternativeLocation=*/DWOAlternativeLocation);
+    if (!CUDie.isValid())
+      continue;
+
+    // The current unit corresponds to the .dwo file. We need to get the
+    // skeleton unit and query for any ranges that will enclose any ranges
+    // in the non-skeleton unit.
+    DWARFDie DummyDie;
+    DWARFDie SkeletonDie =
+        CUDie.getDwarfUnit()->isDWOUnit() ? CU->getUnitDIE(false) : DummyDie;
+    // Disable the ranges processing if we have just a single .dwo object,
+    // as any DW_AT_ranges will access not available range information.
+    RangesDataAvailable =
+        (!CUDie.getDwarfUnit()->isDWOUnit() ||
+         (SkeletonDie.isValid() ? !SkeletonDie.getDwarfUnit()->isDWOUnit()
+                                : true));
+
+    traverseDieAndChildren(CUDie, Root, SkeletonDie);
+
+    createLineAndFileRecords(DwarfContext->getLineTableForUnit(CU.get()));
+    if (Error Err = createInstructions())
+      return Err;
+
+    // Process the compilation unit, as there are cases where enclosed
+    // functions have the same ranges values. Insert the compilation unit
+    // ranges at the end, to allow enclosing ranges to be first in the list.
+    LVSectionIndex SectionIndex = getSectionIndex(CompileUnit);
+    addSectionRange(SectionIndex, CompileUnit);
+    LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);
+    ScopesWithRanges->sort();
+
+    processLines(&CULines, SectionIndex);
+    processLocationGaps();
+
+    // These are per compile unit.
+    ScopesWithRanges->clear();
+    SymbolsWithLocations.clear();
+    CULines.clear();
+  }
+
+  return Error::success();
+}
+
+// Get the location information for the associated attribute.
+void LVELFReader::processLocationList(dwarf::Attribute Attr,
+                                      const DWARFFormValue &FormValue,
+                                      const DWARFDie &Die,
+                                      uint64_t OffsetOnEntry,
+                                      bool CallSiteLocation) {
+
+  auto ProcessLocationExpression = [&](const DWARFExpression &Expression) {
+    // DW_OP_const_type is variable-length and has 3
+    // operands. DWARFExpression thus far only supports 2.
+    uint64_t Operands[2] = {0};
+    for (const DWARFExpression::Operation &Op : Expression) {
+      DWARFExpression::Operation::Description Description = Op.getDescription();
+      for (unsigned Operand = 0; Operand < 2; ++Operand) {
+        if (Description.Op[Operand] == DWARFExpression::Operation::SizeNA)
+          break;
+        Operands[Operand] = Op.getRawOperand(Operand);
+      }
+      CurrentSymbol->addLocationOperands(Op.getCode(), Operands[0],
+                                         Operands[1]);
+    }
+  };
+
+  DWARFUnit *U = Die.getDwarfUnit();
+  DWARFContext &DwarfContext = U->getContext();
+  bool IsLittleEndian = DwarfContext.isLittleEndian();
+  if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||
+      (DWARFAttribute::mayHaveLocationExpr(Attr) &&
+       FormValue.isFormClass(DWARFFormValue::FC_Exprloc))) {
+    ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+    DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
+                       IsLittleEndian, 0);
+    DWARFExpression Expression(Data, U->getAddressByteSize(),
+                               U->getFormParams().Format);
+
+    // Add location and operation entries.
+    CurrentSymbol->addLocation(Attr, /*LowPC=*/0, /*HighPC=*/-1,
+                               /*SectionOffset=*/0, OffsetOnEntry,
+                               CallSiteLocation);
+    ProcessLocationExpression(Expression);
+    return;
+  }
+
+  if (DWARFAttribute::mayHaveLocationList(Attr) &&
+      FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {
+    uint64_t Offset = *FormValue.getAsSectionOffset();
+    if (FormValue.getForm() == dwarf::DW_FORM_loclistx) {
+      Optional<uint64_t> LoclistOffset = U->getLoclistOffset(Offset);
+      if (!LoclistOffset)
+        return;
+      Offset = *LoclistOffset;
+    }
+    uint64_t BaseAddr = 0;
+    if (Optional<SectionedAddress> BA = U->getBaseAddress())
+      BaseAddr = BA->Address;
+    LVAddress LowPC = 0;
+    LVAddress HighPC = 0;
+
+    auto ProcessLocationEntry = [&](const DWARFLocationEntry &Entry) {
+      if (Entry.Kind == dwarf::DW_LLE_base_address) {
+        BaseAddr = Entry.Value0;
+        return;
+      }
+      if (Entry.Kind == dwarf::DW_LLE_offset_pair) {
+        LowPC = BaseAddr + Entry.Value0;
+        HighPC = BaseAddr + Entry.Value1;
+        DWARFAddressRange Range{LowPC, HighPC, Entry.SectionIndex};
+        if (Range.SectionIndex == SectionedAddress::UndefSection)
+          Range.SectionIndex = Entry.SectionIndex;
+        DWARFLocationExpression Loc{Range, Entry.Loc};
+        DWARFDataExtractor Data(Loc.Expr, IsLittleEndian,
+                                U->getAddressByteSize());
+        DWARFExpression Expression(Data, U->getAddressByteSize());
+
+        // Store the real upper limit for the address range.
+        if (UpdateHighAddress && HighPC > 0)
+          --HighPC;
+        // Add location and operation entries.
+        CurrentSymbol->addLocation(Attr, LowPC, HighPC, Offset, OffsetOnEntry,
+                                   CallSiteLocation);
+        ProcessLocationExpression(Expression);
+      }
+    };
+    Error E = U->getLocationTable().visitLocationList(
+        &Offset, [&](const DWARFLocationEntry &E) {
+          ProcessLocationEntry(E);
+          return true;
+        });
+    if (E)
+      consumeError(std::move(E));
+  }
+}
+
+void LVELFReader::processLocationMember(dwarf::Attribute Attr,
+                                        const DWARFFormValue &FormValue,
+                                        const DWARFDie &Die,
+                                        uint64_t OffsetOnEntry) {
+  // Check if the value is an integer constant.
+  if (FormValue.isFormClass(DWARFFormValue::FC_Constant))
+    // Add a record to hold a constant as location.
+    CurrentSymbol->addLocationConstant(Attr, *FormValue.getAsUnsignedConstant(),
+                                       OffsetOnEntry);
+  else
+    // This is a a location description, or a reference to one.
+    processLocationList(Attr, FormValue, Die, OffsetOnEntry);
+}
+
+// Update the current element with the reference.
+void LVELFReader::updateReference(dwarf::Attribute Attr,
+                                  const DWARFFormValue &FormValue) {
+  // We are assuming that DW_AT_specification, DW_AT_abstract_origin,
+  // DW_AT_type and DW_AT_extension do not appear at the same time
+  // in the same DIE.
+  uint64_t Reference = *FormValue.getAsReference();
+  // Get target for the given reference, if already created.
+  LVElement *Target = getElementForOffset(Reference, CurrentElement);
+  // Check if we are dealing with cross CU references.
+  if (FormValue.getForm() == dwarf::DW_FORM_ref_addr) {
+    if (Target) {
+      // The global reference is ready. Mark it as global.
+      Target->setIsGlobalReference();
+      // Remove global reference from the unseen list.
+      removeGlobalOffset(Reference);
+    } else
+      // Record the unseen cross CU reference.
+      addGlobalOffset(Reference);
+  }
+
+  // At this point, 'Target' can be null, in the case of the target element
+  // not being seen. But the correct bit is set, to indicate that the target
+  // is being referenced by (abstract_origin, extension, specification) or
+  // (import, type).
+  // We must 
diff erentiate between the kind of reference. This is needed to
+  // complete inlined function instances with dropped abstract references,
+  // in order to facilitate a logical comparison.
+  switch (Attr) {
+  case dwarf::DW_AT_abstract_origin:
+  case dwarf::DW_AT_call_origin:
+    CurrentElement->setReference(Target);
+    CurrentElement->setHasReferenceAbstract();
+    break;
+  case dwarf::DW_AT_extension:
+    CurrentElement->setReference(Target);
+    CurrentElement->setHasReferenceExtension();
+    break;
+  case dwarf::DW_AT_specification:
+    CurrentElement->setReference(Target);
+    CurrentElement->setHasReferenceSpecification();
+    break;
+  case dwarf::DW_AT_import:
+  case dwarf::DW_AT_type:
+    CurrentElement->setType(Target);
+    break;
+  default:
+    break;
+  }
+}
+
+// Get an element given the DIE offset.
+LVElement *LVELFReader::getElementForOffset(LVOffset Offset,
+                                            LVElement *Element) {
+  LVElement *Target = nullptr;
+  // Search offset in the cross references.
+  LVElementReference::iterator Iter = ElementTable.find(Offset);
+  if (Iter == ElementTable.end())
+    // Reference to an unseen element.
+    ElementTable.emplace(std::piecewise_construct,
+                         std::forward_as_tuple(Offset),
+                         std::forward_as_tuple(nullptr, LVElementSet{Element}));
+  else {
+    // There are previous references to this element. We need to update the
+    // element and all the references pointing to this element.
+    LVElementEntry &Reference = Iter->second;
+    Target = Reference.first;
+    if (!Target)
+      // Add the element to the set.
+      Reference.second.insert(Element);
+  }
+  return Target;
+}
+
+Error LVELFReader::loadTargetInfo(const ObjectFile &Obj) {
+  // Detect the architecture from the object file. We usually don't need OS
+  // info to lookup a target and create register info.
+  Triple TT;
+  TT.setArch(Triple::ArchType(Obj.getArch()));
+  TT.setVendor(Triple::UnknownVendor);
+  TT.setOS(Triple::UnknownOS);
+
+  // Features to be passed to target/subtarget
+  SubtargetFeatures Features = Obj.getFeatures();
+
+  return loadGenericTargetInfo(TT.str(), Features.getString());
+}
+
+void LVELFReader::mapRangeAddress(const ObjectFile &Obj) {
+  for (auto Iter = Obj.symbol_begin(); Iter != Obj.symbol_end(); ++Iter) {
+    const SymbolRef &Symbol = *Iter;
+
+    Expected<SymbolRef::Type> TypeOrErr = Symbol.getType();
+    if (!TypeOrErr) {
+      consumeError(TypeOrErr.takeError());
+      continue;
+    }
+
+    // Process only symbols that represent a function.
+    SymbolRef::Type Type = *TypeOrErr;
+    if (Type != SymbolRef::ST_Function)
+      continue;
+
+    // In the case of a Mach-O STAB symbol, get its section only if
+    // the STAB symbol's section field refers to a valid section index.
+    // Otherwise the symbol may error trying to load a section that
+    // does not exist.
+    const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&Obj);
+    bool IsSTAB = false;
+    if (MachO) {
+      DataRefImpl SymDRI = Symbol.getRawDataRefImpl();
+      uint8_t NType =
+          (MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type
+                            : MachO->getSymbolTableEntry(SymDRI).n_type);
+      if (NType & MachO::N_STAB)
+        IsSTAB = true;
+    }
+
+    Expected<section_iterator> IterOrErr = Symbol.getSection();
+    if (!IterOrErr) {
+      consumeError(IterOrErr.takeError());
+      continue;
+    }
+    section_iterator Section = IsSTAB ? Obj.section_end() : *IterOrErr;
+    if (Section == Obj.section_end())
+      continue;
+
+    // Get the symbol value.
+    Expected<uint64_t> AddressOrErr = Symbol.getAddress();
+    if (!AddressOrErr) {
+      consumeError(AddressOrErr.takeError());
+      continue;
+    }
+    uint64_t Address = *AddressOrErr;
+
+    // Get symbol name.
+    StringRef Name;
+    Expected<StringRef> NameOrErr = Symbol.getName();
+    if (!NameOrErr) {
+      consumeError(NameOrErr.takeError());
+      continue;
+    }
+    Name = *NameOrErr;
+
+    // Check if the symbol is Comdat.
+    Expected<uint32_t> FlagsOrErr = Symbol.getFlags();
+    if (!FlagsOrErr) {
+      consumeError(FlagsOrErr.takeError());
+      continue;
+    }
+    uint32_t Flags = *FlagsOrErr;
+
+    // Mark the symbol as 'comdat' in any of the following cases:
+    // - Symbol has the SF_Weak flag or
+    // - Symbol section index 
diff erent from the DotTextSectionIndex.
+    LVSectionIndex SectionIndex = Section->getIndex();
+    bool IsComdat =
+        (Flags & SymbolRef::SF_Weak) || (SectionIndex != DotTextSectionIndex);
+
+    // Record the symbol name (linkage) and its loading address.
+    addToSymbolTable(Name, Address, SectionIndex, IsComdat);
+  }
+}
+
+void LVELFReader::sortScopes() { Root->sort(); }
+
+void LVELFReader::print(raw_ostream &OS) const {
+  OS << "LVType\n";
+  LLVM_DEBUG(dbgs() << "CreateReaders\n");
+}

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test
new file mode 100644
index 0000000000000..532d11054a8a3
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-compare-logical-elements.test
@@ -0,0 +1,101 @@
+; Test case 1 - General options
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Compare mode - Logical view.
+; The output shows in view form the 'missing (-), added (+)' elements,
+; giving more context by swapping the reference and target object files.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=view \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/test-dwarf-clang.o \
+; RUN:                         %p/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Reference: 'test-dwarf-clang.o'
+; ONE-NEXT: Target:    'test-dwarf-gcc.o'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT:  [000]           {File} 'test-dwarf-clang.o'
+; ONE-EMPTY:
+; ONE-NEXT:  [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; ONE-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT:  [003]                 {Block}
+; ONE-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+; Compare mode - Logical elements.
+; The output shows in tabular form the 'missing (-), added (+)' elements,
+; giving more context by swapping the reference and target object files.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/Inputs/test-dwarf-clang.o \
+; RUN:                         %p/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Reference: 'test-dwarf-clang.o'
+; TWO-NEXT: Target:    'test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Missing Types:
+; TWO-NEXT: -[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Added Types:
+; TWO-NEXT: +[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Element   Expected    Missing      Added
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Scopes           4          0          0
+; TWO-NEXT: Symbols          0          0          0
+; TWO-NEXT: Types            2          1          1
+; TWO-NEXT: Lines            0          0          0
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Total            6          1          1
+
+; Changing the 'Reference' and 'Target' order:
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/Inputs/test-dwarf-gcc.o \
+; RUN:                         %p/Inputs/test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THR %s
+
+; THR:      Reference: 'test-dwarf-gcc.o'
+; THR-NEXT: Target:    'test-dwarf-clang.o'
+; THR-EMPTY:
+; THR-NEXT: (1) Missing Types:
+; THR-NEXT: -[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; THR-EMPTY:
+; THR-NEXT: (1) Added Types:
+; THR-NEXT: +[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; THR-EMPTY:
+; THR-NEXT: ----------------------------------------
+; THR-NEXT: Element   Expected    Missing      Added
+; THR-NEXT: ----------------------------------------
+; THR-NEXT: Scopes           4          0          0
+; THR-NEXT: Symbols          0          0          0
+; THR-NEXT: Types            2          1          1
+; THR-NEXT: Lines            0          0          0
+; THR-NEXT: ----------------------------------------
+; THR-NEXT: Total            6          1          1

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test
new file mode 100644
index 0000000000000..9b38a527e8a5c
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-print-basic-details.test
@@ -0,0 +1,67 @@
+; Test case 1 - General options.
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Print basic details.
+; The following command prints basic details for all the logical elements
+; sorted by the debug information internal offset; it includes its lexical
+; level and debug info format.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=scopes,symbols,types,lines,instructions \
+; RUN:                         %p/Inputs/test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=offset \
+; RUN:                         --print=elements \
+; RUN:                         %p/Inputs/test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'test-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: [004]     5             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	$0x7, -0x1c(%rbp)'
+; ONE-NEXT: [004]     6             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	$0x7, -0x4(%rbp)'
+; ONE-NEXT: [004]                   {Code} 'jmp	0x6'
+; ONE-NEXT: [004]     8             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	-0x14(%rbp), %eax'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'movb	%dl, %al'
+; ONE-NEXT: [003]                 {Code} 'movq	%rdi, -0x10(%rbp)'
+; ONE-NEXT: [003]                 {Code} 'movl	%esi, -0x14(%rbp)'
+; ONE-NEXT: [003]                 {Code} 'andb	$0x1, %al'
+; ONE-NEXT: [003]                 {Code} 'movb	%al, -0x15(%rbp)'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'testb	$0x1, -0x15(%rbp)'
+; ONE-NEXT: [003]                 {Code} 'je	0x13'
+; ONE-NEXT: [003]     8           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	%eax, -0x4(%rbp)'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [003]     9           {Line}
+; ONE-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test
new file mode 100644
index 0000000000000..55584b89fec41
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/01-dwarf-select-logical-elements.test
@@ -0,0 +1,71 @@
+; Test case 1 - General options
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Select logical elements.
+; The following prints all 'instructions', 'symbols' and 'types' that
+; contain 'inte' or 'movl' in their names or types, using a tab layout
+; and given the number of matches.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select-nocase --select-regex \
+; RUN:                         --select=INTe --select=movl \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,instructions,summary \
+; RUN:                         %p/Inputs/test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'test-dwarf-clang.o'
+; ONE-EMPTY:
+; ONE-NEXT: [001]           {CompileUnit} 'test.cpp'
+; ONE-NEXT: [004]           {Code} 'movl	$0x7, -0x1c(%rbp)'
+; ONE-NEXT: [004]           {Code} 'movl	$0x7, -0x4(%rbp)'
+; ONE-NEXT: [003]           {Code} 'movl	%eax, -0x4(%rbp)'
+; ONE-NEXT: [003]           {Code} 'movl	%esi, -0x14(%rbp)'
+; ONE-NEXT: [004]           {Code} 'movl	-0x14(%rbp), %eax'
+; ONE-NEXT: [003]           {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-EMPTY:
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Element      Total    Printed
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Scopes           3          0
+; ONE-NEXT: Symbols          4          1
+; ONE-NEXT: Types            2          1
+; ONE-NEXT: Lines           17          6
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Total           26          8
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --select-regex --select-nocase \
+; RUN:                         --select=INTe \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/test-dwarf-clang.o \
+; RUN:                         %p/Inputs/test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'test-dwarf-clang.o'
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'test.cpp'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'test.cpp'
+; TWO-NEXT: [004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'CONSTANT' -> 'const INTEGER'

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test
new file mode 100644
index 0000000000000..e925ad7c4b07e
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/02-dwarf-logical-lines.test
@@ -0,0 +1,63 @@
+; Test case 2 - Assembler instructions.
+
+; hello-world.cpp
+;  1  extern int printf(const char * format, ... );
+;  2
+;  3  int main()
+;  4  {
+;  5    printf("Hello, World\n");
+;  6    return 0;
+;  7  }
+
+; Logical lines.
+; The logical views shows the intermixed lines and assembler instructions,
+; allowing to compare the code generated by the 
diff erent toolchains.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --print=lines,instructions \
+; RUN:                         %p/Inputs/hello-world-dwarf-clang.o \
+; RUN:                         %p/Inputs/hello-world-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'hello-world-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'subq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'movl	$0x0, -0x4(%rbp)'
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]                 {Code} 'leaq	(%rip), %rdi'
+; ONE-NEXT: [003]                 {Code} 'movb	$0x0, %al'
+; ONE-NEXT: [003]                 {Code} 'callq	0x0'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'xorl	%eax, %eax'
+; ONE-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'hello-world-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'hello-world.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'main' -> 'int'
+; ONE-NEXT: [003]     4           {Line}
+; ONE-NEXT: [003]                 {Code} 'endbr64'
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]                 {Code} 'leaq	(%rip), %rdi'
+; ONE-NEXT: [003]                 {Code} 'movl	$0x0, %eax'
+; ONE-NEXT: [003]                 {Code} 'callq	0x0'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	$0x0, %eax'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [003]     7           {Line}

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test
new file mode 100644
index 0000000000000..0abacc0ccae27
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/03-dwarf-incorrect-lexical-scope-typedef.test
@@ -0,0 +1,124 @@
+; Test case 3 - Incorrect lexical scope for typedef.
+
+; pr-44884.cpp
+;  1  int bar(float Input) { return (int)Input; }
+;  2
+;  3  unsigned foo(char Param) {
+;  4    typedef int INT;                // ** Definition for INT **
+;  5    INT Value = Param;
+;  6    {
+;  7      typedef float FLOAT;          // ** Definition for FLOAT **
+;  8      {
+;  9        FLOAT Added = Value + Param;
+; 10        Value = bar(Added);
+; 11      }
+; 12    }
+; 13    return Value + Param;
+; 14  }
+
+; The lines 4 and 7 contains 2 typedefs, defined at 
diff erent lexical
+; scopes.
+
+; The above test is used to illustrates a scope issue found in the
+; Clang compiler.
+; PR44884: https://bugs.llvm.org/show_bug.cgi?id=44884
+; PR44229: https://github.com/llvm/llvm-project/issues/44229
+
+; In the following logical views, we can see that the Clang compiler
+; emits both typedefs at the same lexical scope (3), which is wrong.
+; GCC emit correct lexical scope for both typedefs.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=kind \
+; RUN:                         --print=symbols,types,lines \
+; RUN:                         %p/Inputs/pr-44884-dwarf-clang.o \
+; RUN:                         %p/Inputs/pr-44884-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-44884-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'foo' -> 'unsigned int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     9             {Variable} 'Added' -> 'FLOAT'
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]     9             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    10             {Line}
+; ONE-NEXT: [004]    13             {Line}
+; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
+; ONE-NEXT: [003]     7           {TypeAlias} 'FLOAT' -> 'float'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
+; ONE-NEXT: [003]     5           {Variable} 'Value' -> 'INT'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-44884.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     1         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     1           {Parameter} 'Input' -> 'float'
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [003]     1           {Line}
+; ONE-NEXT: [002]     3         {Function} extern not_inlined 'foo' -> 'unsigned int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]     9               {Variable} 'Added' -> 'FLOAT'
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]     9               {Line}
+; ONE-NEXT: [005]    10               {Line}
+; ONE-NEXT: [005]    13               {Line}
+; ONE-NEXT: [004]     7             {TypeAlias} 'FLOAT' -> 'float'
+; ONE-NEXT: [003]     3           {Parameter} 'Param' -> 'char'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INT' -> 'int'
+; ONE-NEXT: [003]     5           {Variable} 'Value' -> 'INT'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]     5           {Line}
+; ONE-NEXT: [003]    13           {Line}
+; ONE-NEXT: [003]    14           {Line}
+; ONE-NEXT: [003]    14           {Line}
+
+; Using the selection facilities, we can produce a simple tabular
+; output showing just the logical types that are 'Typedef'.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Typedef \
+; RUN:                         --report=list \
+; RUN:                         --print=types \
+; RUN:                         %p/Inputs/pr-44884-*.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-44884-dwarf-clang.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
+; TWO-NEXT: [003]     7     {TypeAlias} 'FLOAT' -> 'float'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-44884-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-44884.cpp'
+; TWO-NEXT: [004]     7     {TypeAlias} 'FLOAT' -> 'float'
+; TWO-NEXT: [003]     4     {TypeAlias} 'INT' -> 'int'

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test
new file mode 100644
index 0000000000000..e86035c9e771e
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/04-dwarf-missing-nested-enumerators.test
@@ -0,0 +1,123 @@
+; Test case 4 - Missing nested enumerations.
+
+; pr-46466.cpp
+;   1  struct Struct {
+;   2    union Union {
+;   3      enum NestedEnum { RED, BLUE };
+;   4    };
+;   5    Union U;
+;   6  };
+;   7
+;   8  Struct S;
+;   9  int test() {
+;  10    return S.U.BLUE;
+;  11  }
+
+; The above test is used to illustrate a scope issue found in the Clang
+; compiler.
+; PR46466: https://bugs.llvm.org/show_bug.cgi?id=46466
+; PR45811: https://github.com/llvm/llvm-project/issues/45811
+
+; In the following logical views, we can see that the DWARF debug
+; information generated by the Clang compiler does not include any
+; references to the enumerators 'RED' and 'BLUE'. The DWARF generated
+; by GCC, does include such references.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/pr-46466-dwarf-clang.o \
+; RUN:                         %p/Inputs/pr-46466-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
+; ONE-NEXT: [002]     1         {Struct} 'Struct'
+; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     8         {Variable} extern 'S' -> 'Struct'
+; ONE-NEXT: [002]     1         {Struct} 'Struct'
+; ONE-NEXT: [003]     5           {Member} public 'U' -> 'Union'
+; ONE-NEXT: [003]     2           {Union} 'Union'
+; ONE-NEXT: [004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
+; ONE-NEXT: [005]                     {Enumerator} 'BLUE' = '0x1'
+; ONE-NEXT: [005]                     {Enumerator} 'RED' = '0x0'
+
+; Using the selection facilities, we can produce a logical view
+; showing just the logical types that are 'Enumerator' and its
+; parents. The logical view is sorted by the types name.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Enumerator \
+; RUN:                         --report=parents \
+; RUN:                         --print=types \
+; RUN:                         %p/Inputs/pr-46466-*.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-46466.cpp'
+; TWO-NEXT: [002]     1         {Struct} 'Struct'
+; TWO-NEXT: [003]     2           {Union} 'Union'
+; TWO-NEXT: [004]     3             {Enumeration} 'NestedEnum' -> 'unsigned int'
+; TWO-NEXT: [005]                     {Enumerator} 'BLUE' = '0x1'
+; TWO-NEXT: [005]                     {Enumerator} 'RED' = '0x0'
+
+; Using the selection facilities, we can produce a simple tabular output
+; including a summary for the logical types that are 'Enumerator'. The
+; logical view is sorted by the types name.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-types=Enumerator \
+; RUN:                         --print=types,summary \
+; RUN:                         %p/Inputs/pr-46466-*.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THR %s
+
+; THR:      Logical View:
+; THR-NEXT: [000]           {File} 'pr-46466-dwarf-clang.o' -> elf64-x86-64
+; THR-EMPTY:
+; THR-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THR-EMPTY:
+; THR-NEXT: -----------------------------
+; THR-NEXT: Element      Total    Printed
+; THR-NEXT: -----------------------------
+; THR-NEXT: Scopes           4          0
+; THR-NEXT: Symbols          0          0
+; THR-NEXT: Types            0          0
+; THR-NEXT: Lines            0          0
+; THR-NEXT: -----------------------------
+; THR-NEXT: Total            4          0
+; THR-EMPTY:
+; THR-NEXT: Logical View:
+; THR-NEXT: [000]           {File} 'pr-46466-dwarf-gcc.o' -> elf64-x86-64
+; THR-EMPTY:
+; THR-NEXT: [001]           {CompileUnit} 'pr-46466.cpp'
+; THR-NEXT: [005]           {Enumerator} 'BLUE' = '0x1'
+; THR-NEXT: [005]           {Enumerator} 'RED' = '0x0'
+; THR-EMPTY:
+; THR-NEXT: -----------------------------
+; THR-NEXT: Element      Total    Printed
+; THR-NEXT: -----------------------------
+; THR-NEXT: Scopes           5          0
+; THR-NEXT: Symbols          0          0
+; THR-NEXT: Types            2          2
+; THR-NEXT: Lines            0          0
+; THR-NEXT: -----------------------------
+; THR-NEXT: Total            7          2

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
new file mode 100644
index 0000000000000..372a8ac8de8b7
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/05-dwarf-incorrect-lexical-scope-variable.test
@@ -0,0 +1,108 @@
+; Test case 5 - Incorrect lexical scope variable.
+
+; pr-43860.cpp
+;  1  #include "definitions.h"
+;  2  forceinline int InlineFunction(int Param) {
+;  3    int Var_1 = Param;
+;  4    {
+;  5      int Var_2 = Param + Var_1;
+;  6      Var_1 = Var_2;
+;  7    }
+;  8    return Var_1;
+;  9  }
+; 10
+; 11  int test(int Param_1, int Param_2) {
+; 12    int A = Param_1;
+; 13    A += InlineFunction(Param_2);
+; 14    return A;
+; 15  }
+
+; The above test is used to illustrate a variable issue found in the
+; Clang compiler.
+; PR43860: https://bugs.llvm.org/show_bug.cgi?id=43860
+; PR43205: https://github.com/llvm/llvm-project/issues/43205
+
+; In the following logical views, we can see that the DWARF debug
+; information generated by the Clang compiler shows the variables
+; 'Var_1' and 'Var_2' are at the same lexical scope (4) in the function
+; 'InlineFuction'.
+; The DWARF generated by GCC/Clang show those variables at the correct
+; lexical scope: '3' and '4' respectively.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --output-sort=name \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/pr-43860-dwarf-clang.o \
+; RUN:                         %p/Inputs/pr-43860-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-43860-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
+; ONE-NEXT: [003]    14           {InlinedFunction} not_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [004]                   {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_2' -> 'int'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT: [000]           {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-43860.cpp'
+; ONE-NEXT: [002]               {Producer} 'GNU C++14 10.3.0 {{.*}}'
+; ONE-NEXT: [002]     2         {Function} extern declared_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [003]     2           {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [003]     3           {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [002]    11         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]    12           {Variable} 'A' -> 'int'
+; ONE-NEXT: [003]    13           {InlinedFunction} declared_inlined 'InlineFunction' -> 'int'
+; ONE-NEXT: [004]                   {Block}
+; ONE-NEXT: [005]                     {Variable} 'Var_2' -> 'int'
+; ONE-NEXT: [004]                   {Parameter} 'Param' -> 'int'
+; ONE-NEXT: [004]                   {Variable} 'Var_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_1' -> 'int'
+; ONE-NEXT: [003]    11           {Parameter} 'Param_2' -> 'int'
+
+; Using the selection facilities, we can produce a simple tabular output
+; showing just the logical elements that have in their name the 'var'
+; pattern. The logical view is sorted by the variables name.
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format \
+; RUN:                         --output-sort=name \
+; RUN:                         --select-regex --select-nocase \
+; RUN:                         --select=Var \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols \
+; RUN:                         %p/Inputs/pr-43860-*.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-43860-dwarf-clang.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
+; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [003]     3     {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [005]           {Variable} 'Var_2' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'Var_2' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: Logical View:
+; TWO-NEXT: [000]           {File} 'pr-43860-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]           {CompileUnit} 'pr-43860.cpp'
+; TWO-NEXT: [004]           {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [003]     3     {Variable} 'Var_1' -> 'int'
+; TWO-NEXT: [005]           {Variable} 'Var_2' -> 'int'
+; TWO-NEXT: [004]     5     {Variable} 'Var_2' -> 'int'

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test
new file mode 100644
index 0000000000000..089726fab02fd
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/06-dwarf-full-logical-view.test
@@ -0,0 +1,105 @@
+; Test case 6 - Full logical view
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; Print low level details.
+; The following command prints low level information that includes
+; offsets within the debug information section, debug location
+; operands, linkage names, etc.
+
+; RUN: llvm-debuginfo-analyzer --attribute=all \
+; RUN:                         --print=all \
+; RUN:                         %p/Inputs/test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [0x0000000000][000]            {File} '{{.*}}test-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [0x000000000b][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT: [0x000000000b][002]                {Producer} 'clang version 15.0.0 {{.*}}'
+; ONE-NEXT:                                    {Directory} '/data/projects/tests/input/general'
+; ONE-NEXT:                                    {File} 'test.cpp'
+; ONE-NEXT:                                    {Public} 'foo' [0x0000000000:0x000000003a]
+; ONE-NEXT: [0x000000000b][002]                {Range} Lines 2:9 [0x0000000000:0x000000003a]
+; ONE-NEXT: [0x00000000bc][002]                {BaseType} 'bool'
+; ONE-NEXT: [0x0000000099][002]                {BaseType} 'int'
+; ONE-NEXT: [0x00000000b5][002]                {BaseType} 'unsigned int'
+; ONE-EMPTY:
+; ONE-NEXT: [0x00000000a0][002]   {Source} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x00000000a0][002]      1         {TypeAlias} 'INTPTR' -> [0x00000000ab]'* const int'
+; ONE-NEXT: [0x000000002a][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000099]'int'
+; ONE-NEXT: [0x000000002a][003]                  {Range} Lines 2:9 [0x0000000000:0x000000003a]
+; ONE-NEXT: [0x000000002a][003]                  {Linkage}  0x2 '_Z3fooPKijb'
+; ONE-NEXT: [0x0000000071][003]                  {Block}
+; ONE-NEXT: [0x0000000071][004]                    {Range} Lines 5:8 [0x000000001c:0x000000002f]
+; ONE-NEXT: [0x000000007e][004]      5             {Variable} 'CONSTANT' -> [0x00000000c3]'const INTEGER'
+; ONE-NEXT: [0x000000007e][005]                      {Coverage} 100.00%
+; ONE-NEXT: [0x000000007f][005]                      {Location}
+; ONE-NEXT: [0x000000007f][006]                        {Entry} fbreg -28
+; ONE-NEXT: [0x000000001c][004]      5             {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x000000001c][004]                    {Code} 'movl	$0x7, -0x1c(%rbp)'
+; ONE-NEXT: [0x0000000023][004]      6             {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x0000000023][004]                    {Code} 'movl	$0x7, -0x4(%rbp)'
+; ONE-NEXT: [0x000000002a][004]                    {Code} 'jmp	0x6'
+; ONE-NEXT: [0x000000002f][004]      8             {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x000000002f][004]                    {Code} 'movl	-0x14(%rbp), %eax'
+; ONE-NEXT: [0x0000000063][003]      2           {Parameter} 'ParamBool' -> [0x00000000bc]'bool'
+; ONE-NEXT: [0x0000000063][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000064][004]                    {Location}
+; ONE-NEXT: [0x0000000064][005]                      {Entry} fbreg -21
+; ONE-NEXT: [0x0000000047][003]      2           {Parameter} 'ParamPtr' -> [0x00000000a0]'INTPTR'
+; ONE-NEXT: [0x0000000047][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000048][004]                    {Location}
+; ONE-NEXT: [0x0000000048][005]                      {Entry} fbreg -16
+; ONE-NEXT: [0x0000000055][003]      2           {Parameter} 'ParamUnsigned' -> [0x00000000b5]'unsigned int'
+; ONE-NEXT: [0x0000000055][004]                    {Coverage} 100.00%
+; ONE-NEXT: [0x0000000056][004]                    {Location}
+; ONE-NEXT: [0x0000000056][005]                      {Entry} fbreg -20
+; ONE-NEXT: [0x000000008d][003]      4           {TypeAlias} 'INTEGER' -> [0x0000000099]'int'
+; ONE-NEXT: [0x0000000000][003]      2           {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x0000000000][003]                  {Code} 'pushq	%rbp'
+; ONE-NEXT: [0x0000000001][003]                  {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [0x0000000004][003]                  {Code} 'movb	%dl, %al'
+; ONE-NEXT: [0x0000000006][003]                  {Code} 'movq	%rdi, -0x10(%rbp)'
+; ONE-NEXT: [0x000000000a][003]                  {Code} 'movl	%esi, -0x14(%rbp)'
+; ONE-NEXT: [0x000000000d][003]                  {Code} 'andb	$0x1, %al'
+; ONE-NEXT: [0x000000000f][003]                  {Code} 'movb	%al, -0x15(%rbp)'
+; ONE-NEXT: [0x0000000012][003]      3           {Line} {NewStatement} {PrologueEnd} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x0000000012][003]                  {Code} 'testb	$0x1, -0x15(%rbp)'
+; ONE-NEXT: [0x0000000016][003]                  {Code} 'je	0x13'
+; ONE-NEXT: [0x0000000032][003]      8           {Line} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x0000000032][003]                  {Code} 'movl	%eax, -0x4(%rbp)'
+; ONE-NEXT: [0x0000000035][003]      9           {Line} {NewStatement} '/data/projects/tests/input/general/test.cpp'
+; ONE-NEXT: [0x0000000035][003]                  {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [0x0000000038][003]                  {Code} 'popq	%rbp'
+; ONE-NEXT: [0x0000000039][003]                  {Code} 'retq'
+; ONE-NEXT: [0x000000003a][003]      9           {Line} {NewStatement} {EndSequence} '/data/projects/tests/input/general/test.cpp'
+; ONE-EMPTY:
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Element      Total    Printed
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Scopes           3          3
+; ONE-NEXT: Symbols          4          4
+; ONE-NEXT: Types            5          5
+; ONE-NEXT: Lines           25         25
+; ONE-NEXT: -----------------------------
+; ONE-NEXT: Total           37         37
+; ONE-EMPTY:
+; ONE-NEXT: Scope Sizes:
+; ONE-NEXT:        189 (100.00%) : [0x000000000b][001]              {CompileUnit} 'test.cpp'
+; ONE-NEXT:        110 ( 58.20%) : [0x000000002a][002]      2         {Function} extern not_inlined 'foo' -> [0x0000000099]'int'
+; ONE-NEXT:         27 ( 14.29%) : [0x0000000071][003]                  {Block}
+; ONE-EMPTY:
+; ONE-NEXT: Totals by lexical level:
+; ONE-NEXT: [001]:        189 (100.00%)
+; ONE-NEXT: [002]:        110 ( 58.20%)
+; ONE-NEXT: [003]:         27 ( 14.29%)

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-clang.o
new file mode 100644
index 0000000000000..61859c6705792
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-gcc.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-gcc.o
new file mode 100644
index 0000000000000..229df05cc22a8
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/hello-world-dwarf-gcc.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-clang.o
new file mode 100644
index 0000000000000..53c2c37211ad0
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-gcc.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-gcc.o
new file mode 100644
index 0000000000000..bbadbb4665ae9
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-43860-dwarf-gcc.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-clang.o
new file mode 100644
index 0000000000000..d833e18d96da6
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-gcc.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-gcc.o
new file mode 100644
index 0000000000000..3f8a70b6420cf
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-44884-dwarf-gcc.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-clang.o
new file mode 100644
index 0000000000000..8e30ccefe5137
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-gcc.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-gcc.o
new file mode 100644
index 0000000000000..fb835776afe7f
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-46466-dwarf-gcc.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-clang.o
new file mode 100644
index 0000000000000..1db88cc964f6e
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-gcc.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-gcc.o
new file mode 100644
index 0000000000000..178b673c37118
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-57040-test-dwarf-gcc.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-incorrect-instructions-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-incorrect-instructions-dwarf-clang.o
new file mode 100644
index 0000000000000..6c0b90636d45c
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/pr-incorrect-instructions-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-clang.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-clang.o
new file mode 100644
index 0000000000000..2d0fbe3fbcba5
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-clang.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-gcc.o b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-gcc.o
new file mode 100644
index 0000000000000..7926f15a8e400
Binary files /dev/null and b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/Inputs/test-dwarf-gcc.o 
diff er

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test
new file mode 100644
index 0000000000000..78e9670241a34
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-ignored-DW_FORM_implicit_const.test
@@ -0,0 +1,65 @@
+; Ignored attributes with DW_FORM_implicit_const.
+; https://github.com/llvm/llvm-project/issues/57040
+
+; Output generated by g++ (Debian 11.3.0-3) 11.3.0
+
+; .debug_abbrev contents:
+; [1] DW_TAG_formal_parameter     DW_CHILDREN_no
+;         DW_AT_decl_file DW_FORM_implicit_const  1
+;         DW_AT_decl_line DW_FORM_implicit_const  2
+
+; [2] DW_TAG_typedef      DW_CHILDREN_no
+;         DW_AT_decl_file DW_FORM_implicit_const  1
+;         DW_AT_decl_line DW_FORM_data1
+
+; Attributes with DW_FORM_implicit_const being ignored by the ELFReader,
+; causing {Parameter} and {TypeAlias} to omit line numbers.
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --print=scopes,symbols,types \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-57040-test-dwarf-clang.o' -> elf64-x86-64
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT: [002]               {Producer} 'clang version 14.0.6'
+; ONE-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: [003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,format,producer \
+; RUN:                         --print=scopes,symbols,types \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-57040-test-dwarf-gcc.o' -> elf64-x86-64
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'test.cpp'
+; TWO-NEXT: [002]               {Producer} 'GNU C++17 11.3.0 {{.*}}'
+; TWO-NEXT: [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; TWO-NEXT: [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; TWO-NEXT: [003]                 {Block}
+; TWO-NEXT: [004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; TWO-NEXT: [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; TWO-NEXT: [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; TWO-NEXT: [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; TWO-NEXT: [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
new file mode 100644
index 0000000000000..4d7aba1d00553
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-57040-incorrect-function-compare.test
@@ -0,0 +1,142 @@
+; Incorrect function matching during comparison.
+; https://github.com/llvm/llvm-project/issues/57040
+
+; Output generated by g++ (Debian 11.3.0-3) 11.3.0
+
+; .debug_info contents:
+; format = DWARF32, version = 0x0005, unit_type = DW_UT_compile
+;
+; DW_TAG_compile_unit
+;   DW_TAG_subprogram ("foo")
+;     DW_AT_decl_file	(1)
+;
+;     DW_TAG_formal_parameter ("ParamPtr")
+;       DW_AT_decl_file	(1)
+;
+; .debug_line contents:
+; Line table prologue:
+;           format: DWARF32, version: 5
+; include_directories[0] = "/usr/local/google/home/aheejin/test/llvm-dva"
+; file_names[0]: name: "test.cpp" dir_index: 0
+; file_names[1]: name: "test.cpp" dir_index: 0
+
+; The values for DW_AT_decl_file are 1-indexed.
+
+; test.cpp
+;  1  using INTPTR = const int *;
+;  2  int foo(INTPTR ParamPtr, unsigned ParamUnsigned, bool ParamBool) {
+;  3    if (ParamBool) {
+;  4      typedef int INTEGER;
+;  5      const INTEGER CONSTANT = 7;
+;  6      return CONSTANT;
+;  7    }
+;  8    return ParamUnsigned;
+;  9  }
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,producer \
+; RUN:                         --compare=types \
+; RUN:                         --report=view \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-clang.o \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Reference: 'pr-57040-test-dwarf-clang.o'
+; ONE-NEXT: Target:    'pr-57040-test-dwarf-gcc.o'
+; ONE-EMPTY:
+; ONE-NEXT: Logical View:
+; ONE-NEXT:  [000]           {File} 'pr-57040-test-dwarf-clang.o'
+; ONE-EMPTY:
+; ONE-NEXT:  [001]             {CompileUnit} 'test.cpp'
+; ONE-NEXT:  [002]               {Producer} 'clang version 14.0.6'
+; ONE-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; ONE-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT:  [003]                 {Block}
+; ONE-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; ONE-NEXT: +[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; ONE-NEXT:  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; ONE-NEXT: -[003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-clang.o \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-gcc.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Reference: 'pr-57040-test-dwarf-clang.o'
+; TWO-NEXT: Target:    'pr-57040-test-dwarf-gcc.o'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Missing Types:
+; TWO-NEXT: -[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: (1) Added Types:
+; TWO-NEXT: +[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; TWO-EMPTY:
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Element   Expected    Missing      Added
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Scopes           4          0          0
+; TWO-NEXT: Symbols          0          0          0
+; TWO-NEXT: Types            2          1          1
+; TWO-NEXT: Lines            0          0          0
+; TWO-NEXT: ----------------------------------------
+; TWO-NEXT: Total            6          1          1
+
+; Changing the 'Reference' and 'Target' order:
+
+; RUN: llvm-debuginfo-analyzer --attribute=level,producer \
+; RUN:                         --compare=types \
+; RUN:                         --report=view \
+; RUN:                         --print=symbols,types \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-gcc.o \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=THR %s
+
+; THR:      Reference: 'pr-57040-test-dwarf-gcc.o'
+; THR-NEXT: Target:    'pr-57040-test-dwarf-clang.o'
+; THR-EMPTY:
+; THR-NEXT: Logical View:
+; THR-NEXT:  [000]           {File} 'pr-57040-test-dwarf-gcc.o'
+; THR-EMPTY:
+; THR-NEXT:  [001]             {CompileUnit} 'test.cpp'
+; THR-NEXT:  [002]               {Producer} 'GNU C++17 11.3.0 {{.*}}'
+; THR-NEXT:  [002]     1         {TypeAlias} 'INTPTR' -> '* const int'
+; THR-NEXT:  [002]     2         {Function} extern not_inlined 'foo' -> 'int'
+; THR-NEXT:  [003]                 {Block}
+; THR-NEXT: -[004]     4             {TypeAlias} 'INTEGER' -> 'int'
+; THR-NEXT:  [004]     5             {Variable} 'CONSTANT' -> 'const INTEGER'
+; THR-NEXT:  [003]     2           {Parameter} 'ParamBool' -> 'bool'
+; THR-NEXT:  [003]     2           {Parameter} 'ParamPtr' -> 'INTPTR'
+; THR-NEXT:  [003]     2           {Parameter} 'ParamUnsigned' -> 'unsigned int'
+; THR-NEXT: +[003]     4           {TypeAlias} 'INTEGER' -> 'int'
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --compare=types \
+; RUN:                         --report=list \
+; RUN:                         --print=symbols,types,summary \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-gcc.o \
+; RUN:                         %p/Inputs/pr-57040-test-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=FOU %s
+
+; FOU:      Reference: 'pr-57040-test-dwarf-gcc.o'
+; FOU-NEXT: Target:    'pr-57040-test-dwarf-clang.o'
+; FOU-EMPTY:
+; FOU-NEXT: (1) Missing Types:
+; FOU-NEXT: -[004]     4     {TypeAlias} 'INTEGER' -> 'int'
+; FOU-EMPTY:
+; FOU-NEXT: (1) Added Types:
+; FOU-NEXT: +[003]     4     {TypeAlias} 'INTEGER' -> 'int'
+; FOU-EMPTY:
+; FOU-NEXT: ----------------------------------------
+; FOU-NEXT: Element   Expected    Missing      Added
+; FOU-NEXT: ----------------------------------------
+; FOU-NEXT: Scopes           4          0          0
+; FOU-NEXT: Symbols          0          0          0
+; FOU-NEXT: Types            2          1          1
+; FOU-NEXT: Lines            0          0          0
+; FOU-NEXT: ----------------------------------------
+; FOU-NEXT: Total            6          1          1

diff  --git a/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test
new file mode 100644
index 0000000000000..083068be784bb
--- /dev/null
+++ b/llvm/test/tools/llvm-debuginfo-analyzer/DWARF/pr-incorrect-logical-instructions.test
@@ -0,0 +1,205 @@
+; * Added incorrect logical instructions for: --print=lines,instructions
+;   'bar' and 'foo' showing extra instruction from compiler generated functions:
+;   '_cxx_global_var_init' and '_GLOBAL_sub_l_suite_lexical_01.cpp'
+;
+; * Missing logical instructions for: --print=instructions
+;   Only 'foo' showing logical instructions.
+
+; pr-incorrect-instructions-dwarf-clang.cpp
+;  1 int ABCDE = 56; int XYZ = ABCDE * 65;
+;  2 int bar(int Param) {
+;  3   return Param + 999999 * Param - 66;
+;  4 }
+;  5
+;  6 int foo(int Param) {
+;  7   return Param - bar(Param) / Param * 66 + ABCDE;
+;  8 }
+;  9
+; 10 int test(int P1) {
+; 11  int Local_1 = P1 - ABCDE;
+; 12  {
+; 13    int Local_A = 0;
+; 14    Local_A = P1 + foo(Local_1);
+; 15    ++Local_1;
+; 16  }
+; 17  return Local_1;
+; 18 }
+; 19
+; 20 int main() {
+; 21  return 0;
+; 22 }
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --print=lines,instructions \
+; RUN:                         %p/Inputs/pr-incorrect-instructions-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=ONE %s
+
+; ONE:      Logical View:
+; ONE-NEXT: [000]           {File} 'pr-incorrect-instructions-dwarf-clang.o'
+; ONE-EMPTY:
+; ONE-NEXT: [001]             {CompileUnit} 'pr-incorrect-instructions-dwarf-clang.cpp'
+; ONE-NEXT: [002]     2         {Function} extern not_inlined 'bar' -> 'int'
+; ONE-NEXT: [003]     2           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'movl	%edi, -0x4(%rbp)'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'imull	$0xf423f, -0x4(%rbp), %ecx'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'addl	%ecx, %eax'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'subl	$0x42, %eax'
+; ONE-NEXT: [003]     3           {Line}
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [002]     6         {Function} extern not_inlined 'foo' -> 'int'
+; ONE-NEXT: [003]     6           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'subq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'movl	%edi, -0x4(%rbp)'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [003]                 {Code} 'movl	%eax, -0x8(%rbp)'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %edi'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'callq	0x0'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'cltd'
+; ONE-NEXT: [003]                 {Code} 'idivl	-0x4(%rbp)'
+; ONE-NEXT: [003]                 {Code} 'movl	%eax, %ecx'
+; ONE-NEXT: [003]                 {Code} 'movl	-0x8(%rbp), %eax'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'imull	$0x42, %ecx, %ecx'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'subl	%ecx, %eax'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'addl	(%rip), %eax'
+; ONE-NEXT: [003]     7           {Line}
+; ONE-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [003]                 {Code} 'data16'
+; ONE-NEXT: [002]    10         {Function} extern not_inlined 'test' -> 'int'
+; ONE-NEXT: [003]                 {Block}
+; ONE-NEXT: [004]    13             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	$0x0, -0xc(%rbp)'
+; ONE-NEXT: [004]    14             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [004]                   {Code} 'movl	%eax, -0x10(%rbp)'
+; ONE-NEXT: [004]    14             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	-0x8(%rbp), %edi'
+; ONE-NEXT: [004]    14             {Line}
+; ONE-NEXT: [004]                   {Code} 'callq	0x0'
+; ONE-NEXT: [004]                   {Code} 'movl	%eax, %ecx'
+; ONE-NEXT: [004]                   {Code} 'movl	-0x10(%rbp), %eax'
+; ONE-NEXT: [004]    14             {Line}
+; ONE-NEXT: [004]                   {Code} 'addl	%ecx, %eax'
+; ONE-NEXT: [004]    14             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	%eax, -0xc(%rbp)'
+; ONE-NEXT: [004]    15             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	-0x8(%rbp), %eax'
+; ONE-NEXT: [004]                   {Code} 'addl	$0x1, %eax'
+; ONE-NEXT: [004]                   {Code} 'movl	%eax, -0x8(%rbp)'
+; ONE-NEXT: [004]    17             {Line}
+; ONE-NEXT: [004]                   {Code} 'movl	-0x8(%rbp), %eax'
+; ONE-NEXT: [003]    10           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'subq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'movl	%edi, -0x4(%rbp)'
+; ONE-NEXT: [003]    11           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; ONE-NEXT: [003]    11           {Line}
+; ONE-NEXT: [003]                 {Code} 'subl	(%rip), %eax'
+; ONE-NEXT: [003]    11           {Line}
+; ONE-NEXT: [003]                 {Code} 'movl	%eax, -0x8(%rbp)'
+; ONE-NEXT: [003]    17           {Line}
+; ONE-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [002]    20         {Function} extern not_inlined 'main' -> 'int'
+; ONE-NEXT: [003]    20           {Line}
+; ONE-NEXT: [003]                 {Code} 'pushq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; ONE-NEXT: [003]                 {Code} 'movl	$0x0, -0x4(%rbp)'
+; ONE-NEXT: [003]    21           {Line}
+; ONE-NEXT: [003]                 {Code} 'xorl	%eax, %eax'
+; ONE-NEXT: [003]                 {Code} 'popq	%rbp'
+; ONE-NEXT: [003]                 {Code} 'retq'
+; ONE-NEXT: [003]    21           {Line}
+
+; RUN: llvm-debuginfo-analyzer --attribute=level \
+; RUN:                         --print=instructions \
+; RUN:                         %p/Inputs/pr-incorrect-instructions-dwarf-clang.o 2>&1 | \
+; RUN: FileCheck --strict-whitespace -check-prefix=TWO %s
+
+; TWO:      Logical View:
+; TWO-NEXT: [000]           {File} 'pr-incorrect-instructions-dwarf-clang.o'
+; TWO-EMPTY:
+; TWO-NEXT: [001]             {CompileUnit} 'pr-incorrect-instructions-dwarf-clang.cpp'
+; TWO-NEXT: [002]     2         {Function} extern not_inlined 'bar' -> 'int'
+; TWO-NEXT: [003]                 {Code} 'pushq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; TWO-NEXT: [003]                 {Code} 'movl	%edi, -0x4(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; TWO-NEXT: [003]                 {Code} 'imull	$0xf423f, -0x4(%rbp), %ecx'
+; TWO-NEXT: [003]                 {Code} 'addl	%ecx, %eax'
+; TWO-NEXT: [003]                 {Code} 'subl	$0x42, %eax'
+; TWO-NEXT: [003]                 {Code} 'popq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'retq'
+; TWO-NEXT: [002]     6         {Function} extern not_inlined 'foo' -> 'int'
+; TWO-NEXT: [003]                 {Code} 'pushq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; TWO-NEXT: [003]                 {Code} 'subq	$0x10, %rsp'
+; TWO-NEXT: [003]                 {Code} 'movl	%edi, -0x4(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; TWO-NEXT: [003]                 {Code} 'movl	%eax, -0x8(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %edi'
+; TWO-NEXT: [003]                 {Code} 'callq	0x0'
+; TWO-NEXT: [003]                 {Code} 'cltd'
+; TWO-NEXT: [003]                 {Code} 'idivl	-0x4(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'movl	%eax, %ecx'
+; TWO-NEXT: [003]                 {Code} 'movl	-0x8(%rbp), %eax'
+; TWO-NEXT: [003]                 {Code} 'imull	$0x42, %ecx, %ecx'
+; TWO-NEXT: [003]                 {Code} 'subl	%ecx, %eax'
+; TWO-NEXT: [003]                 {Code} 'addl	(%rip), %eax'
+; TWO-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
+; TWO-NEXT: [003]                 {Code} 'popq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'retq'
+; TWO-NEXT: [003]                 {Code} 'data16'
+; TWO-NEXT: [002]    10         {Function} extern not_inlined 'test' -> 'int'
+; TWO-NEXT: [003]                 {Block}
+; TWO-NEXT: [004]                   {Code} 'movl	$0x0, -0xc(%rbp)'
+; TWO-NEXT: [004]                   {Code} 'movl	-0x4(%rbp), %eax'
+; TWO-NEXT: [004]                   {Code} 'movl	%eax, -0x10(%rbp)'
+; TWO-NEXT: [004]                   {Code} 'movl	-0x8(%rbp), %edi'
+; TWO-NEXT: [004]                   {Code} 'callq	0x0'
+; TWO-NEXT: [004]                   {Code} 'movl	%eax, %ecx'
+; TWO-NEXT: [004]                   {Code} 'movl	-0x10(%rbp), %eax'
+; TWO-NEXT: [004]                   {Code} 'addl	%ecx, %eax'
+; TWO-NEXT: [004]                   {Code} 'movl	%eax, -0xc(%rbp)'
+; TWO-NEXT: [004]                   {Code} 'movl	-0x8(%rbp), %eax'
+; TWO-NEXT: [004]                   {Code} 'addl	$0x1, %eax'
+; TWO-NEXT: [004]                   {Code} 'movl	%eax, -0x8(%rbp)'
+; TWO-NEXT: [004]                   {Code} 'movl	-0x8(%rbp), %eax'
+; TWO-NEXT: [003]                 {Code} 'pushq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; TWO-NEXT: [003]                 {Code} 'subq	$0x10, %rsp'
+; TWO-NEXT: [003]                 {Code} 'movl	%edi, -0x4(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'movl	-0x4(%rbp), %eax'
+; TWO-NEXT: [003]                 {Code} 'subl	(%rip), %eax'
+; TWO-NEXT: [003]                 {Code} 'movl	%eax, -0x8(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'addq	$0x10, %rsp'
+; TWO-NEXT: [003]                 {Code} 'popq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'retq'
+; TWO-NEXT: [002]    20         {Function} extern not_inlined 'main' -> 'int'
+; TWO-NEXT: [003]                 {Code} 'pushq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'movq	%rsp, %rbp'
+; TWO-NEXT: [003]                 {Code} 'movl	$0x0, -0x4(%rbp)'
+; TWO-NEXT: [003]                 {Code} 'xorl	%eax, %eax'
+; TWO-NEXT: [003]                 {Code} 'popq	%rbp'
+; TWO-NEXT: [003]                 {Code} 'retq'

diff  --git a/llvm/tools/llvm-debuginfo-analyzer/LLVMBuild.txt b/llvm/tools/llvm-debuginfo-analyzer/LLVMBuild.txt
deleted file mode 100644
index 2fcd27062688f..0000000000000
--- a/llvm/tools/llvm-debuginfo-analyzer/LLVMBuild.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-;===- ./tools/llvm-debuginfo-analyzer/LLVMBuild.txt ------------*- Conf -*--===;
-;
-; 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 is an LLVMBuild description file for the components in this subdirectory.
-;
-; For more information on the LLVMBuild system, please see:
-;
-;   http://llvm.org/docs/LLVMBuild.html
-;
-;===------------------------------------------------------------------------===;
-
-[component_0]
-type = Tool
-name = llvm-debuginfo-analyzer
-parent = Tools
-required_libraries = DebugInfoLogicalView DebugInfoDWARF DebugInfoCodeView DebugInfoPDB Object

diff  --git a/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp b/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp
index a651b97f3d7de..fb82ec0b80e75 100644
--- a/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp
+++ b/llvm/tools/llvm-debuginfo-analyzer/llvm-debuginfo-analyzer.cpp
@@ -13,11 +13,10 @@
 
 #include "Options.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
-#include "llvm/Object/Archive.h"
+#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
 #include "llvm/Support/COM.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/ToolOutputFile.h"
 #include "llvm/Support/WithColor.h"
@@ -39,6 +38,16 @@ static void error(std::error_code EC, char const *Fmt, const Ts &...Vals) {
   exit(1);
 }
 
+static void error(Error EC) {
+  if (!EC)
+    return;
+  handleAllErrors(std::move(EC), [&](const ErrorInfoBase &EI) {
+    errs() << "\n";
+    WithColor::error(errs(), ToolName) << EI.message() << ".\n";
+    exit(1);
+  });
+}
+
 /// If the input path is a .dSYM bundle (as created by the dsymutil tool),
 /// replace it with individual entries for each of the object files inside the
 /// bundle otherwise return the input path.
@@ -113,6 +122,7 @@ int main(int argc, char **argv) {
 
   propagateOptions();
   ScopedPrinter W(OutputFile.os());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
 
   // Print the command line.
   if (options().getInternalCmdline()) {
@@ -123,5 +133,9 @@ int main(int argc, char **argv) {
     Stream << "\n";
   }
 
+  // Create readers and perform requested tasks on them.
+  if (Error Err = ReaderHandler.process())
+    error(std::move(Err));
+
   return EXIT_SUCCESS;
 }

diff  --git a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
index 4a51f017164c5..d17ea757e586f 100644
--- a/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
@@ -1,10 +1,15 @@
 set(LLVM_LINK_COMPONENTS
+  AllTargetsDescs
+  AllTargetsInfos
+  AllTargetsDisassemblers
   DebugInfoLogicalView
+  MCDisassembler
   )
 
-add_llvm_unittest(DebugInfoLogicalViewTests
+add_llvm_unittest_with_input_files(DebugInfoLogicalViewTests
   CommandLineOptionsTest.cpp
   CompareElementsTest.cpp
+  ELFReaderTest.cpp
   SelectElementsTest.cpp
   LocationRangesTest.cpp
   LogicalElementsTest.cpp

diff  --git a/llvm/unittests/DebugInfo/LogicalView/ELFReaderTest.cpp b/llvm/unittests/DebugInfo/LogicalView/ELFReaderTest.cpp
new file mode 100644
index 0000000000000..e494e03cf2ed5
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/ELFReaderTest.cpp
@@ -0,0 +1,342 @@
+//===- llvm/unittest/DebugInfo/LogicalView/ELFReaderTest.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/LVCompare.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/DebugInfo/LogicalView/LVReaderHandler.h"
+#include "llvm/Support/COM.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+extern const char *TestMainArgv0;
+
+namespace {
+
+const char *DwarfClang = "test-dwarf-clang.o";
+const char *DwarfGcc = "test-dwarf-gcc.o";
+
+// Helper function to get the first compile unit.
+LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {
+  EXPECT_NE(Root, nullptr);
+  const LVScopes *CompileUnits = Root->getScopes();
+  EXPECT_NE(CompileUnits, nullptr);
+  EXPECT_EQ(CompileUnits->size(), 1u);
+
+  LVScopes::const_iterator Iter = CompileUnits->begin();
+  EXPECT_NE(Iter, nullptr);
+  LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(*Iter);
+  EXPECT_NE(CompileUnit, nullptr);
+  return CompileUnit;
+}
+
+// Helper function to create a reader.
+LVReader *createReader(LVReaderHandler &ReaderHandler,
+                       SmallString<128> &InputsDir, StringRef Filename) {
+  SmallString<128> ObjectName(InputsDir);
+  llvm::sys::path::append(ObjectName, Filename);
+
+  Expected<LVReader *> ReaderOrErr =
+      ReaderHandler.createReader(std::string(ObjectName));
+  EXPECT_THAT_EXPECTED(ReaderOrErr, Succeeded());
+  LVReader *Reader = *ReaderOrErr;
+  EXPECT_NE(Reader, nullptr);
+  return Reader;
+}
+
+// Check the logical elements basic properties.
+void checkElementProperties(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64");
+  EXPECT_EQ(Root->getName(), DwarfClang);
+
+  EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
+  EXPECT_TRUE(CompileUnit->getProducer().startswith("clang"));
+  EXPECT_EQ(CompileUnit->getName(), "test.cpp");
+
+  EXPECT_EQ(CompileUnit->lineCount(), 0u);
+  EXPECT_EQ(CompileUnit->scopeCount(), 1u);
+  EXPECT_EQ(CompileUnit->symbolCount(), 0u);
+  EXPECT_EQ(CompileUnit->typeCount(), 7u);
+  EXPECT_EQ(CompileUnit->rangeCount(), 1u);
+
+  const LVLocations *Ranges = CompileUnit->getRanges();
+  ASSERT_NE(Ranges, nullptr);
+  ASSERT_EQ(Ranges->size(), 1u);
+  LVLocations::const_iterator IterLocation = Ranges->begin();
+  LVLocation *Location = (*IterLocation);
+  EXPECT_STREQ(Location->getIntervalInfo().c_str(),
+               "{Range} Lines 2:9 [0x0000000000:0x000000003a]");
+
+  LVRange RangeList;
+  CompileUnit->getRanges(RangeList);
+
+  const LVRangeEntries &RangeEntries = RangeList.getEntries();
+  ASSERT_EQ(RangeEntries.size(), 2u);
+  LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();
+  LVRangeEntry RangeEntry = *IterRanges;
+  EXPECT_EQ(RangeEntry.lower(), 0u);
+  EXPECT_EQ(RangeEntry.upper(), 0x3au);
+  EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
+  EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");
+  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x0bu);
+
+  ++IterRanges;
+  RangeEntry = *IterRanges;
+  EXPECT_EQ(RangeEntry.lower(), 0x1cu);
+  EXPECT_EQ(RangeEntry.upper(), 0x2fu);
+  EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
+  EXPECT_EQ(RangeEntry.scope()->getName(), "foo::?");
+  EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x71u);
+
+  const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
+  ASSERT_EQ(PublicNames.size(), 1u);
+  LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
+  LVScope *Function = (*IterNames).first;
+  EXPECT_EQ(Function->getName(), "foo");
+  EXPECT_EQ(Function->getLineNumber(), 2u);
+  LVNameInfo NameInfo = (*IterNames).second;
+  EXPECT_EQ(NameInfo.first, 0u);
+  EXPECT_EQ(NameInfo.second, 0x3au);
+
+  // Lines (debug and assembler) for 'foo'.
+  const LVLines *Lines = Function->getLines();
+  ASSERT_NE(Lines, nullptr);
+  ASSERT_EQ(Lines->size(), 0x12u);
+}
+
+// Check the logical elements selection.
+void checkElementSelection(LVReader *Reader) {
+  LVScopeRoot *Root = Reader->getScopesRoot();
+  LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
+
+  // Get the matched elements.
+  LVElements MatchedElements = CompileUnit->getMatchedElements();
+  std::map<LVOffset, LVElement *> MapElements;
+  for (LVElement *Element : MatchedElements)
+    MapElements[Element->getOffset()] = Element;
+  ASSERT_EQ(MapElements.size(), 0xeu);
+
+  LVElement *Element = MapElements[0x000000004b]; // 'foo'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("foo"), StringRef::npos);
+  EXPECT_EQ(Element->getIsScope(), 1);
+
+  Element = MapElements[0x00000000c0]; // 'CONSTANT'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("CONSTANT"), StringRef::npos);
+  EXPECT_EQ(Element->getIsSymbol(), 1);
+
+  Element = MapElements[0x000000002d]; // 'INTPTR'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("INTPTR"), StringRef::npos);
+  EXPECT_EQ(Element->getIsType(), 1);
+
+  Element = MapElements[0x00000000af]; // 'INTEGER'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("INTEGER"), StringRef::npos);
+  EXPECT_EQ(Element->getIsType(), 1);
+
+  Element = MapElements[0x000000000f]; // 'movl	%edx, %eax'
+  ASSERT_NE(Element, nullptr);
+  EXPECT_NE(Element->getName().find("movl"), StringRef::npos);
+  EXPECT_EQ(Element->getIsLine(), 1);
+
+  // Get the parents for the matched elements.
+  LVScopes MatchedScopes = CompileUnit->getMatchedScopes();
+  std::set<LVOffset> SetScopes;
+  for (LVScope *Scope : MatchedScopes)
+    SetScopes.insert(Scope->getOffset());
+  std::set<LVOffset>::iterator Iter;
+  ASSERT_EQ(SetScopes.size(), 3u);
+
+  Iter = SetScopes.find(0x000000000b); // CompileUnit <- 'foo'
+  EXPECT_NE(Iter, SetScopes.end());
+  Iter = SetScopes.find(0x000000009e); // Function <- 'movl	%edx, %eax'
+  EXPECT_NE(Iter, SetScopes.end());
+  Iter = SetScopes.find(0x000000009e); // LexicalScope <- 'INTEGER'
+  EXPECT_NE(Iter, SetScopes.end());
+}
+
+// Check the logical elements comparison.
+void checkElementComparison(LVReader *Reference, LVReader *Target) {
+  LVCompare Compare(nulls());
+  Error Err = Compare.execute(Reference, Target);
+  ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+
+  // Get comparison table.
+  LVPassTable PassTable = Compare.getPassTable();
+  ASSERT_EQ(PassTable.size(), 5u);
+
+  LVReader *Reader;
+  LVElement *Element;
+  LVComparePass Pass;
+
+  // Reference: Missing Variable 'CONSTANT'
+  std::tie(Reader, Element, Pass) = PassTable[0];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 5u);
+  EXPECT_EQ(Element->getName(), "CONSTANT");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing TypeDefinition 'INTEGER'
+  std::tie(Reader, Element, Pass) = PassTable[1];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 3u);
+  EXPECT_EQ(Element->getLineNumber(), 4u);
+  EXPECT_EQ(Element->getName(), "INTEGER");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Reference: Missing DebugLine
+  std::tie(Reader, Element, Pass) = PassTable[2];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Reference);
+  EXPECT_EQ(Element->getLevel(), 3u);
+  EXPECT_EQ(Element->getLineNumber(), 8u);
+  EXPECT_EQ(Element->getName(), "");
+  EXPECT_EQ(Pass, LVComparePass::Missing);
+
+  // Target: Added Variable 'CONSTANT'
+  std::tie(Reader, Element, Pass) = PassTable[3];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Target);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 5u);
+  EXPECT_EQ(Element->getName(), "CONSTANT");
+  EXPECT_EQ(Pass, LVComparePass::Added);
+
+  // Target: Added TypeDefinition 'INTEGER'
+  std::tie(Reader, Element, Pass) = PassTable[4];
+  ASSERT_NE(Reader, nullptr);
+  ASSERT_NE(Element, nullptr);
+  EXPECT_EQ(Reader, Target);
+  EXPECT_EQ(Element->getLevel(), 4u);
+  EXPECT_EQ(Element->getLineNumber(), 4u);
+  EXPECT_EQ(Element->getName(), "INTEGER");
+  EXPECT_EQ(Pass, LVComparePass::Added);
+}
+
+// Logical elements properties.
+void elementProperties(SmallString<128> &InputsDir) {
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setAttributeFormat();
+  ReaderOptions.setAttributeFilename();
+  ReaderOptions.setAttributeProducer();
+  ReaderOptions.setAttributePublics();
+  ReaderOptions.setAttributeRange();
+  ReaderOptions.setAttributeLocation();
+  ReaderOptions.setPrintAll();
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical elements properties.
+  LVReader *Reader = createReader(ReaderHandler, InputsDir, DwarfClang);
+  checkElementProperties(Reader);
+  ReaderHandler.deleteReader(Reader);
+}
+
+// Logical elements selection.
+void elementSelection(SmallString<128> &InputsDir) {
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setPrintAll();
+
+  ReaderOptions.setSelectIgnoreCase();
+  ReaderOptions.setSelectUseRegex();
+
+  ReaderOptions.setReportList(); // Matched elements.
+  ReaderOptions.setReportView(); // Parents for matched elements.
+
+  // Add patterns.
+  ReaderOptions.Select.Generic.insert("foo");
+  ReaderOptions.Select.Generic.insert("movl[ \t]?%");
+  ReaderOptions.Select.Generic.insert("INT[a-z]*");
+  ReaderOptions.Select.Generic.insert("CONSTANT");
+
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical elements selection.
+  LVReader *Reader = createReader(ReaderHandler, InputsDir, DwarfGcc);
+  checkElementSelection(Reader);
+  ReaderHandler.deleteReader(Reader);
+}
+
+// Compare logical elements.
+void compareElements(SmallString<128> &InputsDir) {
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setPrintLines();
+  ReaderOptions.setPrintSymbols();
+  ReaderOptions.setPrintTypes();
+  ReaderOptions.setCompareLines();
+  ReaderOptions.setCompareSymbols();
+  ReaderOptions.setCompareTypes();
+
+  ReaderOptions.resolveDependencies();
+
+  std::vector<std::string> Objects;
+  ScopedPrinter W(outs());
+  LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
+
+  // Check logical comparison.
+  LVReader *Reference = createReader(ReaderHandler, InputsDir, DwarfClang);
+  LVReader *Target = createReader(ReaderHandler, InputsDir, DwarfGcc);
+  checkElementComparison(Reference, Target);
+  ReaderHandler.deleteReader(Reference);
+  ReaderHandler.deleteReader(Target);
+}
+
+TEST(LogicalViewTest, ELFReader) {
+  // Initialize targets and assembly printers/parsers.
+  llvm::InitializeAllTargetInfos();
+  llvm::InitializeAllTargetMCs();
+  InitializeAllDisassemblers();
+
+  llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
+  SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
+
+  // Logical elements general properties and selection.
+  elementProperties(InputsDir);
+  elementSelection(InputsDir);
+
+  // Compare logical elements.
+  compareElements(InputsDir);
+}
+
+} // namespace

diff  --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang.o b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang.o
new file mode 100644
index 0000000000000..23aedf65d1d6d
Binary files /dev/null and b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-clang.o 
diff er

diff  --git a/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-gcc.o b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-gcc.o
new file mode 100644
index 0000000000000..7926f15a8e400
Binary files /dev/null and b/llvm/unittests/DebugInfo/LogicalView/Inputs/test-dwarf-gcc.o 
diff er


        


More information about the llvm-commits mailing list