--- /dev/null
+//===-- 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
enum class LVBinaryType { NONE, ELF, COFF };
+// Validate functions.
+using LVValidLocation = bool (LVLocation::*)();
+
// Keep counters of objects.
struct LVCounter {
unsigned Lines = 0;
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; }
--- /dev/null
+//===-- 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
#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"
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;
};
// 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; }
#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>
namespace llvm {
namespace logicalview {
+class LVRange;
+
enum class LVScopeKind {
IsAggregate,
IsArray,
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;
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
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(); }
// 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; }
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
// 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
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;
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,
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);
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
// 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;
// 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();
}
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;
}
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();
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
--- /dev/null
+//===-- 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);
+ }
+}
--- /dev/null
+//===-- 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);
+}
#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"
if (Error Err = createScopes())
return Err;
+ // Calculate symbol coverage and detect invalid debug locations and ranges.
+ Root->processRangeInformation();
+
// As the elements can depend on elements from a different compile unit,
// information such as name and file/line source information needs to be
// updated.
#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"
delete Symbols;
delete Scopes;
delete Lines;
+ delete Ranges;
delete Children;
}
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.");
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;
Traverse(Parent->Types, SortFunction);
Traverse(Parent->Symbols, SortFunction);
Traverse(Parent->Scopes, SortFunction);
+ Traverse(Parent->Ranges, compareRange);
Traverse(Parent->Children, SortFunction);
if (Parent->Scopes)
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),
<< formattedNames(getTypeQualifiedName(), typeAsString());
}
OS << "\n";
+
+ // Print any active ranges.
+ if (Full && getIsBlock())
+ printActiveRanges(OS, Full);
}
//===----------------------------------------------------------------------===//
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;
// 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);
}
}
if (Full) {
if (getIsTemplateResolved())
printEncodedArgs(OS, Full);
+ printActiveRanges(OS, Full);
if (Reference)
Reference->printReference(OS, Full, const_cast<LVScopeFunction *>(this));
}
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);
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) {
//===----------------------------------------------------------------------===//
#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"
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;
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();
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);
}
}
add_llvm_unittest(DebugInfoLogicalViewTests
CommandLineOptionsTest.cpp
+ LocationRangesTest.cpp
LogicalElementsTest.cpp
StringPoolTest.cpp
)
--- /dev/null
+//===- 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