//===- 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(LVSymbol *Symbol, LVLine *LowerLine, LVLine *UpperLine); void add(LVScope *Parent, LVElement *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); 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 { #define CREATE(VARIABLE, CREATE_FUNCTION) \ VARIABLE = CREATE_FUNCTION(); \ EXPECT_NE(VARIABLE, nullptr); // 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. CREATE(IntegerType, createType); // Create the logical scopes. CREATE(NestedScope, createScope); CREATE(CompileUnit, createScopeCompileUnit); CREATE(Function, createScopeFunction); // Create the logical symbols. CREATE(LocalVariable, createSymbol); CREATE(NestedVariable, createSymbol); CREATE(Parameter, createSymbol); // Create the logical lines. CREATE(LineOne, createLine); CREATE(LineTwo, createLine); CREATE(LineThree, createLine); CREATE(LineFour, createLine); CREATE(LineFive, createLine); CREATE(LineSix, createLine); // Create the logical locations. CREATE(LocationOne, createLocation); CREATE(LocationTwo, createLocation); CREATE(LocationThree, createLocation); CREATE(LocationFour, createLocation); CREATE(LocationFive, createLocation); CREATE(LocationSix, createLocation); } // 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 *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 = createType(); EXPECT_NE(IntegerType, nullptr); // Create the logical scopes. CompileUnit = createScopeCompileUnit(); EXPECT_NE(CompileUnit, nullptr); Function = createScopeFunction(); EXPECT_NE(Function, nullptr); InlinedFunction = createScopeFunctionInlined(); EXPECT_NE(InlinedFunction, nullptr); // Create the logical symbols. Variable = createSymbol(); EXPECT_NE(Variable, nullptr); Parameter = createSymbol(); EXPECT_NE(Parameter, nullptr); // Create the logical lines. LineOne = createLine(); EXPECT_NE(LineOne, nullptr); LineTwo = createLine(); EXPECT_NE(LineTwo, nullptr); LineThree = createLine(); EXPECT_NE(LineThree, nullptr); LineFour = createLine(); EXPECT_NE(LineFour, nullptr); LineFive = createLine(); EXPECT_NE(LineFive, nullptr); LineSix = createLine(); EXPECT_NE(LineSix, nullptr); // Create the logical locations. LocationOne = createLocation(); EXPECT_NE(LocationOne, nullptr); LocationTwo = createLocation(); EXPECT_NE(LocationTwo, nullptr); LocationFive = createLocation(); EXPECT_NE(LocationFive, nullptr); LocationSix = createLocation(); EXPECT_NE(LocationSix, nullptr); } // 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(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.00f); // Before the changes: Variable: CoveragePercentage = 1000.00 // After the changes: Variable: CoveragePercentage = 56.83 EXPECT_FLOAT_EQ(Variable->getCoveragePercentage(), 56.83f); } 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