[llvm] 3c397c9 - [llvm-debuginfo-analyzer] (04/09) - Locations and ranges

Carlos Alberto Enciso via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 20 00:32:14 PDT 2022


Author: Carlos Alberto Enciso
Date: 2022-10-20T08:31:13+01:00
New Revision: 3c397c90c18377b1996783b994fba42d0b1649a2

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

LOG: [llvm-debuginfo-analyzer] (04/09) - Locations and ranges

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:

Locations and ranges
- All functionality for logical debug locations and ranges:
  LVLocation, LVRanges.

Reviewed By: psamolysov, probinson

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

Added: 
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h
    llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVRange.cpp
    llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp

Modified: 
    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/LVSort.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
    llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
    llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
    llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
    llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
    llvm/unittests/DebugInfo/LogicalView/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
new file mode 100644
index 000000000000..49d342426dd4
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVLocation.h
@@ -0,0 +1,195 @@
+//===-- 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();
+
+  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);
+
+  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) {}
+
+  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; };
+
+  void addObject(LVAddress LowPC, LVAddress HighPC, LVUnsigned SectionOffset,
+                 uint64_t LocDescOffset) override;
+  void addObject(LVSmall Opcode, LVUnsigned Operand1,
+                 LVUnsigned Operand2) override;
+
+  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

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
index d15449cff358..b44b706d6128 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVObject.h
@@ -102,6 +102,9 @@ const LVAddress MaxAddress = std::numeric_limits<uint64_t>::max();
 
 enum class LVBinaryType { NONE, ELF, COFF };
 
+// Validate functions.
+using LVValidLocation = bool (LVLocation::*)();
+
 // Keep counters of objects.
 struct LVCounter {
   unsigned Lines = 0;
@@ -258,6 +261,11 @@ class LVObject {
   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; }
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h
new file mode 100644
index 000000000000..3ec0ccb31168
--- /dev/null
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVRange.h
@@ -0,0 +1,98 @@
+//===-- 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;
+
+  LVRangeEntry() = delete;
+  LVRangeEntry(LVAddress LowerAddress, LVAddress UpperAddress, LVScope *Scope)
+      : Lower(LowerAddress), Upper(UpperAddress), Scope(Scope) {}
+
+  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 and can overlap.
+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;
+
+  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 hasEntry(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() {}
+
+  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

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
index 141588006b39..e464a44ba1c1 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVReader.h
+++ b/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"
@@ -127,6 +128,11 @@ class LVReader {
   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;
   };
@@ -136,6 +142,7 @@ class LVReader {
 
   // 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; }

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
index 909c701c96f8..22b169471539 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVScope.h
+++ b/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 @@ class LVScope : public LVElement {
   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 @@ class LVScope : public LVElement {
                        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,8 +117,9 @@ class LVScope : public LVElement {
   void resolveTemplate();
   void printEncodedArgs(raw_ostream &OS, bool Full) const;
 
-  virtual void printSizes(raw_ostream &OS) const {}
-  virtual void printSummary(raw_ostream &OS) const {}
+  void printActiveRanges(raw_ostream &OS, bool Full = true) const;
+  virtual void printSizes(raw_ostream &OS) const {};
+  virtual void printSummary(raw_ostream &OS) const {};
 
   // Encoded template arguments.
   virtual StringRef getEncodedArgs() const { return StringRef(); }
@@ -171,6 +185,7 @@ class LVScope : public LVElement {
 
   // 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; }
@@ -181,6 +196,8 @@ class LVScope : public LVElement {
   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
@@ -194,10 +211,23 @@ class LVScope : public LVElement {
 
   // 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; }
 
+  // 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
@@ -378,6 +408,10 @@ class LVScopeCompileUnit final : public LVScope {
     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;
@@ -563,6 +597,9 @@ class LVScopeRoot final : public LVScope {
     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,

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
index 93ce6de3ff0b..01f0b1880fbc 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSort.h
@@ -40,6 +40,7 @@ LVSortValue compareKind(const LVObject *LHS, const LVObject *RHS);
 LVSortValue compareLine(const LVObject *LHS, const LVObject *RHS);
 LVSortValue compareName(const LVObject *LHS, const LVObject *RHS);
 LVSortValue compareOffset(const LVObject *LHS, const LVObject *RHS);
+LVSortValue 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);

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
index 19781f68660f..cfa0c7ca2209 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSupport.h
@@ -158,6 +158,21 @@ inline std::string formattedNames(StringRef Name1, StringRef Name2) {
   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 getCodeViewOperationCode(uint8_t Code) { return 0x1100 | Code; }
+
 } // end namespace logicalview
 } // end namespace llvm
 

diff  --git a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
index 32b115804293..320bde953127 100644
--- a/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
+++ b/llvm/include/llvm/DebugInfo/LogicalView/Core/LVSymbol.h
@@ -43,6 +43,8 @@ class LVSymbol final : public LVElement {
 
   // 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 @@ class LVSymbol final : public LVElement {
   // 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 @@ class LVSymbol final : public LVElement {
   }
   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;
@@ -107,6 +117,34 @@ class LVSymbol final : public LVElement {
   }
   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();

diff  --git a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
index cec32ff6f701..e6a85d385f12 100644
--- a/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
+++ b/llvm/lib/DebugInfo/LogicalView/CMakeLists.txt
@@ -6,8 +6,10 @@ endmacro()
 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

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
new file mode 100644
index 000000000000..3a414deb5355
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVLocation.cpp
@@ -0,0 +1,675 @@
+//===-- 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 = getCodeViewOperationCode(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) {
+  if (!Locations || Locations->empty())
+    return;
+
+  // Print the symbol coverage.
+  if (options().getAttributeCoverage()) {
+    // 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 (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);
+  }
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVRange.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVRange.cpp
new file mode 100644
index 000000000000..b6003fcb8b93
--- /dev/null
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVRange.cpp
@@ -0,0 +1,158 @@
+//===-- 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"
+
+using namespace llvm;
+using namespace llvm::logicalview;
+
+#define DEBUG_TYPE "Range"
+
+void LVRange::startSearch() {
+  RangesTree.clear();
+
+  LLVM_DEBUG({ dbgs() << "\nRanges Tree entries:\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 (!hasEntry(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;
+}
+
+// True if the range addresses contain the pair [LowerAddress, UpperAddress].
+bool LVRange::hasEntry(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 {
+    if (lhs.lower() < rhs.lower())
+      return true;
+
+    // If the lower address is the same, use the upper address value in
+    // order to put first the smallest interval.
+    if (lhs.lower() == rhs.lower())
+      return lhs.upper() < rhs.upper();
+
+    return false;
+  };
+
+  // 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);
+}

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
index 335053159362..2154ace04e05 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVReader.cpp
+++ b/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 @@ Error LVReader::doLoad() {
   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 
diff erent compile unit,
   // information such as name and file/line source information needs to be
   // updated.

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
index 61c5c5894f31..7a90d1f1ed80 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVScope.cpp
+++ b/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 @@ LVScope::~LVScope() {
   delete Symbols;
   delete Scopes;
   delete Lines;
+  delete Ranges;
   delete Children;
 }
 
@@ -129,6 +131,21 @@ void LVScope::addElement(LVLine *Line) {
   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 @@ void LVScope::addElement(LVType *Type) {
   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 @@ void LVScope::sort() {
           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,83 @@ void LVScope::traverseParentsAndChildren(LVObjectGetFunction GetFunction,
     TraverseChildren(this);
 }
 
+// Traverse the symbol location ranges and for each range:
+// - Apply the 'ValidLocation' validation criteria.
+// - Add any failed range to the 'LocationList'.
+// - Calculate location coverage.
+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);
+}
+
+// Traverse the scope ranges and for each range:
+// - Apply the 'ValidLocation' validation criteria.
+// - Add any failed range to the 'LocationList'.
+// - Calculate location coverage.
+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) {
+    const LVLocations *ParentRanges = Parent->getRanges();
+    if (ParentRanges)
+      for (const LVLocation *Location : *ParentRanges)
+        if (Location->getLowerAddress() <= Address)
+          return Parent;
+    Parent = Parent->getParentScope();
+  }
+  return Parent;
+}
+
+void LVScope::printActiveRanges(raw_ostream &OS, bool Full) const {
+  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 +811,10 @@ void LVScope::printExtra(raw_ostream &OS, bool Full) const {
          << formattedNames(getTypeQualifiedName(), typeAsString());
   }
   OS << "\n";
+
+  // Print any active ranges.
+  if (Full && getIsBlock())
+    printActiveRanges(OS, Full);
 }
 
 //===----------------------------------------------------------------------===//
@@ -829,6 +939,24 @@ void LVScopeCompileUnit::addSize(LVScope *Scope, LVOffset Lower,
     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;
@@ -1103,9 +1231,10 @@ void LVScopeCompileUnit::printExtra(raw_ostream &OS, bool Full) const {
   // 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 +1338,7 @@ void LVScopeFunction::printExtra(raw_ostream &OS, bool Full) const {
   if (Full) {
     if (getIsTemplateResolved())
       printEncodedArgs(OS, Full);
+    printActiveRanges(OS, Full);
     if (Reference)
       Reference->printReference(OS, Full, const_cast<LVScopeFunction *>(this));
   }
@@ -1268,12 +1398,31 @@ void LVScopeFunctionType::resolveExtra() {
 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);

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
index 48d2b8a85454..ea01671d0eb1 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
+++ b/llvm/lib/DebugInfo/LogicalView/Core/LVSort.cpp
@@ -47,6 +47,20 @@ LVSortValue llvm::logicalview::compareOffset(const LVObject *LHS,
   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) {

diff  --git a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp b/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
index d2b2c97ecf1d..4e9b05ee8918 100644
--- a/llvm/lib/DebugInfo/LogicalView/Core/LVSymbol.cpp
+++ b/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 @@ const char *LVSymbol::kind() const {
   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-contiguous 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 @@ StringRef LVSymbol::resolveReferencesChain() {
   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,8 @@ void LVSymbol::printExtra(raw_ostream &OS, bool Full) const {
       printLinkageName(OS, Full, const_cast<LVSymbol *>(this));
     if (LVSymbol *Reference = getReference())
       Reference->printReference(OS, Full, const_cast<LVSymbol *>(this));
+
+    // Print location information.
+    LVLocation::print(Locations, OS, Full);
   }
 }

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

diff  --git a/llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp b/llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp
new file mode 100644
index 000000000000..5210535136f2
--- /dev/null
+++ b/llvm/unittests/DebugInfo/LogicalView/LocationRangesTest.cpp
@@ -0,0 +1,587 @@
+//===- 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 ReaderTest : public LVReader {
+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:
+  ReaderTest(ScopedPrinter &W) : LVReader("", "", W) { setInstance(this); }
+
+  Error createScopes() { return LVReader::createScopes(); }
+};
+
+// Helper function to add a logical element to a given scope.
+void ReaderTest::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 ReaderTest::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 ReaderTest::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 ReaderTest::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);
+}
+
+class ReaderTestLocations : public ReaderTest {
+  // 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;
+
+public:
+  ReaderTestLocations(ScopedPrinter &W) : ReaderTest(W) {}
+
+  void createElements();
+  void addElements();
+  void initElements();
+};
+
+// 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(), 4u);
+
+  // Add ranges to NestedScope.
+  // NestedScope: LocationThree, LocationFour
+  NestedScope->addObject(LocationThree);
+  NestedScope->addObject(LocationFour);
+  EXPECT_EQ(NestedScope->rangeCount(), 2u);
+
+  // 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(), 1u);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineOne->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
+
+  Locations.clear();
+  LocalVariable->getLocations(Locations);
+  ASSERT_EQ(Locations.size(), 2u);
+  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(), 1u);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineThree->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineFour->getAddress());
+}
+
+class ReaderTestCoverage : public ReaderTest {
+  // Types.
+  LVType *IntegerType = nullptr;
+
+  // Scopes.
+  LVScopeFunction *Function = nullptr;
+  LVScopeFunctionInlined *InlinedFunction = nullptr;
+
+  // Symbols.
+  LVSymbol *Variable = 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;
+
+public:
+  ReaderTestCoverage(ScopedPrinter &W) : ReaderTest(W) {}
+
+  void createElements();
+  void addElements();
+  void initElements();
+};
+
+// Create the logical elements.
+void ReaderTestCoverage::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.
+  CompileUnit = create<LVScopeCompileUnit>();
+  Function = create<LVScopeFunction>();
+  InlinedFunction = create<LVScopeFunctionInlined>();
+
+  // Create the logical symbols.
+  Variable = 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 ReaderTestCoverage::addElements() {
+  setCompileUnit(CompileUnit);
+
+  // Root
+  //   CompileUnit
+  //     IntegerType
+  //     Function
+  //       Ranges
+  //         [LineOne, LineOne]
+  //         [LineTwo, LineSix]
+  //         [LineSix, LineSix]
+  //       LineOne
+  //       LineTwo
+  //       InlinedFunction
+  //         Ranges
+  //           [LineFive, LineFive]
+  //         Parameter
+  //           Location
+  //             [LineThree, LineThree]
+  //         Variable
+  //           Location
+  //             [LineFour, LineFive]
+  //             [LineFive, LineSix]
+  //         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, InlinedFunction);
+  add(Function, LineOne);
+  add(Function, LineTwo);
+  add(Function, LineSix);
+
+  // Add elements to function InlinedFunction.
+  add(InlinedFunction, Parameter);
+  add(InlinedFunction, Variable);
+  add(InlinedFunction, LineThree);
+  add(InlinedFunction, LineFour);
+  add(InlinedFunction, LineFive);
+}
+
+// Set initial values to logical elements.
+void ReaderTestCoverage::initElements() {
+  // Types.
+  set(IntegerType, "int", 0x1000);
+
+  // Scopes.
+  set(CompileUnit, "foo.cpp", 0x2000);
+  set(Function, "foo", 0x2500, 100, IntegerType);
+  set(InlinedFunction, "InlinedFunction", 0x3000, 300);
+
+  // Symbols.
+  set(Parameter, "Parameter", 0x3100, 310, IntegerType);
+  set(Variable, "Variable", 0x3200, 320, 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, 0x5199);
+  EXPECT_STREQ(LocationOne->getIntervalInfo().c_str(),
+               " Lines 100:100 [0x0000005000:0x0000005199]");
+
+  set(LocationTwo, LineTwo, LineSix, 0x5200, 0x6100);
+  EXPECT_STREQ(LocationTwo->getIntervalInfo().c_str(),
+               " Lines 200:600 [0x0000005200:0x0000006100]");
+
+  set(LocationThree, LineThree, LineFive, 0x5400, 0x5800);
+  EXPECT_STREQ(LocationThree->getIntervalInfo().c_str(),
+               " Lines 300:500 [0x0000005400:0x0000005800]");
+
+  set(LocationFour, LineFour, LineFour, 0x5600, 0x5700);
+  EXPECT_STREQ(LocationFour->getIntervalInfo().c_str(),
+               " Lines 400:400 [0x0000005600:0x0000005700]");
+
+  set(LocationFive, LineFive, LineFive, 0x5800, 0x5900);
+  EXPECT_STREQ(LocationFive->getIntervalInfo().c_str(),
+               " Lines 500:500 [0x0000005800:0x0000005900]");
+
+  set(LocationSix, LineSix, LineSix, 0x6000, 0x6100);
+  EXPECT_STREQ(LocationSix->getIntervalInfo().c_str(),
+               " Lines 600:600 [0x0000006000:0x0000006100]");
+
+  // Add ranges to Function.
+  // Function: LocationOne, LocationTwo, LocationSix
+  Function->addObject(LocationOne);
+  Function->addObject(LocationTwo);
+  Function->addObject(LocationSix);
+  EXPECT_EQ(Function->rangeCount(), 3u);
+
+  // Add ranges to Inlined.
+  // Inlined: LocationFive
+  InlinedFunction->addObject(LocationFive);
+  EXPECT_EQ(InlinedFunction->rangeCount(), 1u);
+
+  // Add locations to symbols.
+  // Parameter: [LineThree, LineThree]
+  // Variable:  [LineFour, LineFive], [LineFive, LineSix]
+  add(Parameter, LineThree, LineThree);
+  add(Variable, LineFour, LineFive);
+  add(Variable, LineFive, LineSix);
+
+  CompileUnit->processRangeLocationCoverage();
+
+  LVLocation *Location;
+  LVLocations Locations;
+  Parameter->getLocations(Locations);
+  ASSERT_EQ(Locations.size(), 1u);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineThree->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineThree->getAddress());
+
+  Locations.clear();
+  Variable->getLocations(Locations);
+  ASSERT_EQ(Locations.size(), 2u);
+  Location = Locations[0];
+  EXPECT_EQ(Location->getLowerAddress(), LineFour->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineFive->getAddress());
+  Location = Locations[1];
+  EXPECT_EQ(Location->getLowerAddress(), LineFive->getAddress());
+  EXPECT_EQ(Location->getUpperAddress(), LineSix->getAddress());
+
+  // Test the changes done to 'LVScope::outermostParent' to use the
+  // ranges allocated int the current scope during the scopes traversal.
+  // These are the pre-conditions for the symbol:
+  // - Its parent must be an inlined function.
+  // - Have more than one location description.
+
+  // Before the changes: Parameter: CoveragePercentage = 100.00
+  // After the changes:  Parameter: CoveragePercentage = 100.00
+  EXPECT_FLOAT_EQ(Parameter->getCoveragePercentage(), 100.00);
+
+  // Before the changes: Variable: CoveragePercentage = 1000.00
+  // After the changes:  Variable: CoveragePercentage = 56.83
+  EXPECT_FLOAT_EQ(Variable->getCoveragePercentage(), 56.83);
+}
+
+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();
+}
+
+TEST(LogicalViewTest, LocationCoverage) {
+  ScopedPrinter W(outs());
+  ReaderTestCoverage Reader(W);
+
+  // Reader options.
+  LVOptions ReaderOptions;
+  ReaderOptions.setAttributeOffset();
+  ReaderOptions.setAttributeRange();
+  ReaderOptions.setAttributeLocation();
+  ReaderOptions.setPrintAll();
+  ReaderOptions.resolveDependencies();
+  options().setOptions(&ReaderOptions);
+
+  Reader.createElements();
+  Reader.addElements();
+  Reader.initElements();
+}
+
+} // namespace


        


More information about the llvm-commits mailing list