Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
@@ -0,0 +1,200 @@
+//===-- LVLocation.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 LVOperation and LVLocation classes, which are used
+// to describe variable locations.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLOCATION_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLOCATION_H
+
+#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
+
+namespace llvm {
+namespace logicalview {
+
+// The DW_AT_data_member_location attribute is a simple member offset.
+const LVSmall LVLocationMemberOffset = 0;
+
+class LVOperation final {
+  // To describe an operation:
+  // OpCode
+  // Operands[0]: First operand.
+  // Operands[1]: Second operand.
+  //   OP_bregx, OP_bit_piece, OP_[GNU_]const_type,
+  //   OP_[GNU_]deref_type, OP_[GNU_]entry_value, OP_implicit_value,
+  //   OP_[GNU_]implicit_pointer, OP_[GNU_]regval_type, OP_xderef_type.
+  LVSmall Opcode = 0;
+  uint64_t Operands[2];
+
+public:
+  LVOperation() = delete;
+  LVOperation(LVSmall Opcode, LVUnsigned Operand1, LVUnsigned Operand2)
+      : Opcode(Opcode) {
+    Operands[0] = Operand1;
+    Operands[1] = Operand2;
+  }
+  LVOperation(const LVOperation &) = delete;
+  LVOperation &operator=(const LVOperation &) = delete;
+  ~LVOperation() = default;
+
+  LVSmall getOpcode() const { return Opcode; }
+  uint64_t getOperand1() const { return Operands[0]; }
+  uint64_t getOperand2() const { return Operands[1]; }
+  std::string getOperandsDWARFInfo();
+  std::string getOperandsCodeViewInfo();
+
+public:
+  void print(raw_ostream &OS, bool Full = true) const;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() { print(dbgs()); }
+#endif
+};
+
+class LVLocation : public LVObject {
+  enum class Property {
+    IsAddressRange,
+    IsBaseClassOffset,
+    IsBaseClassStep,
+    IsClassOffset,
+    IsFixedAddress,
+    IsLocationSimple,
+    IsGapEntry,
+    IsOperation,
+    IsOperationList,
+    IsRegister,
+    IsStackOffset,
+    IsDiscardedRange,
+    IsInvalidRange,
+    IsInvalidLower,
+    IsInvalidUpper,
+    IsCallSite,
+    LastEntry
+  };
+  // Typed bitvector with properties for this location.
+  LVProperties<Property> Properties;
+
+  // True if the location it is associated with a debug range.
+  bool hasAssociatedRange() const {
+    return !getIsClassOffset() && !getIsDiscardedRange();
+  }
+
+protected:
+  // Line numbers associated with locations ranges.
+  LVLine *LowerLine = nullptr;
+  LVLine *UpperLine = nullptr;
+
+  // Active range:
+  // LowPC: an offset from an applicable base address, not a PC value.
+  // HighPC: an offset from an applicable base address, or a length.
+  LVAddress LowPC = 0;
+  LVAddress HighPC = 0;
+
+  void setKind();
+
+public:
+  LVLocation() : LVObject() { setIsLocation(); }
+  LVLocation(const LVLocation &) = delete;
+  LVLocation &operator=(const LVLocation &) = delete;
+  virtual ~LVLocation() = default;
+
+  PROPERTY(Property, IsAddressRange);
+  PROPERTY(Property, IsBaseClassOffset);
+  PROPERTY(Property, IsBaseClassStep);
+  PROPERTY_1(Property, IsClassOffset, IsLocationSimple);
+  PROPERTY_1(Property, IsFixedAddress, IsLocationSimple);
+  PROPERTY(Property, IsLocationSimple);
+  PROPERTY(Property, IsGapEntry);
+  PROPERTY(Property, IsOperationList);
+  PROPERTY(Property, IsOperation);
+  PROPERTY(Property, IsRegister);
+  PROPERTY_1(Property, IsStackOffset, IsLocationSimple);
+  PROPERTY(Property, IsDiscardedRange);
+  PROPERTY(Property, IsInvalidRange);
+  PROPERTY(Property, IsInvalidLower);
+  PROPERTY(Property, IsInvalidUpper);
+  PROPERTY(Property, IsCallSite);
+
+public:
+  const char *kind() const override;
+  // Mark the locations that have only DW_OP_fbreg as stack offset based.
+  virtual void updateKind() {}
+
+  // Line numbers for locations.
+  const LVLine *getLowerLine() const { return LowerLine; }
+  void setLowerLine(LVLine *Line) { LowerLine = Line; }
+  const LVLine *getUpperLine() const { return UpperLine; }
+  void setUpperLine(LVLine *Line) { UpperLine = Line; }
+
+  // Addresses for locations.
+  LVAddress getLowerAddress() const override { return LowPC; }
+  void setLowerAddress(LVAddress Address) override { LowPC = Address; }
+  LVAddress getUpperAddress() const override { return HighPC; }
+  void setUpperAddress(LVAddress Address) override { HighPC = Address; }
+
+  std::string getIntervalInfo() const;
+
+  bool validateRanges();
+
+  // In order to calculate a symbol coverage (percentage), take the ranges
+  // and obtain the number of units (bytes) covered by those ranges. We can't
+  // use the line numbers, because they can be zero or invalid.
+  // We return:
+  //   false: No locations or multiple locations.
+  //   true: a single location.
+  static bool calculateCoverage(LVLocations *Locations, unsigned &Factor,
+                                float &Percentage);
+
+  virtual void addObject(LVAddress LowPC, LVAddress HighPC,
+                         LVUnsigned SectionOffset, uint64_t LocDescOffset) {}
+  virtual void addObject(LVSmall Opcode, LVUnsigned Operand1,
+                         LVUnsigned Operand2) {}
+
+public:
+  static void print(LVLocations *Locations, raw_ostream &OS, bool Full = true);
+  void printInterval(raw_ostream &OS, bool Full = true) const;
+  void printRaw(raw_ostream &OS, bool Full = true) const;
+  virtual void printRawExtra(raw_ostream &OS, bool Full = true) const {}
+
+  void print(raw_ostream &OS, bool Full = true) const override;
+  void printExtra(raw_ostream &OS, bool Full = true) const override;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const override { print(dbgs()); }
+#endif
+};
+
+class LVLocationSymbol final : public LVLocation {
+  // Location descriptors for the active range.
+  LVAutoOperations *Entries = nullptr;
+
+  void updateKind() override;
+
+public:
+  LVLocationSymbol() : LVLocation() {}
+  LVLocationSymbol(const LVLocationSymbol &) = delete;
+  LVLocationSymbol &operator=(const LVLocationSymbol &) = delete;
+  ~LVLocationSymbol() { delete Entries; };
+
+public:
+  void addObject(LVAddress LowPC, LVAddress HighPC, LVUnsigned SectionOffset,
+                 uint64_t LocDescOffset) override;
+  void addObject(LVSmall Opcode, LVUnsigned Operand1,
+                 LVUnsigned Operand2) override;
+
+public:
+  void printRawExtra(raw_ostream &OS, bool Full = true) const override;
+  void printExtra(raw_ostream &OS, bool Full = true) const override;
+};
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVLOCATION_H
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
===================================================================
--- llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
@@ -102,6 +102,9 @@
 
 enum class LVBinaryType { NONE, ELF, COFF };
 
+// Validate functions.
+using LVValidLocation = bool (LVLocation::*)();
+
 // Keep counters of objects.
 struct LVCounter {
   unsigned Lines = 0;
@@ -261,6 +264,11 @@
   void setParent(LVSymbol *Symbol);
   void resetParent() { Parent = {nullptr}; }
 
+  virtual LVAddress getLowerAddress() const { return 0; }
+  virtual void setLowerAddress(LVAddress Address) {}
+  virtual LVAddress getUpperAddress() const { return 0; }
+  virtual void setUpperAddress(LVAddress Address) {}
+
   uint32_t getLineNumber() const { return LineNumber; }
   void setLineNumber(uint32_t Number) { LineNumber = Number; }
 
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h
@@ -0,0 +1,102 @@
+//===-- LVRange.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 LVRange class, which is used to describe a debug
+// information range.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVRANGE_H
+#define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVRANGE_H
+
+#include "llvm/ADT/IntervalTree.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVObject.h"
+
+namespace llvm {
+namespace logicalview {
+
+using LVAddressRange = std::pair<LVAddress, LVAddress>;
+
+class LVRangeEntry final {
+  LVAddress Lower = 0;
+  LVAddress Upper = 0;
+  LVScope *Scope = nullptr;
+
+public:
+  using RangeType = LVAddress;
+
+public:
+  LVRangeEntry() = delete;
+  LVRangeEntry(LVAddress LowerAddress, LVAddress UpperAddress, LVScope *Scope)
+      : Lower(LowerAddress), Upper(UpperAddress), Scope(Scope) {}
+
+public:
+  RangeType lower() const { return Lower; }
+  RangeType upper() const { return Upper; }
+  LVAddressRange addressRange() const {
+    return LVAddressRange(lower(), upper());
+  }
+  LVScope *scope() const { return Scope; }
+};
+
+// Class to represent a list of range addresses associated with a
+// scope; the addresses are stored in ascending order.
+using LVRangeEntries = std::vector<LVRangeEntry>;
+
+class LVRange final : public LVObject {
+  /// Map of where a user value is live, and its location.
+  using LVRangesTree = IntervalTree<LVAddress, LVScope *>;
+  using LVAllocator = LVRangesTree::Allocator;
+
+  LVAllocator Allocator;
+  LVRangesTree RangesTree;
+  LVRangeEntries RangeEntries;
+  LVAddress Lower = MaxAddress;
+  LVAddress Upper = 0;
+
+public:
+  LVRange() : LVObject(), RangesTree(Allocator) {}
+  LVRange(const LVRange &) = delete;
+  LVRange &operator=(const LVRange &) = delete;
+  ~LVRange() = default;
+
+public:
+  void addEntry(LVScope *Scope, LVAddress LowerAddress, LVAddress UpperAddress);
+  void addEntry(LVScope *Scope);
+  LVScope *getEntry(LVAddress Address) const;
+  LVScope *getEntry(LVAddress LowerAddress, LVAddress UpperAddress) const;
+  bool findEntry(LVAddress Low, LVAddress High) const;
+  LVAddress getLower() const { return Lower; }
+  LVAddress getUpper() const { return Upper; }
+
+  const LVRangeEntries &getEntries() const { return RangeEntries; }
+
+  void clear() {
+    RangeEntries.clear();
+    Lower = MaxAddress;
+    Upper = 0;
+  }
+  bool empty() const { return RangeEntries.empty(); }
+  void sort();
+
+  void startSearch();
+  void endSearch() {}
+
+public:
+  void print(raw_ostream &OS, bool Full = true) const override;
+  void printExtra(raw_ostream &OS, bool Full = true) const override {}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+  void dump() const override { print(dbgs()); }
+#endif
+};
+
+} // end namespace logicalview
+} // end namespace llvm
+
+#endif // LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVRANGE_H
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
===================================================================
--- llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
@@ -15,6 +15,7 @@
 #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVREADER_H
 
 #include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVRange.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/ToolOutputFile.h"
@@ -130,6 +131,11 @@
   Error doPrint();
   Error doLoad();
 
+  virtual std::string getRegisterName(LVSmall Opcode, uint64_t Operands[2]) {
+    llvm_unreachable("Invalid instance reader.");
+    return {};
+  }
+
   virtual bool isSystemEntry(LVElement *Element, StringRef Name = {}) {
     return false;
   };
@@ -140,6 +146,7 @@
 public:
   // Conditions to print an object.
   bool doPrintLine(const LVLine *Line) const { return true; }
+  bool doPrintLocation(const LVLocation *Location) const { return true; }
   bool doPrintScope(const LVScope *Scope) const { return true; }
   bool doPrintSymbol(const LVSymbol *Symbol) const { return true; }
   bool doPrintType(const LVType *Type) const { return true; }
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
===================================================================
--- llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
@@ -15,6 +15,7 @@
 #define LLVM_DEBUGINFO_LOGICALVIEW_CORE_LVSCOPE_H
 
 #include "llvm/DebugInfo/LogicalView/Core/LVElement.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVSort.h"
 #include <map>
 #include <set>
@@ -22,6 +23,8 @@
 namespace llvm {
 namespace logicalview {
 
+class LVRange;
+
 enum class LVScopeKind {
   IsAggregate,
   IsArray,
@@ -76,6 +79,15 @@
   LVProperties<LVScopeKind> Kinds;
   LVProperties<Property> Properties;
 
+  // Coverage factor in units (bytes).
+  unsigned CoverageFactor = 0;
+
+  // Calculate coverage factor.
+  void calculateCoverage() {
+    float CoveragePercentage = 0;
+    LVLocation::calculateCoverage(Ranges, CoverageFactor, CoveragePercentage);
+  }
+
   // Decide if the scope will be printed, using some conditions given by:
   // only-globals, only-locals, a-pattern.
   bool resolvePrinting() const;
@@ -86,11 +98,12 @@
                        LVScopeSetFunction SetFunction);
 
 protected:
-  // Types, Symbols, Scopes, Lines in this scope.
+  // Types, Symbols, Scopes, Lines, Locations in this scope.
   LVAutoTypes *Types = nullptr;
   LVAutoSymbols *Symbols = nullptr;
   LVAutoScopes *Scopes = nullptr;
   LVAutoLines *Lines = nullptr;
+  LVAutoLocations *Ranges = nullptr;
 
   // Vector of elements (types, scopes and symbols).
   // It is the union of (*Types, *Symbols and *Scopes) to be used for
@@ -104,6 +117,10 @@
   void resolveTemplate();
   void printEncodedArgs(raw_ostream &OS, bool Full) const;
 
+  void printActiveRanges(raw_ostream &OS, bool Full = true);
+  void printActiveRanges(raw_ostream &OS, bool Full = true) const {
+    (const_cast<LVScope *>(this))->printActiveRanges(OS, Full);
+  }
   virtual void printSizes(raw_ostream &OS) const {};
   virtual void printSummary(raw_ostream &OS) const {};
 
@@ -172,6 +189,7 @@
 
   // Get the specific children.
   const LVLines *getLines() const { return Lines; }
+  const LVLocations *getRanges() const { return Ranges; }
   const LVScopes *getScopes() const { return Scopes; }
   const LVSymbols *getSymbols() const { return Symbols; }
   const LVTypes *getTypes() const { return Types; }
@@ -182,6 +200,8 @@
   void addElement(LVScope *Scope);
   void addElement(LVSymbol *Symbol);
   void addElement(LVType *Type);
+  void addObject(LVLocation *Location);
+  void addObject(LVAddress LowerAddress, LVAddress UpperAddress);
   void addToChildren(LVElement *Element);
 
   // Add the missing elements from the given 'Reference', which is the
@@ -195,10 +215,29 @@
 
   // Get the size of specific children.
   size_t lineCount() const { return Lines ? Lines->size() : 0; }
+  size_t rangeCount() const { return Ranges ? Ranges->size() : 0; }
   size_t scopeCount() const { return Scopes ? Scopes->size() : 0; }
   size_t symbolCount() const { return Symbols ? Symbols->size() : 0; }
   size_t typeCount() const { return Types ? Types->size() : 0; }
 
+  // Calculate coverage factor.
+  void CalculateCoverageFactor() {
+    float CoveragePercentage = 0;
+    LVLocation::calculateCoverage(Ranges, CoverageFactor, CoveragePercentage);
+  }
+
+  // Find containing parent for the given address.
+  LVScope *outermostParent(LVAddress Address);
+
+  // Get all the locations associated with symbols.
+  void getLocations(LVLocations &LocationList, LVValidLocation ValidLocation,
+                    bool RecordInvalid = false);
+  void getRanges(LVLocations &LocationList, LVValidLocation ValidLocation,
+                 bool RecordInvalid = false);
+  void getRanges(LVRange &RangeList);
+
+  unsigned getCoverageFactor() const { return CoverageFactor; }
+
   Error doPrint(bool Split, bool Match, bool Print, raw_ostream &OS,
                 bool Full = true) const override;
   // Sort the logical elements using the criteria specified by the
@@ -380,6 +419,10 @@
     ProducerIndex = getStringPool().getIndex(ProducerName);
   }
 
+  // Process ranges, locations and calculate coverage.
+  void processRangeLocationCoverage(
+      LVValidLocation ValidLocation = &LVLocation::validateRanges);
+
   void printLocalNames(raw_ostream &OS, bool Full = true) const;
   void printSummary(raw_ostream &OS, const LVCounter &Counter,
                     const char *Header) const;
@@ -565,6 +608,9 @@
     FileFormatNameIndex = getStringPool().getIndex(FileFormatName);
   }
 
+  // Process the collected location, ranges and calculate coverage.
+  void processRangeInformation();
+
   void print(raw_ostream &OS, bool Full = true) const override;
   void printExtra(raw_ostream &OS, bool Full = true) const override;
   Error doPrintMatches(bool Split, raw_ostream &OS,
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
===================================================================
--- llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
@@ -40,6 +40,7 @@
 LVSortValue compareLine(const LVObject *LHS, const LVObject *RHS);
 LVSortValue compareName(const LVObject *LHS, const LVObject *RHS);
 LVSortValue compareOffset(const LVObject *LHS, const LVObject *RHS);
+LVSortValue compareRange(const LVObject *LHS, const LVObject *RHS);
 LVSortValue sortByKind(const LVObject *LHS, const LVObject *RHS);
 LVSortValue sortByLine(const LVObject *LHS, const LVObject *RHS);
 LVSortValue sortByName(const LVObject *LHS, const LVObject *RHS);
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
===================================================================
--- llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -167,6 +167,21 @@
   return (Twine("'") + Twine(Name1) + Twine(Name2) + Twine("'")).str();
 }
 
+// These are the values assigned to the debug location record IDs.
+// See DebugInfo/CodeView/CodeViewSymbols.def.
+// S_DEFRANGE                               0x113f
+// S_DEFRANGE_SUBFIELD                      0x1140
+// S_DEFRANGE_REGISTER                      0x1141
+// S_DEFRANGE_FRAMEPOINTER_REL              0x1142
+// S_DEFRANGE_SUBFIELD_REGISTER             0x1143
+// S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE   0x1144
+// S_DEFRANGE_REGISTER_REL                  0x1145
+// When recording CodeView debug location, the above values are truncated
+// to a uint8_t value in order to fit the 'OpCode' used for the logical
+// debug location operations.
+// Return the original CodeView enum value.
+inline uint16_t updateOperationCode(uint8_t Code) { return 0x1100 | Code; }
+
 } // end namespace logicalview
 } // end namespace llvm
 
Index: llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
===================================================================
--- llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
+++ llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
@@ -43,6 +43,8 @@
 
   // Reference to DW_AT_specification, DW_AT_abstract_origin attribute.
   LVSymbol *Reference = nullptr;
+  LVAutoLocations *Locations = nullptr;
+  LVLocation *CurrentLocation = nullptr;
 
   // Bitfields length.
   uint32_t BitSize = 0;
@@ -50,6 +52,14 @@
   // Index in the String pool representing any initial value.
   size_t ValueIndex = 0;
 
+  // Coverage factor in units (bytes).
+  unsigned CoverageFactor = 0;
+  float CoveragePercentage = 0;
+
+  // Add a location gap into the location list.
+  LVAutoLocations::iterator addLocationGap(LVAutoLocations::iterator Pos,
+                                           LVAddress LowPC, LVAddress HighPC);
+
 public:
   LVSymbol() : LVElement(LVSubclassID::LV_SYMBOL) {
     setIsSymbol();
@@ -57,7 +67,7 @@
   }
   LVSymbol(const LVSymbol &) = delete;
   LVSymbol &operator=(const LVSymbol &) = delete;
-  ~LVSymbol() = default;
+  ~LVSymbol() { delete Locations; }
 
   static bool classof(const LVElement *Element) {
     return Element->getSubclassID() == LVSubclassID::LV_SYMBOL;
@@ -109,6 +119,34 @@
   }
   size_t getValueIndex() const override { return ValueIndex; }
 
+  // Add a Location Entry.
+  void addLocationConstant(dwarf::Attribute Attr, LVUnsigned Constant,
+                           uint64_t LocDescOffset);
+  void addLocationOperands(LVSmall Opcode, uint64_t Operand1,
+                           uint64_t Operand2);
+  void addLocation(dwarf::Attribute Attr, LVAddress LowPC, LVAddress HighPC,
+                   LVUnsigned SectionOffset, uint64_t LocDescOffset,
+                   bool CallSiteLocation = false);
+
+  // Fill gaps in the location list.
+  void fillLocationGaps();
+
+  // Get all the locations associated with symbols.
+  void getLocations(LVLocations &LocationList, LVValidLocation ValidLocation,
+                    bool RecordInvalid = false);
+  void getLocations(LVLocations &LocationList) const;
+
+  // Calculate coverage factor.
+  void calculateCoverage();
+
+  unsigned getCoverageFactor() const { return CoverageFactor; }
+  void setCoverageFactor(unsigned Value) { CoverageFactor = Value; }
+  float getCoveragePercentage() const { return CoveragePercentage; }
+  void setCoveragePercentage(float Value) { CoveragePercentage = Value; }
+
+  // Print location in raw format.
+  void printLocations(raw_ostream &OS, bool Full = true) const;
+
   // Follow a chain of references given by DW_AT_abstract_origin and/or
   // DW_AT_specification and update the symbol name.
   StringRef resolveReferencesChain();
Index: llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
===================================================================
--- llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -17,8 +17,10 @@
 add_lv_impl_folder(Core
   Core/LVElement.cpp
   Core/LVLine.cpp
+  Core/LVLocation.cpp
   Core/LVObject.cpp
   Core/LVOptions.cpp
+  Core/LVRange.cpp
   Core/LVReader.cpp
   Core/LVScope.cpp
   Core/LVSort.cpp
Index: llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
===================================================================
--- /dev/null
+++ llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
@@ -0,0 +1,674 @@
+//===-- LVLocation.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 LVOperation and LVLocation classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Location"
+
+void LVOperation::print(raw_ostream &OS, bool Full) const {}
+
+// Identify the most common type of operations and print them using a high
+// level format, trying to isolate the DWARF complexity.
+std::string LVOperation::getOperandsDWARFInfo() {
+  std::string String;
+  raw_string_ostream Stream(String);
+
+  auto PrintRegisterInfo = [&](LVSmall Code) {
+    //-----------------------------------------------------------------------
+    // 2.5.1.1 Literal encodings.
+    //-----------------------------------------------------------------------
+    if (dwarf::DW_OP_lit0 <= Code && Code <= dwarf::DW_OP_lit31) {
+      Stream << format("lit%d", Code - dwarf::DW_OP_lit0);
+      return;
+    }
+
+    //-----------------------------------------------------------------------
+    // 2.5.1.2 Register values.
+    //-----------------------------------------------------------------------
+    if (dwarf::DW_OP_breg0 <= Code && Code <= dwarf::DW_OP_breg31) {
+      std::string RegisterName(getReader().getRegisterName(Code, Operands));
+      Stream << format("breg%d+%d%s", Code - dwarf::DW_OP_breg0, Operands[0],
+                       RegisterName.c_str());
+      return;
+    }
+
+    //-----------------------------------------------------------------------
+    // 2.6.1.1.3 Register location descriptions.
+    //-----------------------------------------------------------------------
+    if (dwarf::DW_OP_reg0 <= Code && Code <= dwarf::DW_OP_reg31) {
+      std::string RegisterName(getReader().getRegisterName(Code, Operands));
+      Stream << format("reg%d%s", Code - dwarf::DW_OP_reg0,
+                       RegisterName.c_str());
+      return;
+    }
+
+    Stream << format("#0x%02x ", Code) << hexString(Operands[0]) << " "
+           << hexString(Operands[1]) << "#";
+  };
+
+  switch (Opcode) {
+  //-------------------------------------------------------------------------
+  // 2.5.1.1 Literal encodings.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_addr:
+    Stream << "addr " << hexString(Operands[0]);
+    break;
+  case dwarf::DW_OP_constu:
+  case dwarf::DW_OP_const1u:
+  case dwarf::DW_OP_const2u:
+  case dwarf::DW_OP_const4u:
+  case dwarf::DW_OP_const8u:
+    Stream << "const_u " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_consts:
+  case dwarf::DW_OP_const1s:
+  case dwarf::DW_OP_const2s:
+  case dwarf::DW_OP_const4s:
+  case dwarf::DW_OP_const8s:
+    Stream << "const_s " << int(Operands[0]);
+    break;
+  case dwarf::DW_OP_addrx:
+    Stream << "addrx " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_constx:
+    Stream << "constx " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_const_type:
+    Stream << "TODO: DW_OP_const_type";
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.5.1.2 Register values.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_fbreg:
+    Stream << "fbreg " << int(Operands[0]);
+    break;
+  case dwarf::DW_OP_bregx: {
+    std::string RegisterName(getReader().getRegisterName(Opcode, Operands));
+    Stream << format("bregx %d%s+%d", Operands[0], RegisterName.c_str(),
+                     unsigned(Operands[1]));
+    break;
+  }
+  case dwarf::DW_OP_regval_type: {
+    std::string RegisterName(getReader().getRegisterName(Opcode, Operands));
+    Stream << format("regval_type %d%s+%d", Operands[0], RegisterName.c_str(),
+                     unsigned(Operands[1]));
+    break;
+  }
+
+  //-------------------------------------------------------------------------
+  // 2.5.1.3 Stack operations.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_dup:
+    Stream << "dup";
+    break;
+  case dwarf::DW_OP_drop:
+    Stream << "drop";
+    break;
+  case dwarf::DW_OP_pick:
+    Stream << "pick " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_over:
+    Stream << "over";
+    break;
+  case dwarf::DW_OP_swap:
+    Stream << "swap";
+    break;
+  case dwarf::DW_OP_rot:
+    Stream << "rot";
+    break;
+  case dwarf::DW_OP_deref:
+    Stream << "deref";
+    break;
+  case dwarf::DW_OP_deref_size:
+    Stream << "deref_size " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_deref_type:
+    Stream << "deref_type " << unsigned(Operands[0]) << " DIE offset "
+           << hexString(Operands[1]);
+    break;
+  case dwarf::DW_OP_xderef:
+    Stream << "xderef";
+    break;
+  case dwarf::DW_OP_xderef_size:
+    Stream << "xderef_size " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_xderef_type:
+    Stream << "xderef_type " << unsigned(Operands[0]) << " DIE offset "
+           << hexString(Operands[1]);
+    break;
+  case dwarf::DW_OP_push_object_address:
+    Stream << "push_object_address";
+    break;
+  case dwarf::DW_OP_form_tls_address:
+    Stream << "form_tls_address " << hexString(Operands[0]);
+    break;
+  case dwarf::DW_OP_call_frame_cfa:
+    Stream << "call_frame_cfa";
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.5.1.4 Arithmetic and Logical Operations.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_abs:
+    Stream << "abs";
+    break;
+  case dwarf::DW_OP_and:
+    Stream << "and";
+    break;
+  case dwarf::DW_OP_div:
+    Stream << "div";
+    break;
+  case dwarf::DW_OP_minus:
+    Stream << "minus";
+    break;
+  case dwarf::DW_OP_mod:
+    Stream << "mod";
+    break;
+  case dwarf::DW_OP_mul:
+    Stream << "mul";
+    break;
+  case dwarf::DW_OP_neg:
+    Stream << "neg";
+    break;
+  case dwarf::DW_OP_not:
+    Stream << "not";
+    break;
+  case dwarf::DW_OP_or:
+    Stream << "or";
+    break;
+  case dwarf::DW_OP_plus:
+    Stream << "plus";
+    break;
+  case dwarf::DW_OP_plus_uconst:
+    Stream << "plus_uconst " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_shl:
+    Stream << "shl";
+    break;
+  case dwarf::DW_OP_shr:
+    Stream << "shr";
+    break;
+  case dwarf::DW_OP_shra:
+    Stream << "shra";
+    break;
+  case dwarf::DW_OP_xor:
+    Stream << "xor";
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.5.1.5 Control Flow Operations.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_le:
+    Stream << "le";
+    break;
+  case dwarf::DW_OP_ge:
+    Stream << "ge";
+    break;
+  case dwarf::DW_OP_eq:
+    Stream << "eq";
+    break;
+  case dwarf::DW_OP_lt:
+    Stream << "lt";
+    break;
+  case dwarf::DW_OP_gt:
+    Stream << "gt";
+    break;
+  case dwarf::DW_OP_ne:
+    Stream << "ne";
+    break;
+  case dwarf::DW_OP_skip:
+    Stream << "skip " << signed(Operands[0]);
+    break;
+  case dwarf::DW_OP_bra:
+    Stream << "bra " << signed(Operands[0]);
+    break;
+  case dwarf::DW_OP_call2:
+    Stream << "call2 DIE offset " << hexString(Operands[0]);
+    break;
+  case dwarf::DW_OP_call4:
+    Stream << "call4 DIE offset " << hexString(Operands[0]);
+    break;
+  case dwarf::DW_OP_call_ref:
+    Stream << "call_ref DIE offset " << hexString(Operands[0]);
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.5.1.6 Type Conversions.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_convert:
+    Stream << "convert DIE offset " << hexString(Operands[0]);
+    break;
+  case dwarf::DW_OP_reinterpret:
+    Stream << "reinterpret DIE offset " << hexString(Operands[0]);
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.5.1.7 Special Operations.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_nop:
+    Stream << "nop";
+    break;
+  case dwarf::DW_OP_entry_value:
+    Stream << "TODO: DW_OP_entry_value";
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.6.1.1.3 Register location descriptions.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_regx:
+    Stream << "regx" << getReader().getRegisterName(Opcode, Operands);
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.6.1.1.4 Implicit location descriptions.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_stack_value:
+    Stream << "stack_value";
+    break;
+  case dwarf::DW_OP_implicit_value:
+    Stream << "TODO: DW_OP_implicit_value";
+    break;
+  case dwarf::DW_OP_implicit_pointer:
+    Stream << "implicit_pointer DIE offset " << hexString(Operands[0]) << " "
+           << int(Operands[1]);
+    break;
+
+  //-------------------------------------------------------------------------
+  // 2.6.1.2 Composite location descriptions.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_piece:
+    Stream << "piece " << int(Operands[0]);
+    break;
+  case dwarf::DW_OP_bit_piece:
+    Stream << "bit_piece " << int(Operands[0]) << " offset "
+           << int(Operands[1]);
+    break;
+
+  //-------------------------------------------------------------------------
+  // GNU extensions.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_GNU_entry_value:
+    Stream << "gnu_entry_value ";
+    PrintRegisterInfo(dwarf::DW_OP_reg0);
+    break;
+  case dwarf::DW_OP_GNU_push_tls_address:
+    Stream << "gnu_push_tls_address " << hexString(Operands[0]);
+    break;
+  case dwarf::DW_OP_GNU_addr_index:
+    Stream << "gnu_addr_index " << unsigned(Operands[0]);
+    break;
+  case dwarf::DW_OP_GNU_const_index:
+    Stream << "gnu_const_index " << unsigned(Operands[0]);
+    break;
+
+  //-------------------------------------------------------------------------
+  // Member location.
+  //-------------------------------------------------------------------------
+  case LVLocationMemberOffset:
+    Stream << "offset " << int(Operands[0]);
+    break;
+
+  //-------------------------------------------------------------------------
+  // Missing location.
+  //-------------------------------------------------------------------------
+  case dwarf::DW_OP_hi_user:
+    Stream << "missing";
+    break;
+
+  //-------------------------------------------------------------------------
+  // Register values.
+  //-------------------------------------------------------------------------
+  default:
+    PrintRegisterInfo(Opcode);
+    break;
+  }
+
+  return String;
+}
+
+// Identify the most common type of operations and print them using a high
+// level format, trying to isolate the CodeView complexity.
+std::string LVOperation::getOperandsCodeViewInfo() {
+  std::string String;
+  raw_string_ostream Stream(String);
+
+  // Get original CodeView operation code.
+  uint16_t OperationCode = updateOperationCode(Opcode);
+
+  switch (OperationCode) {
+  // Operands: [Offset, 0].
+  case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
+    Stream << "frame_pointer_rel " << int(Operands[0]);
+    break;
+  case codeview::SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+    Stream << "frame_pointer_rel_full_scope " << int(Operands[0]);
+    break;
+
+  // Operands: [Register, 0].
+  case codeview::SymbolKind::S_DEFRANGE_REGISTER:
+    Stream << "register " << getReader().getRegisterName(Opcode, Operands);
+    break;
+  case codeview::SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
+    Stream << "subfield_register "
+           << getReader().getRegisterName(Opcode, Operands);
+    break;
+
+  // Operands: [Register, Offset].
+  case codeview::SymbolKind::S_DEFRANGE_REGISTER_REL:
+    Stream << "register_rel " << getReader().getRegisterName(Opcode, Operands)
+           << " offset " << int(Operands[1]);
+    break;
+
+  // Operands: [Program, 0].
+  case codeview::SymbolKind::S_DEFRANGE:
+    Stream << "frame " << int(Operands[0]);
+    break;
+  case codeview::SymbolKind::S_DEFRANGE_SUBFIELD:
+    Stream << "subfield " << int(Operands[0]);
+    break;
+
+  default:
+    Stream << format("#0x%02x: ", Opcode) << hexString(Operands[0]) << " "
+           << hexString(Operands[1]) << "#";
+    break;
+  }
+
+  return String;
+}
+
+namespace {
+const char *const KindBaseClassOffset = "BaseClassOffset";
+const char *const KindBaseClassStep = "BaseClassStep";
+const char *const KindClassOffset = "ClassOffset";
+const char *const KindFixedAddress = "FixedAddress";
+const char *const KindMissingInfo = "Missing";
+const char *const KindOperation = "Operation";
+const char *const KindOperationList = "OperationList";
+const char *const KindRegister = "Register";
+const char *const KindUndefined = "Undefined";
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// DWARF location information.
+//===----------------------------------------------------------------------===//
+const char *LVLocation::kind() const {
+  const char *Kind = KindUndefined;
+  if (getIsBaseClassOffset())
+    Kind = KindBaseClassOffset;
+  else if (getIsBaseClassStep())
+    Kind = KindBaseClassStep;
+  else if (getIsClassOffset())
+    Kind = KindClassOffset;
+  else if (getIsFixedAddress())
+    Kind = KindFixedAddress;
+  else if (getIsGapEntry())
+    Kind = KindMissingInfo;
+  else if (getIsOperation())
+    Kind = KindOperation;
+  else if (getIsOperationList())
+    Kind = KindOperationList;
+  else if (getIsRegister())
+    Kind = KindRegister;
+  return Kind;
+}
+
+std::string LVLocation::getIntervalInfo() const {
+  static const char *const Question = "?";
+  std::string String;
+  raw_string_ostream Stream(String);
+  if (getIsAddressRange())
+    Stream << "{Range}";
+
+  auto PrintLine = [&](const LVLine *Line) {
+    if (Line) {
+      std::string TheLine;
+      TheLine = Line->lineNumberAsStringStripped();
+      Stream << TheLine.c_str();
+    } else {
+      Stream << Question;
+    }
+  };
+
+  Stream << " Lines ";
+  PrintLine(getLowerLine());
+  Stream << ":";
+  PrintLine(getUpperLine());
+
+  if (options().getAttributeOffset())
+    // Print the active range (low pc and high pc).
+    Stream << " [" << hexString(getLowerAddress()) << ":"
+           << hexString(getUpperAddress()) << "]";
+
+  return String;
+}
+
+// Validate the ranges associated with the location.
+bool LVLocation::validateRanges() {
+  // Traverse the locations and validate them against the address to line
+  // mapping in the current compile unit. Record those invalid ranges.
+  // A valid range must meet the following conditions:
+  // a) line(lopc) <= line(hipc)
+  // b) line(lopc) and line(hipc) are valid.
+
+  if (!hasAssociatedRange())
+    return true;
+
+  LVScopeCompileUnit *Scope = getReader().getCompileUnit();
+  LVLine *LowLine = Scope->lineLowerBound(getLowerAddress());
+  LVLine *HighLine = Scope->lineUpperBound(getUpperAddress());
+  if (LowLine)
+    setLowerLine(LowLine);
+  else {
+    setIsInvalidLower();
+    return false;
+  }
+  if (HighLine)
+    setUpperLine(HighLine);
+  else {
+    setIsInvalidUpper();
+    return false;
+  }
+  // Check for a valid interval.
+  if (LowLine->getLineNumber() > HighLine->getLineNumber()) {
+    setIsInvalidRange();
+    return false;
+  }
+
+  return true;
+}
+
+bool LVLocation::calculateCoverage(LVLocations *Locations, unsigned &Factor,
+                                   float &Percentage) {
+  if (!options().getAttributeCoverage() && !Locations)
+    return false;
+
+  // Calculate the coverage depending on the kind of location. We have
+  // the simple and composed locations.
+  if (Locations->size() == 1) {
+    // Simple: fixed address, class offset, stack offset.
+    LVLocation *Location = Locations->front();
+    // Some types of locations do not have specific kind. Now is the time
+    // to set those types, depending on the operation type.
+    Location->updateKind();
+    if (Location->getIsLocationSimple()) {
+      Factor = 100;
+      Percentage = 100;
+      return true;
+    }
+  }
+
+  // Composed locations.
+  LVAddress LowerAddress = 0;
+  LVAddress UpperAddress = 0;
+  for (const LVLocation *Location : *Locations)
+    // Do not include locations representing a gap.
+    if (!Location->getIsGapEntry()) {
+      LowerAddress = Location->getLowerAddress();
+      UpperAddress = Location->getUpperAddress();
+      Factor += (UpperAddress > LowerAddress) ? UpperAddress - LowerAddress
+                                              : LowerAddress - UpperAddress;
+    }
+
+  Percentage = 0;
+  return false;
+}
+
+void LVLocation::printRaw(raw_ostream &OS, bool Full) const {
+  // Print the active range (low pc and high pc).
+  OS << " [" << hexString(getLowerAddress()) << ":"
+     << hexString(getUpperAddress()) << "]\n";
+  // Print any DWARF operations.
+  printRawExtra(OS, Full);
+}
+
+void LVLocation::printInterval(raw_ostream &OS, bool Full) const {
+  if (hasAssociatedRange())
+    OS << getIntervalInfo();
+}
+
+void LVLocation::print(raw_ostream &OS, bool Full) const {
+  if (getReader().doPrintLocation(this)) {
+    LVObject::print(OS, Full);
+    printExtra(OS, Full);
+  }
+}
+
+void LVLocation::printExtra(raw_ostream &OS, bool Full) const {
+  printInterval(OS, Full);
+  OS << "\n";
+}
+
+//===----------------------------------------------------------------------===//
+// DWARF location for a symbol.
+//===----------------------------------------------------------------------===//
+// Add a Location Entry.
+void LVLocationSymbol::addObject(LVAddress LowPC, LVAddress HighPC,
+                                 LVUnsigned SectionOffset,
+                                 uint64_t LocDescOffset) {
+  setLowerAddress(LowPC);
+  setUpperAddress(HighPC);
+
+  // Record the offset where the location information begins.
+  setOffset(LocDescOffset ? LocDescOffset : SectionOffset);
+
+  // A -1 HighPC value, indicates no range.
+  if (HighPC == LVAddress(UINT64_MAX))
+    setIsDiscardedRange();
+
+  // Update the location kind, using the DWARF attribute.
+  setKind();
+}
+
+// Add a Location Record.
+void LVLocationSymbol::addObject(LVSmall Opcode, LVUnsigned Operand1,
+                                 LVUnsigned Operand2) {
+  if (!Entries)
+    Entries = new LVAutoOperations();
+  Entries->emplace_back(new LVOperation(Opcode, Operand1, Operand2));
+}
+
+// Based on the DWARF attribute, define the location kind.
+void LVLocation::setKind() {
+  switch (getAttr()) {
+  case dwarf::DW_AT_data_member_location:
+    setIsClassOffset();
+    break;
+  case dwarf::DW_AT_location:
+    // Depending on the operand, we have a fixed address.
+    setIsFixedAddress();
+    break;
+  default:
+    break;
+  }
+  // For those symbols with absolute location information, ignore any
+  // gaps in their location description; that is the case with absolute
+  // memory addresses and members located at specific offsets.
+  if (hasAssociatedRange())
+    getParentSymbol()->setFillGaps();
+}
+
+void LVLocationSymbol::updateKind() {
+  // Update the location type for simple ones.
+  if (Entries && Entries->size() == 1) {
+    LVOperation *Operation = Entries->front();
+    if (dwarf::DW_OP_fbreg == Operation->getOpcode())
+      setIsStackOffset();
+  }
+}
+
+void LVLocationSymbol::printRawExtra(raw_ostream &OS, bool Full) const {
+  if (Entries)
+    for (const LVOperation *Operation : *Entries)
+      Operation->print(OS, Full);
+}
+
+// Print location (formatted version).
+void LVLocation::print(LVLocations *Locations, raw_ostream &OS, bool Full) {
+  assert(Locations && "Locations must not be nullptr");
+  // Print the symbol coverage.
+  if (Locations && !Locations->empty() && options().getAttributeCoverage()) {
+    assert(!Locations->empty() && "Locations must have at least one element");
+    // The location entries are contained within a symbol. Get a location,
+    // to access basic information about indentation, parent, etc.
+    LVLocation *Location = Locations->front();
+    LVSymbol *Symbol = Location->getParentSymbol();
+    float Percentage = Symbol->getCoveragePercentage();
+
+    // The coverage is dependent on the kind of location.
+    std::string String;
+    raw_string_ostream Stream(String);
+    Stream << format("%.2f%%", Percentage);
+    if (!Location->getIsLocationSimple())
+      Stream << format(" (%d/%d)", Symbol->getCoverageFactor(),
+                       Symbol->getParentScope()->getCoverageFactor());
+    Symbol->printAttributes(OS, Full, "{Coverage} ", Symbol, StringRef(String),
+                            /*UseQuotes=*/false,
+                            /*PrintRef=*/false);
+  }
+
+  // Print the symbol location, including the missing entries.
+  if (Locations && getReader().doPrintLocation(/*Location=*/nullptr))
+    for (const LVLocation *Location : *Locations)
+      Location->print(OS, Full);
+}
+
+void LVLocationSymbol::printExtra(raw_ostream &OS, bool Full) const {
+  OS << "{Location}";
+  if (getIsCallSite())
+    OS << " -> CallSite";
+  printInterval(OS, Full);
+  OS << "\n";
+
+  // Print location entries.
+  if (Full && Entries) {
+    bool CodeViewLocation = getParentSymbol()->getHasCodeViewLocation();
+    std::stringstream Stream;
+    std::string Leading = "";
+    for (LVOperation *Operation : *Entries) {
+      Stream << Leading
+             << (CodeViewLocation ? Operation->getOperandsCodeViewInfo()
+                                  : Operation->getOperandsDWARFInfo());
+      Leading = ", ";
+    }
+    printAttributes(OS, Full, "{Entry} ", const_cast<LVLocationSymbol *>(this),
+                    StringRef(Stream.str()),
+                    /*UseQuotes=*/false,
+                    /*PrintRef=*/false);
+  }
+}
Index: llvm/lib/DebugInfo/LogicalView/Core/LVRange.cpp
===================================================================
--- /dev/null
+++ llvm/lib/DebugInfo/LogicalView/Core/LVRange.cpp
@@ -0,0 +1,151 @@
+//===-- LVRange.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 LVRange class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVRange.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Range"
+
+void LVRange::startSearch() {
+  RangesTree.clear();
+
+  LLVM_DEBUG({ dbgs() << "\nRanges Tree:\n"; });
+
+  // Traverse the ranges and store them into the interval tree.
+  for (LVRangeEntry &RangeEntry : RangeEntries) {
+    LLVM_DEBUG({
+      LVScope *Scope = RangeEntry.scope();
+      dbgs() << "Scope: " << format_decimal(Scope->getLevel(), 5) << " "
+              << "Range: [" << hexValue(RangeEntry.lower()) << ":"
+              << hexValue(RangeEntry.upper()) << "]\n";
+    });
+
+    RangesTree.insert(RangeEntry.lower(), RangeEntry.upper(),
+                      RangeEntry.scope());
+  }
+
+  // Create the interval tree.
+  RangesTree.create();
+
+  LLVM_DEBUG({
+    dbgs() << "\nRanges Tree:\n";
+    RangesTree.print(dbgs());
+  });
+}
+
+// Add the pair in an ascending order, with the smallest ranges at the
+// start; in that way, enclosing scopes ranges are at the end of the
+// list; we assume that low <= high.
+void LVRange::addEntry(LVScope *Scope, LVAddress LowerAddress,
+                       LVAddress UpperAddress) {
+  // We assume the low <= high.
+  if (LowerAddress > UpperAddress)
+    std::swap(LowerAddress, UpperAddress);
+
+  // Record the lowest and highest seen addresses.
+  if (LowerAddress < Lower)
+    Lower = LowerAddress;
+  if (UpperAddress > Upper)
+    Upper = UpperAddress;
+
+  // Just add the scope and range pair, in no particular order.
+  RangeEntries.emplace_back(LowerAddress, UpperAddress, Scope);
+}
+
+void LVRange::addEntry(LVScope *Scope) {
+  assert(Scope && "Scope must not be nullptr");
+  // Traverse the ranges and update the ranges set only if the ranges
+  // values are not already recorded.
+  if (const LVLocations *Locations = Scope->getRanges())
+    for (const LVLocation *Location : *Locations) {
+      LVAddress LowPC = Location->getLowerAddress();
+      LVAddress HighPC = Location->getUpperAddress();
+      if (!findEntry(LowPC, HighPC))
+        // Add the pair of addresses.
+        addEntry(Scope, LowPC, HighPC);
+    }
+}
+
+// Get the scope associated with the input address.
+LVScope *LVRange::getEntry(LVAddress Address) const {
+  LLVM_DEBUG({ dbgs() << format("Searching: 0x%08x\nFound: ", Address); });
+
+  LVScope *Target = nullptr;
+  LVLevel TargetLevel = 0;
+  LVLevel Level = 0;
+  LVScope *Scope = nullptr;
+  for (LVRangesTree::find_iterator Iter = RangesTree.find(Address),
+                                   End = RangesTree.find_end();
+       Iter != End; ++Iter) {
+    LLVM_DEBUG(
+        { dbgs() << format("[0x%08x,0x%08x] ", Iter->left(), Iter->right()); });
+    Scope = Iter->value();
+    Level = Scope->getLevel();
+    if (Level > TargetLevel) {
+      TargetLevel = Level;
+      Target = Scope;
+    }
+  }
+
+  LLVM_DEBUG({ dbgs() << (Scope ? "\n" : "None\n"); });
+
+  return Target;
+}
+
+// Find the associated Scope for the given ranges values.
+LVScope *LVRange::getEntry(LVAddress LowerAddress,
+                           LVAddress UpperAddress) const {
+  for (const LVRangeEntry &RangeEntry : RangeEntries)
+    if (LowerAddress >= RangeEntry.lower() && UpperAddress < RangeEntry.upper())
+      return RangeEntry.scope();
+  return nullptr;
+}
+
+// Find the associated Scope for the given ranges values.
+bool LVRange::findEntry(LVAddress LowerAddress, LVAddress UpperAddress) const {
+  for (const LVRangeEntry &RangeEntry : RangeEntries)
+    if (LowerAddress == RangeEntry.lower() &&
+        UpperAddress == RangeEntry.upper())
+      return true;
+  return false;
+}
+
+// Sort the range elements for the whole Compile Unit.
+void LVRange::sort() {
+  auto CompareRangeEntry = [](const LVRangeEntry &lhs,
+                              const LVRangeEntry &rhs) -> bool {
+    return (lhs.lower() < rhs.lower());
+  };
+
+  // Sort the ranges using low address and range size.
+  std::stable_sort(RangeEntries.begin(), RangeEntries.end(), CompareRangeEntry);
+}
+
+void LVRange::print(raw_ostream &OS, bool Full) const {
+  size_t Indentation = 0;
+  for (const LVRangeEntry &RangeEntry : RangeEntries) {
+    LVScope *Scope = RangeEntry.scope();
+    Scope->printAttributes(OS, Full);
+    Indentation = options().indentationSize();
+    if (Indentation)
+      OS << " ";
+    OS << format("[0x%08x,0x%08x] ", RangeEntry.lower(), RangeEntry.upper())
+       << formattedKind(Scope->kind()) << " " << formattedName(Scope->getName())
+       << "\n";
+  }
+  printExtra(OS, Full);
+}
Index: llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
===================================================================
--- llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
@@ -13,7 +13,6 @@
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
-#include "llvm/Support/Error.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/FormatAdapters.h"
 #include "llvm/Support/FormatVariadic.h"
@@ -134,6 +133,9 @@
   if (Error Err = createScopes())
     return Err;
 
+  // Calculate symbol coverage and detect invalid debug locations and ranges.
+  Root->processRangeInformation();
+
   // As the elements can depend on elements from a different compile unit,
   // information such as name and file/line source information needs to be
   // updated.
Index: llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
===================================================================
--- llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
@@ -12,7 +12,8 @@
 
 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
-#include "llvm/DebugInfo/LogicalView/Core/LVOptions.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVRange.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVType.h"
@@ -48,6 +49,7 @@
   delete Symbols;
   delete Scopes;
   delete Lines;
+  delete Ranges;
   delete Children;
 }
 
@@ -129,6 +131,21 @@
   traverseParents(&LVScope::getHasLines, &LVScope::setHasLines);
 }
 
+// Add a location.
+void LVScope::addObject(LVLocation *Location) {
+  assert(Location && "Invalid location.");
+  assert(!Location->getParent() && "Location already inserted");
+  if (!Ranges)
+    Ranges = new LVAutoLocations();
+
+  // Add it to parent.
+  Location->setParent(this);
+  Location->setOffset(getOffset());
+
+  Ranges->push_back(Location);
+  setHasRanges();
+}
+
 // Adds the scope to the child scopes and sets the parent in the child.
 void LVScope::addElement(LVScope *Scope) {
   assert(Scope && "Invalid scope.");
@@ -210,6 +227,17 @@
   traverseParents(&LVScope::getHasTypes, &LVScope::setHasTypes);
 }
 
+// Add a pair of ranges.
+void LVScope::addObject(LVAddress LowerAddress, LVAddress UpperAddress) {
+  // Pack the ranges into a Location object.
+  LVLocation *Location = new LVLocation();
+  Location->setLowerAddress(LowerAddress);
+  Location->setUpperAddress(UpperAddress);
+  Location->setIsAddressRange();
+
+  addObject(Location);
+}
+
 bool LVScope::removeElement(LVElement *Element) {
   auto Predicate = [Element](LVElement *Item) -> bool {
     return Item == Element;
@@ -618,6 +646,7 @@
           Traverse(Parent->Types, SortFunction);
           Traverse(Parent->Symbols, SortFunction);
           Traverse(Parent->Scopes, SortFunction);
+          Traverse(Parent->Ranges, compareRange);
           Traverse(Parent->Children, SortFunction);
 
           if (Parent->Scopes)
@@ -679,6 +708,76 @@
     TraverseChildren(this);
 }
 
+// Get all the locations associated with symbols.
+void LVScope::getLocations(LVLocations &LocationList,
+                           LVValidLocation ValidLocation, bool RecordInvalid) {
+  // Traverse scopes and symbols.
+  if (Symbols)
+    for (LVSymbol *Symbol : *Symbols)
+      Symbol->getLocations(LocationList, ValidLocation, RecordInvalid);
+  if (Scopes)
+    for (LVScope *Scope : *Scopes)
+      Scope->getLocations(LocationList, ValidLocation, RecordInvalid);
+}
+
+// Get all the ranges associated with scopes.
+void LVScope::getRanges(LVLocations &LocationList,
+                        LVValidLocation ValidLocation, bool RecordInvalid) {
+  // Ignore discarded or stripped scopes (functions).
+  if (getIsDiscarded())
+    return;
+
+  // Process the ranges for current scope.
+  if (Ranges) {
+    for (LVLocation *Location : *Ranges) {
+      // Add the invalid location object.
+      if (!(Location->*ValidLocation)() && RecordInvalid)
+        LocationList.push_back(Location);
+    }
+
+    // Calculate coverage factor.
+    calculateCoverage();
+  }
+
+  // Traverse the scopes.
+  if (Scopes)
+    for (LVScope *Scope : *Scopes)
+      Scope->getRanges(LocationList, ValidLocation, RecordInvalid);
+}
+
+// Get all the ranges associated with scopes.
+void LVScope::getRanges(LVRange &RangeList) {
+  // Ignore discarded or stripped scopes (functions).
+  if (getIsDiscarded())
+    return;
+
+  if (Ranges)
+    RangeList.addEntry(this);
+  if (Scopes)
+    for (LVScope *Scope : *Scopes)
+      Scope->getRanges(RangeList);
+}
+
+LVScope *LVScope::outermostParent(LVAddress Address) {
+  LVScope *Parent = this;
+  while (Parent) {
+    if (Ranges)
+      for (const LVLocation *Location : *Ranges)
+        if (Location->getLowerAddress() <= Address)
+          return Parent;
+    Parent = Parent->getParentScope();
+  }
+  return Parent;
+}
+
+void LVScope::printActiveRanges(raw_ostream &OS, bool Full) {
+  if (options().getPrintFormatting() && options().getAttributeRange() &&
+      Ranges) {
+    for (const LVLocation *Location : *Ranges)
+      Location->print(OS, Full);
+  }
+}
+
 void LVScope::printEncodedArgs(raw_ostream &OS, bool Full) const {
   if (options().getPrintFormatting() && options().getAttributeEncoded())
     printAttributes(OS, Full, "{Encoded} ", const_cast<LVScope *>(this),
@@ -705,6 +804,10 @@
          << formattedNames(getTypeQualifiedName(), typeAsString());
   }
   OS << "\n";
+
+  // Print any active ranges.
+  if (Full && getIsBlock())
+    printActiveRanges(OS, Full);
 }
 
 //===----------------------------------------------------------------------===//
@@ -829,6 +932,24 @@
     CUContributionSize = Size;
 }
 
+void LVScopeCompileUnit::processRangeLocationCoverage(
+    LVValidLocation ValidLocation) {
+
+  if (options().getAttributeRange()) {
+    // Traverse the scopes to get scopes that have invalid ranges.
+    LVLocations Locations;
+    bool RecordInvalid = false;
+    getRanges(Locations, ValidLocation, RecordInvalid);
+  }
+
+  if (options().getAttributeLocation()) {
+    // Traverse the scopes to get locations that have invalid ranges.
+    LVLocations Locations;
+    bool RecordInvalid = false;
+    getLocations(Locations, ValidLocation, RecordInvalid);
+  }
+}
+
 LVLine *LVScopeCompileUnit::lineLowerBound(LVAddress Address) const {
   LVAddressToLine::const_iterator Iter = AddressToLine.lower_bound(Address);
   return (Iter != AddressToLine.end()) ? Iter->second : nullptr;
@@ -1102,9 +1223,10 @@
   // Reset file index, to allow its children to print the correct filename.
   options().resetFilenameIndex();
 
-  // Print any files, directories, public names.
+  // Print any files, directories, public names and active ranges.
   if (Full) {
     printLocalNames(OS, Full);
+    printActiveRanges(OS, Full);
   }
 }
 
@@ -1209,6 +1331,7 @@
   if (Full) {
     if (getIsTemplateResolved())
       printEncodedArgs(OS, Full);
+    printActiveRanges(OS, Full);
     if (Reference)
       Reference->printReference(OS, Full, const_cast<LVScopeFunction *>(this));
   }
@@ -1268,12 +1391,31 @@
 void LVScopeNamespace::printExtra(raw_ostream &OS, bool Full) const {
   OS << formattedKind(kind()) << " " << formattedName(getName()) << "\n";
 
+  // Print any active ranges.
   if (Full) {
+    printActiveRanges(OS, Full);
+
     if (LVScope *Reference = getReference())
       Reference->printReference(OS, Full, const_cast<LVScopeNamespace *>(this));
   }
 }
 
+//===----------------------------------------------------------------------===//
+// An object file (single or multiple CUs).
+//===----------------------------------------------------------------------===//
+void LVScopeRoot::processRangeInformation() {
+  if (!options().getAttributeAnyLocation())
+    return;
+
+  if (Scopes)
+    for (LVScope *Scope : *Scopes) {
+      LVScopeCompileUnit *CompileUnit =
+          static_cast<LVScopeCompileUnit *>(Scope);
+      getReader().setCompileUnit(CompileUnit);
+      CompileUnit->processRangeLocationCoverage();
+    }
+}
+
 void LVScopeRoot::print(raw_ostream &OS, bool Full) const {
   OS << "\nLogical View:\n";
   LVScope::print(OS, Full);
Index: llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
===================================================================
--- llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
+++ llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
@@ -47,6 +47,20 @@
   return LHS->getOffset() < RHS->getOffset();
 }
 
+// Callback comparator for Range compare.
+LVSortValue llvm::logicalview::compareRange(const LVObject *LHS,
+                                            const LVObject *RHS) {
+  if (LHS->getLowerAddress() < RHS->getLowerAddress())
+    return true;
+
+  // If the lower address is the same, use the upper address value in
+  // order to put first the smallest interval.
+  if (LHS->getLowerAddress() == RHS->getLowerAddress())
+    return LHS->getUpperAddress() < RHS->getUpperAddress();
+
+  return false;
+}
+
 // Callback comparator based on multiple keys (First: Kind).
 LVSortValue llvm::logicalview::sortByKind(const LVObject *LHS,
                                           const LVObject *RHS) {
Index: llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
===================================================================
--- llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
+++ llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVLocation.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
 #include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
 
@@ -50,6 +51,161 @@
   return Kind;
 }
 
+// Add a Location Entry.
+void LVSymbol::addLocation(dwarf::Attribute Attr, LVAddress LowPC,
+                           LVAddress HighPC, LVUnsigned SectionOffset,
+                           uint64_t LocDescOffset, bool CallSiteLocation) {
+  if (!Locations)
+    Locations = new LVAutoLocations();
+
+  // Create the location entry.
+  CurrentLocation = new LVLocationSymbol();
+  CurrentLocation->setParent(this);
+  CurrentLocation->setAttr(Attr);
+  if (CallSiteLocation)
+    CurrentLocation->setIsCallSite();
+  CurrentLocation->addObject(LowPC, HighPC, SectionOffset, LocDescOffset);
+  Locations->push_back(CurrentLocation);
+
+  // Mark the symbol as having location information.
+  setHasLocation();
+}
+
+// Add a Location Record.
+void LVSymbol::addLocationOperands(LVSmall Opcode, uint64_t Operand1,
+                                   uint64_t Operand2) {
+  if (CurrentLocation)
+    CurrentLocation->addObject(Opcode, Operand1, Operand2);
+}
+
+// Add a Location Entry.
+void LVSymbol::addLocationConstant(dwarf::Attribute Attr, LVUnsigned Constant,
+                                   uint64_t LocDescOffset) {
+  // Create a Location Entry, with the global information.
+  addLocation(Attr,
+              /*LowPC=*/0, /*HighPC=*/-1,
+              /*SectionOffset=*/0, LocDescOffset);
+
+  // Add records to Location Entry.
+  addLocationOperands(/*Opcode=*/LVLocationMemberOffset,
+                      /*Operand1=*/Constant, /*Operand2=*/0);
+}
+
+LVLocations::iterator LVSymbol::addLocationGap(LVLocations::iterator Pos,
+                                               LVAddress LowPC,
+                                               LVAddress HighPC) {
+  // Create a location entry for the gap.
+  LVLocation *Gap = new LVLocationSymbol();
+  Gap->setParent(this);
+  Gap->setAttr(dwarf::DW_AT_location);
+  Gap->addObject(LowPC, HighPC,
+                 /*section_offset=*/0,
+                 /*locdesc_offset=*/0);
+
+  LVLocations::iterator Iter = Locations->insert(Pos, Gap);
+
+  // Add gap to Location Entry.
+  Gap->addObject(/*op=*/dwarf::DW_OP_hi_user,
+                 /*opd1=*/0, /*opd2=*/0);
+
+  // Mark the entry as a gap.
+  Gap->setIsGapEntry();
+
+  return Iter;
+}
+
+void LVSymbol::fillLocationGaps() {
+  // The symbol has locations records. Fill gaps in the location list.
+  if (!getHasLocation() || !getFillGaps())
+    return;
+
+  // Get the parent range information and add dummy location entries.
+  const LVLocations *Ranges = getParentScope()->getRanges();
+  if (!Ranges)
+    return;
+
+  for (const LVLocation *Entry : *Ranges) {
+    LVAddress ParentLowPC = Entry->getLowerAddress();
+    LVAddress ParentHighPC = Entry->getUpperAddress();
+
+    // Traverse the symbol locations and for each location contained in
+    // the current parent range, insert locations for any existing gap.
+    LVLocation *Location;
+    LVAddress LowPC = 0;
+    LVAddress Marker = ParentLowPC;
+    for (LVLocations::iterator Iter = Locations->begin();
+         Iter != Locations->end(); ++Iter) {
+      Location = *Iter;
+      LowPC = Location->getLowerAddress();
+      if (LowPC != Marker) {
+        // We have a gap at [Marker,LowPC - 1].
+        Iter = addLocationGap(Iter, Marker, LowPC - 1);
+        ++Iter;
+      }
+
+      // Move to the next item in the location list.
+      Marker = Location->getUpperAddress() + 1;
+    }
+
+    // Check any gap at the end.
+    if (Marker < ParentHighPC)
+      // We have a gap at [Marker,ParentHighPC].
+      addLocationGap(Locations->end(), Marker, ParentHighPC);
+  }
+}
+
+// Get all the locations based on the valid function.
+void LVSymbol::getLocations(LVLocations &LocationList,
+                            LVValidLocation ValidLocation, bool RecordInvalid) {
+  if (!Locations)
+    return;
+
+  for (LVLocation *Location : *Locations) {
+    // Add the invalid location object.
+    if (!(Location->*ValidLocation)() && RecordInvalid)
+      LocationList.push_back(Location);
+  }
+
+  // Calculate coverage factor.
+  calculateCoverage();
+}
+
+void LVSymbol::getLocations(LVLocations &LocationList) const {
+  if (!Locations)
+    return;
+
+  for (LVLocation *Location : *Locations)
+    LocationList.push_back(Location);
+}
+
+// Calculate coverage factor.
+void LVSymbol::calculateCoverage() {
+  if (!LVLocation::calculateCoverage(Locations, CoverageFactor,
+                                     CoveragePercentage)) {
+    LVScope *Parent = getParentScope();
+    if (Parent->getIsInlinedFunction()) {
+      // For symbols representing the inlined function parameters and its
+      // variables, get the outer most parent that contains their location
+      // lower address.
+      // The symbol can have a set of non-continuos locations. We are using
+      // only the first location entry to get the outermost parent.
+      // If no scope contains the location, assume its enclosing parent.
+      LVScope *Scope =
+          Parent->outermostParent(Locations->front()->getLowerAddress());
+      if (Scope)
+        Parent = Scope;
+    }
+    unsigned CoverageParent = Parent->getCoverageFactor();
+    // Get a percentage rounded to two decimal digits. This avoids
+    // implementation-defined rounding inside printing functions.
+    CoveragePercentage =
+        CoverageParent
+            ? rint((double(CoverageFactor) / CoverageParent) * 100.0 * 100.0) /
+                  100.0
+            : 0;
+  }
+}
+
 void LVSymbol::resolveName() {
   if (getIsResolvedName())
     return;
@@ -108,6 +264,12 @@
   return getName();
 }
 
+void LVSymbol::printLocations(raw_ostream &OS, bool Full) const {
+  if (Locations)
+    for (const LVLocation *Location : *Locations)
+      Location->printRaw(OS, Full);
+}
+
 void LVSymbol::print(raw_ostream &OS, bool Full) const {
   if (getIncludeInPrint() && getReader().doPrintSymbol(this)) {
     getReaderCompileUnit()->incrementPrintedSymbols();
@@ -160,5 +322,9 @@
       printLinkageName(OS, Full, const_cast<LVSymbol *>(this));
     if (LVSymbol *Reference = getReference())
       Reference->printReference(OS, Full, const_cast<LVSymbol *>(this));
+
+    if (Locations)
+      // Print location information.
+      LVLocation::print(Locations, OS, Full);
   }
 }
Index: llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
===================================================================
--- llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
+++ llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt
@@ -4,6 +4,7 @@
 
 add_llvm_unittest(DebugInfoLogicalViewTests
   CommandLineOptionsTest.cpp
+  LocationRangesTest.cpp
   LogicalElementsTest.cpp
   StringPoolTest.cpp
   )
Index: llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp
===================================================================
--- /dev/null
+++ llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp
@@ -0,0 +1,345 @@
+//===- llvm/unittest/DebugInfo/LogicalView/LocationRangesTest.cpp ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"
+#include "llvm/DebugInfo/LogicalView/Core/LVType.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Testing/Support/Error.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+namespace {
+
+class ReaderTestLocations : public LVReader {
+  // Types.
+  LVType *IntegerType = nullptr;
+
+  // Scopes.
+  LVScope *NestedScope = nullptr;
+  LVScopeFunction *Function = nullptr;
+
+  // Symbols.
+  LVSymbol *LocalVariable = nullptr;
+  LVSymbol *NestedVariable = nullptr;
+  LVSymbol *Parameter = nullptr;
+
+  // Lines.
+  LVLine *LineOne = nullptr;
+  LVLine *LineTwo = nullptr;
+  LVLine *LineThree = nullptr;
+  LVLine *LineFour = nullptr;
+  LVLine *LineFive = nullptr;
+  LVLine *LineSix = nullptr;
+
+  // Locations.
+  LVLocation *LocationOne = nullptr;
+  LVLocation *LocationTwo = nullptr;
+  LVLocation *LocationThree = nullptr;
+  LVLocation *LocationFour = nullptr;
+  LVLocation *LocationFive = nullptr;
+  LVLocation *LocationSix = nullptr;
+
+protected:
+  void add(LVScope *Parent, LVElement *Element);
+  template <typename T> T *create() {
+    T *Element = new (std::nothrow) T();
+    EXPECT_NE(Element, nullptr);
+    return Element;
+  }
+  void set(LVElement *Element, StringRef Name, LVOffset Offset,
+           uint32_t LineNumber = 0, LVElement *Type = nullptr);
+  void set(LVLocation *Location, LVLine *LowerLine, LVLine *UpperLine,
+           LVAddress LowerAddress, LVAddress UpperAddress);
+  void add(LVSymbol *Symbol, LVLine *LowerLine, LVLine *UpperLine);
+
+public:
+  ReaderTestLocations(ScopedPrinter &W) : LVReader("", "", W) {
+    setInstance(this);
+  }
+
+  Error createScopes() { return LVReader::createScopes(); }
+
+  void createElements();
+  void addElements();
+  void initElements();
+};
+
+// Helper function to add a logical element to a given scope.
+void ReaderTestLocations::add(LVScope *Parent, LVElement *Child) {
+  Parent->addElement(Child);
+  EXPECT_EQ(Child->getParent(), Parent);
+  EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1);
+}
+
+// Helper function to set the initial values for a given logical element.
+void ReaderTestLocations::set(LVElement *Element, StringRef Name,
+                              LVOffset Offset, uint32_t LineNumber,
+                              LVElement *Type) {
+  Element->setName(Name);
+  Element->setOffset(Offset);
+  Element->setLineNumber(LineNumber);
+  Element->setType(Type);
+  EXPECT_EQ(Element->getName(), Name);
+  EXPECT_EQ(Element->getOffset(), Offset);
+  EXPECT_EQ(Element->getLineNumber(), LineNumber);
+  EXPECT_EQ(Element->getType(), Type);
+}
+
+// Helper function to set the initial values for a given logical location.
+void ReaderTestLocations::set(LVLocation *Location, LVLine *LowerLine,
+                              LVLine *UpperLine, LVAddress LowerAddress,
+                              LVAddress UpperAddress) {
+  Location->setLowerLine(LowerLine);
+  Location->setUpperLine(UpperLine);
+  Location->setLowerAddress(LowerAddress);
+  Location->setUpperAddress(UpperAddress);
+  EXPECT_EQ(Location->getLowerLine(), LowerLine);
+  EXPECT_EQ(Location->getUpperLine(), UpperLine);
+  EXPECT_EQ(Location->getLowerAddress(), LowerAddress);
+  EXPECT_EQ(Location->getUpperAddress(), UpperAddress);
+}
+
+// Helper function to add a logical location to a logical symbol.
+void ReaderTestLocations::add(LVSymbol *Symbol, LVLine *LowerLine,
+                              LVLine *UpperLine) {
+  dwarf::Attribute Attr = dwarf::DW_AT_location;
+
+  Symbol->addLocation(Attr, LowerLine->getAddress(), UpperLine->getAddress(),
+                      /*SectionOffset=*/0, /*LocDesOffset=*/0);
+}
+
+// Create the logical elements.
+void ReaderTestLocations::createElements() {
+  // Create scope root.
+  Error Err = createScopes();
+  ASSERT_THAT_ERROR(std::move(Err), Succeeded());
+  Root = getScopesRoot();
+  EXPECT_NE(Root, nullptr);
+
+  // Create the logical types.
+  IntegerType = create<LVType>();
+
+  // Create the logical scopes.
+  NestedScope = create<LVScope>();
+  CompileUnit = create<LVScopeCompileUnit>();
+  Function = create<LVScopeFunction>();
+
+  // Create the logical symbols.
+  LocalVariable = create<LVSymbol>();
+  NestedVariable = create<LVSymbol>();
+  Parameter = create<LVSymbol>();
+
+  // Create the logical lines.
+  LineOne = create<LVLine>();
+  LineTwo = create<LVLine>();
+  LineThree = create<LVLine>();
+  LineFour = create<LVLine>();
+  LineFive = create<LVLine>();
+  LineSix = create<LVLine>();
+
+  // Create the logical locations.
+  LocationOne = create<LVLocation>();
+  LocationTwo = create<LVLocation>();
+  LocationThree = create<LVLocation>();
+  LocationFour = create<LVLocation>();
+  LocationFive = create<LVLocation>();
+  LocationSix = create<LVLocation>();
+}
+
+// Create the logical view adding the created logical elements.
+void ReaderTestLocations::addElements() {
+  setCompileUnit(CompileUnit);
+
+  // Root
+  //   CompileUnit
+  //     IntegerType
+  //     Function
+  //       LocationOne
+  //       LocationTwo
+  //       LocationFive
+  //       LocationSix
+  //       Parameter
+  //       LocalVariable
+  //       LineOne
+  //       LineTwo
+  //       NestedScope
+  //         LocationThree
+  //         LocationFour
+  //         NestedVariable
+  //         LineThree
+  //         LineFour
+  //       LineFive
+  //       LineSix
+
+  // Add elements to Root.
+  add(Root, CompileUnit);
+
+  // Add elements to CompileUnit.
+  add(CompileUnit, IntegerType);
+  add(CompileUnit, Function);
+
+  // Add elements to Function.
+  add(Function, Parameter);
+  add(Function, LocalVariable);
+  add(Function, LineOne);
+  add(Function, LineTwo);
+  add(Function, LineFive);
+  add(Function, LineSix);
+  add(Function, NestedScope);
+
+  // Add elements to NestedScope.
+  add(NestedScope, NestedVariable);
+  add(NestedScope, LineThree);
+  add(NestedScope, LineFour);
+}
+
+// Set initial values to logical elements.
+void ReaderTestLocations::initElements() {
+  // Types.
+  set(IntegerType, "int", 0x1000);
+
+  // Scopes.
+  set(CompileUnit, "foo.cpp", 0x2000);
+  set(Function, "foo", 0x2010, 100, IntegerType);
+  set(NestedScope, "", 0x2020, 300);
+
+  // Symbols.
+  set(Parameter, "Param", 0x3000, 110, IntegerType);
+  set(LocalVariable, "LocalVariable", 0x3000, 120, IntegerType);
+  set(NestedVariable, "NestedVariable", 0x3010, 310, IntegerType);
+
+  // Lines.
+  set(LineOne, "", 0x5000, 100);
+  set(LineTwo, "", 0x5200, 200);
+  set(LineThree, "", 0x5400, 300);
+  set(LineFour, "", 0x5600, 400);
+  set(LineFive, "", 0x5800, 500);
+  set(LineSix, "", 0x6000, 600);
+
+  // Locations.
+  set(LocationOne, LineOne, LineOne, 0x5000, 0x5100);
+  EXPECT_STREQ(LocationOne->getIntervalInfo().c_str(),
+               " Lines 100:100 [0x0000005000:0x0000005100]");
+
+  set(LocationTwo, LineTwo, LineTwo, 0x5200, 0x5300);
+  EXPECT_STREQ(LocationTwo->getIntervalInfo().c_str(),
+               " Lines 200:200 [0x0000005200:0x0000005300]");
+
+  set(LocationThree, LineThree, LineThree, 0x5400, 0x5500);
+  EXPECT_STREQ(LocationThree->getIntervalInfo().c_str(),
+               " Lines 300:300 [0x0000005400:0x0000005500]");
+
+  set(LocationFour, LineFour, LineFour, 0x5600, 0x5700);
+  LocationFour->setIsAddressRange();
+  EXPECT_STREQ(LocationFour->getIntervalInfo().c_str(),
+               "{Range} Lines 400:400 [0x0000005600:0x0000005700]");
+
+  set(LocationFive, LineFive, LineFive, 0x5800, 0x5900);
+  LocationFive->setIsAddressRange();
+  EXPECT_STREQ(LocationFive->getIntervalInfo().c_str(),
+               "{Range} Lines 500:500 [0x0000005800:0x0000005900]");
+
+  set(LocationSix, LineSix, LineSix, 0x6000, 0x6100);
+  LocationSix->setIsAddressRange();
+  EXPECT_STREQ(LocationSix->getIntervalInfo().c_str(),
+               "{Range} Lines 600:600 [0x0000006000:0x0000006100]");
+
+  // Add ranges to Function.
+  // Function: LocationOne, LocationTwo, LocationFive, LocationSix
+  Function->addObject(LocationOne);
+  Function->addObject(LocationTwo);
+  Function->addObject(LocationFive);
+  Function->addObject(LocationSix);
+  EXPECT_EQ(Function->rangeCount(), 4);
+
+  // Add ranges to NestedScope.
+  // NestedScope: LocationThree, LocationFour
+  NestedScope->addObject(LocationThree);
+  NestedScope->addObject(LocationFour);
+  EXPECT_EQ(NestedScope->rangeCount(), 2);
+
+  // Get all ranges.
+  LVRange Ranges;
+  CompileUnit->getRanges(Ranges);
+  Ranges.startSearch();
+  EXPECT_EQ(Ranges.getEntry(0x4000), nullptr);
+
+  EXPECT_EQ(Ranges.getEntry(0x5060), Function);
+  EXPECT_EQ(Ranges.getEntry(0x5850), Function);
+  EXPECT_EQ(Ranges.getEntry(0x5010, 0x5090), Function);
+  EXPECT_EQ(Ranges.getEntry(0x5210, 0x5290), Function);
+  EXPECT_EQ(Ranges.getEntry(0x5810, 0x5890), Function);
+  EXPECT_EQ(Ranges.getEntry(0x6010, 0x6090), Function);
+
+  EXPECT_EQ(Ranges.getEntry(0x5400), NestedScope);
+  EXPECT_EQ(Ranges.getEntry(0x5650), NestedScope);
+  EXPECT_EQ(Ranges.getEntry(0x5410, 0x5490), NestedScope);
+  EXPECT_EQ(Ranges.getEntry(0x5610, 0x5690), NestedScope);
+
+  EXPECT_EQ(Ranges.getEntry(0x8000), nullptr);
+  Ranges.endSearch();
+
+  // Add locations to symbols.
+  // Parameter:       [LineOne, LineSix]
+  // LocalVariable:   [LineTwo, LineSix], [LineFour, LineFive]
+  // NestedVariable:  [LineThree, LineFour]
+  add(Parameter, LineOne, LineSix);
+  add(LocalVariable, LineTwo, LineSix);
+  add(LocalVariable, LineFour, LineFive);
+  add(NestedVariable, LineThree, LineFour);
+
+  LVLocation *Location;
+  LVLocations Locations;
+  Parameter->getLocations(Locations);
+  ASSERT_EQ(Locations.size(), 1);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineOne->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
+
+  Locations.clear();
+  LocalVariable->getLocations(Locations);
+  ASSERT_EQ(Locations.size(), 2);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineTwo->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
+  Location = Locations[1];
+  EXPECT_EQ(Location->getLowerAddress(), LineFour->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineFive->getAddress());
+
+  Locations.clear();
+  NestedVariable->getLocations(Locations);
+  ASSERT_EQ(Locations.size(), 1);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineThree->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineFour->getAddress());
+}
+
+TEST(LogicalViewTest, LocationRanges) {
+  ScopedPrinter W(outs());
+  ReaderTestLocations Reader(W);
+
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setPrintAll();
+  ReaderOptions.resolveDependencies();
+  options().setOptions(&ReaderOptions);
+
+  Reader.createElements();
+  Reader.addElements();
+  Reader.initElements();
+}
+
+} // namespace