566 lines · cpp
1//===- llvm/unittest/DebugInfo/LogicalView/WarningInternalTest.cpp --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"10#include "llvm/DebugInfo/LogicalView/Core/LVReader.h"11#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"12#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"13#include "llvm/DebugInfo/LogicalView/Core/LVType.h"14#include "llvm/Support/ScopedPrinter.h"15#include "llvm/Support/ToolOutputFile.h"16#include "llvm/Testing/Support/Error.h"17 18#include "gtest/gtest.h"19 20using namespace llvm;21using namespace llvm::logicalview;22 23namespace {24 25class MyLocation : public LVLocation {26public:27 bool validateRanges();28};29 30// This code emulates the work done by the Readers when processing the31// binary files and the creation of the AddressToLine mapping is done32// automatically, using the text sections.33class MyAddressToLine {34 using LVAddressToLine = std::map<LVAddress, LVLine *>;35 LVAddressToLine AddressToLineData;36 37public:38 MyAddressToLine() = default;39 40 void insert(LVLine *Line) {41 AddressToLineData.emplace(Line->getOffset(), Line);42 }43 44 LVLine *lineLowerBound(LVAddress Address);45 LVLine *lineUpperBound(LVAddress Address);46};47 48LVLine *MyAddressToLine::lineLowerBound(LVAddress Address) {49 LVAddressToLine::const_iterator Iter = AddressToLineData.lower_bound(Address);50 return (Iter != AddressToLineData.end()) ? Iter->second : nullptr;51}52 53LVLine *MyAddressToLine::lineUpperBound(LVAddress Address) {54 if (AddressToLineData.empty())55 return nullptr;56 LVAddressToLine::const_iterator Iter = AddressToLineData.upper_bound(Address);57 if (Iter != AddressToLineData.begin())58 Iter = std::prev(Iter);59 return Iter->second;60}61 62MyAddressToLine AddressToLine;63 64class ReaderTestWarningInternal : public LVReader {65#define CREATE(VARIABLE, CREATE_FUNCTION) \66 VARIABLE = CREATE_FUNCTION(); \67 EXPECT_NE(VARIABLE, nullptr);68 69#define CREATE_CUSTOM(VARIABLE, CREATE_FUNCTION) \70 VARIABLE = CREATE_FUNCTION(); \71 EXPECT_NE(VARIABLE, nullptr);72 73 // Types.74 LVType *IntegerType = nullptr;75 76 // Scopes.77 LVScope *NestedScope = nullptr;78 LVScopeFunction *Function = nullptr;79 80 // Symbols.81 LVSymbol *LocalVariable = nullptr;82 LVSymbol *NestedVariable = nullptr;83 LVSymbol *Parameter = nullptr;84 85 // Lines.86 LVLine *LineOne = nullptr;87 LVLine *LineTwo = nullptr;88 LVLine *LineThree = nullptr;89 LVLine *LineFour = nullptr;90 LVLine *LineFive = nullptr;91 LVLine *LineSix = nullptr;92 93 // Locations.94 MyLocation *LocationOne = nullptr;95 MyLocation *LocationTwo = nullptr;96 MyLocation *LocationThree = nullptr;97 MyLocation *LocationFour = nullptr;98 MyLocation *LocationFive = nullptr;99 MyLocation *LocationSix = nullptr;100 101 llvm::SpecificBumpPtrAllocator<MyLocation> AllocatedLocations;102 103protected:104 MyLocation *createCustomLocation() {105 return new (AllocatedLocations.Allocate()) MyLocation();106 }107 108 void add(LVSymbol *Symbol, LVLine *LowerLine, LVLine *UpperLine);109 void add(LVScope *Parent, LVElement *Element);110 void set(LVElement *Element, StringRef Name, LVOffset Offset,111 uint32_t LineNumber = 0, LVElement *Type = nullptr);112 void set(MyLocation *Location, LVLine *LowerLine, LVLine *UpperLine,113 LVAddress LowerAddress, LVAddress UpperAddress);114 115public:116 ReaderTestWarningInternal(ScopedPrinter &W) : LVReader("", "", W) {117 setInstance(this);118 }119 120 Error createScopes() override { return LVReader::createScopes(); }121 122 void setMapping();123 void createElements();124 void addElements();125 void initElements();126 void resolveElements();127 void checkWarnings();128};129 130bool MyLocation::validateRanges() {131 // Traverse the locations and validate them against the address to line132 // mapping in the current compile unit. Record those invalid ranges.133 // A valid range must meet the following conditions:134 // a) line(lopc) <= line(hipc)135 // b) line(lopc) and line(hipc) are valid.136 137 LVLine *LowLine = AddressToLine.lineLowerBound(getLowerAddress());138 LVLine *HighLine = AddressToLine.lineUpperBound(getUpperAddress());139 if (LowLine)140 setLowerLine(LowLine);141 else {142 setIsInvalidLower();143 return false;144 }145 if (HighLine)146 setUpperLine(HighLine);147 else {148 setIsInvalidUpper();149 return false;150 }151 // Check for a valid interval.152 if (LowLine->getLineNumber() > HighLine->getLineNumber()) {153 setIsInvalidRange();154 return false;155 }156 157 return true;158}159 160// Map all logical lines with their addresses.161void ReaderTestWarningInternal::setMapping() {162 AddressToLine.insert(LineOne);163 AddressToLine.insert(LineTwo);164 AddressToLine.insert(LineThree);165 AddressToLine.insert(LineFour);166 AddressToLine.insert(LineFive);167 AddressToLine.insert(LineSix);168}169 170// Helper function to add a logical element to a given scope.171void ReaderTestWarningInternal::add(LVScope *Parent, LVElement *Child) {172 Parent->addElement(Child);173 EXPECT_EQ(Child->getParent(), Parent);174 EXPECT_EQ(Child->getLevel(), Parent->getLevel() + 1);175}176 177// Helper function to set the initial values for a given logical element.178void ReaderTestWarningInternal::set(LVElement *Element, StringRef Name,179 LVOffset Offset, uint32_t LineNumber,180 LVElement *Type) {181 Element->setName(Name);182 Element->setOffset(Offset);183 Element->setLineNumber(LineNumber);184 Element->setType(Type);185 EXPECT_EQ(Element->getName(), Name);186 EXPECT_EQ(Element->getOffset(), Offset);187 EXPECT_EQ(Element->getLineNumber(), LineNumber);188 EXPECT_EQ(Element->getType(), Type);189}190 191// Helper function to set the initial values for a given logical location.192void ReaderTestWarningInternal::set(MyLocation *Location, LVLine *LowerLine,193 LVLine *UpperLine, LVAddress LowerAddress,194 LVAddress UpperAddress) {195 Location->setLowerLine(LowerLine);196 Location->setUpperLine(UpperLine);197 Location->setLowerAddress(LowerAddress);198 Location->setUpperAddress(UpperAddress);199 EXPECT_EQ(Location->getLowerLine(), LowerLine);200 EXPECT_EQ(Location->getUpperLine(), UpperLine);201 EXPECT_EQ(Location->getLowerAddress(), LowerAddress);202 EXPECT_EQ(Location->getUpperAddress(), UpperAddress);203}204 205// Helper function to add a logical location to a logical symbol.206void ReaderTestWarningInternal::add(LVSymbol *Symbol, LVLine *LowerLine,207 LVLine *UpperLine) {208 dwarf::Attribute Attr = dwarf::DW_AT_location;209 210 Symbol->addLocation(Attr, LowerLine->getAddress(), UpperLine->getAddress(),211 /*SectionOffset=*/0, /*LocDesOffset=*/0);212}213 214// Create the logical elements.215void ReaderTestWarningInternal::createElements() {216 // Create scope root.217 Error Err = createScopes();218 ASSERT_THAT_ERROR(std::move(Err), Succeeded());219 Root = getScopesRoot();220 EXPECT_NE(Root, nullptr);221 222 // Create the logical types.223 CREATE(IntegerType, createType);224 225 // Create the logical scopes.226 CREATE(NestedScope, createScope);227 CREATE(CompileUnit, createScopeCompileUnit);228 CREATE(Function, createScopeFunction);229 230 // Create the logical symbols.231 CREATE(LocalVariable, createSymbol);232 CREATE(NestedVariable, createSymbol);233 CREATE(Parameter, createSymbol);234 235 // Create the logical lines.236 CREATE(LineOne, createLine);237 CREATE(LineTwo, createLine);238 CREATE(LineThree, createLine);239 CREATE(LineFour, createLine);240 CREATE(LineFive, createLine);241 CREATE(LineSix, createLine);242 243 // Create the logical locations.244 CREATE_CUSTOM(LocationOne, createCustomLocation);245 CREATE_CUSTOM(LocationTwo, createCustomLocation);246 CREATE_CUSTOM(LocationThree, createCustomLocation);247 CREATE_CUSTOM(LocationFour, createCustomLocation);248 CREATE_CUSTOM(LocationFive, createCustomLocation);249 CREATE_CUSTOM(LocationSix, createCustomLocation);250}251 252// Create the logical view adding the created logical elements.253void ReaderTestWarningInternal::addElements() {254 setCompileUnit(CompileUnit);255 256 // Root257 // CompileUnit258 // IntegerType259 // Function260 // LocationOne261 // LocationTwo262 // LocationFive263 // LocationSix264 // Parameter265 // LocalVariable266 // LineOne267 // LineTwo268 // NestedScope269 // LocationThree270 // LocationFour271 // NestedVariable272 // LineThree273 // LineFour274 // LineFive275 // LineSix276 277 // Add elements to Root.278 add(Root, CompileUnit);279 280 // Add elements to CompileUnit.281 add(CompileUnit, IntegerType);282 add(CompileUnit, Function);283 284 // Add elements to Function.285 add(Function, Parameter);286 add(Function, LocalVariable);287 add(Function, LineOne);288 add(Function, LineTwo);289 add(Function, LineFive);290 add(Function, LineSix);291 add(Function, NestedScope);292 293 // Add elements to NestedScope.294 add(NestedScope, NestedVariable);295 add(NestedScope, LineThree);296 add(NestedScope, LineFour);297}298 299void ReaderTestWarningInternal::resolveElements() {300 // Traverse the given scope and its children checking for any warnings.301 std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) {302 auto Warnings = [&](auto *Entry) {303 if (Entry->getIsLine()) {304 LVLine *Line = (LVLine *)Entry;305 if (options().getWarningLines() && Line->getIsLineDebug() &&306 !Line->getLineNumber())307 CompileUnit->addLineZero(Line);308 }309 };310 auto Traverse = [&](const auto *Set) {311 if (Set)312 for (const auto &Entry : *Set) {313 Warnings(Entry);314 }315 };316 317 Warnings(Parent);318 319 Traverse(Parent->getSymbols());320 Traverse(Parent->getTypes());321 Traverse(Parent->getLines());322 323 if (const LVScopes *Scopes = Parent->getScopes())324 for (LVScope *Scope : *Scopes) {325 Warnings(Scope);326 TraverseScope(Scope);327 }328 };329 330 // Start traversing the scopes root and resolve the elements.331 TraverseScope(Root);332}333 334// Set initial values to logical elements.335void ReaderTestWarningInternal::initElements() {336 // Types.337 set(IntegerType, "int", 0x1000);338 339 // Scopes.340 set(CompileUnit, "foo.cpp", 0x2000);341 set(Function, "foo", 0x2010, 100, IntegerType);342 set(NestedScope, "", 0x2020, 300);343 344 // Symbols.345 set(Parameter, "Param", 0x3000, 110, IntegerType);346 set(LocalVariable, "LocalVariable", 0x3020, 120, IntegerType);347 set(NestedVariable, "NestedVariable", 0x3010, 310, IntegerType);348 349 // Lines.350 set(LineOne, "", 0x5000, 100);351 LineOne->setIsLineDebug();352 set(LineTwo, "", 0x5200, 000);353 LineTwo->setIsLineDebug();354 set(LineThree, "", 0x5400, 300);355 LineThree->setIsLineDebug();356 set(LineFour, "", 0x5600, 000);357 LineFour->setIsLineDebug();358 set(LineFive, "", 0x5800, 500);359 LineOne->setIsLineDebug();360 set(LineSix, "", 0x6000, 600);361 LineSix->setIsLineDebug();362 363 // Locations.364 set(LocationOne, LineOne, LineOne, 0x5000, 0x5100);365 EXPECT_STREQ(LocationOne->getIntervalInfo().c_str(),366 " Lines 100:100 [0x0000005000:0x0000005100]");367 368 // Uses a Line zero.369 set(LocationTwo, LineTwo, LineTwo, 0x5200, 0x5300);370 EXPECT_STREQ(LocationTwo->getIntervalInfo().c_str(),371 " Lines -:- [0x0000005200:0x0000005300]");372 373 set(LocationThree, LineThree, LineThree, 0x5400, 0x5500);374 EXPECT_STREQ(LocationThree->getIntervalInfo().c_str(),375 " Lines 300:300 [0x0000005400:0x0000005500]");376 377 // Uses a Line zero.378 set(LocationFour, LineFour, LineFour, 0x5600, 0x5700);379 LocationFour->setIsAddressRange();380 EXPECT_STREQ(LocationFour->getIntervalInfo().c_str(),381 "{Range} Lines -:- [0x0000005600:0x0000005700]");382 383 // Invalid range.384 set(LocationFive, LineFive, LineFive, 0x7800, 0x5900);385 LocationFive->setIsAddressRange();386 EXPECT_STREQ(LocationFive->getIntervalInfo().c_str(),387 "{Range} Lines 500:500 [0x0000007800:0x0000005900]");388 389 set(LocationSix, LineSix, LineSix, 0x6000, 0x6100);390 LocationSix->setIsAddressRange();391 EXPECT_STREQ(LocationSix->getIntervalInfo().c_str(),392 "{Range} Lines 600:600 [0x0000006000:0x0000006100]");393 394 // Add ranges to Function.395 // Function: LocationOne, LocationTwo, LocationFive, LocationSix396 Function->addObject(LocationOne);397 Function->addObject(LocationTwo);398 Function->addObject(LocationFive);399 Function->addObject(LocationSix);400 EXPECT_EQ(Function->rangeCount(), 4u);401 402 // Add ranges to NestedScope.403 // NestedScope: LocationThree, LocationFour404 NestedScope->addObject(LocationThree);405 NestedScope->addObject(LocationFour);406 EXPECT_EQ(NestedScope->rangeCount(), 2u);407 408 // Get all ranges.409 LVRange Ranges;410 CompileUnit->getRanges(Ranges);411 Ranges.startSearch();412 EXPECT_EQ(Ranges.getEntry(0x4000), nullptr);413 414 EXPECT_EQ(Ranges.getEntry(0x5060), Function);415 EXPECT_EQ(Ranges.getEntry(0x5850), nullptr);416 EXPECT_EQ(Ranges.getEntry(0x5010, 0x5090), Function);417 EXPECT_EQ(Ranges.getEntry(0x5210, 0x5290), Function);418 EXPECT_EQ(Ranges.getEntry(0x5810, 0x5890), nullptr);419 EXPECT_EQ(Ranges.getEntry(0x6010, 0x6090), Function);420 421 EXPECT_EQ(Ranges.getEntry(0x5400), NestedScope);422 EXPECT_EQ(Ranges.getEntry(0x5650), NestedScope);423 EXPECT_EQ(Ranges.getEntry(0x5410, 0x5490), NestedScope);424 EXPECT_EQ(Ranges.getEntry(0x5610, 0x5690), NestedScope);425 426 EXPECT_EQ(Ranges.getEntry(0x8000), nullptr);427 Ranges.endSearch();428 429 // Add locations to symbols.430 // Parameter: [LineOne, LineSix]431 // LocalVariable: [LineTwo, LineSix], [LineFour, LineFive]432 // NestedVariable: [LineThree, LineFour]433 add(Parameter, LineOne, LineSix);434 add(LocalVariable, LineTwo, LineSix);435 add(LocalVariable, LineFour, LineFive);436 add(NestedVariable, LineThree, LineFour);437 add(NestedVariable, LineOne, LineSix);438}439 440// Check logical elements warnigs.441void ReaderTestWarningInternal::checkWarnings() {442 // Map all lines with their addresses.443 setMapping();444 445 // Check for lines with line zero.446 resolveElements();447 448 // Check invalid locations and ranges using a customized validation.449 CompileUnit->processRangeLocationCoverage(450 (LVValidLocation)(&MyLocation::validateRanges));451 452 // Get lines with line zero. [Parent, Line]453 // Function, LineTwo454 // NestedScope, LineFour455 LVOffsetLinesMap LinesZero = CompileUnit->getLinesZero();456 ASSERT_EQ(LinesZero.size(), 2u);457 458 LVOffsetLinesMap::iterator IterZero = LinesZero.begin();459 EXPECT_EQ(IterZero->first, Function->getOffset());460 LVLines *Lines = &IterZero->second;461 EXPECT_NE(Lines, nullptr);462 ASSERT_EQ(Lines->size(), 1u);463 LVLine *Line = *(Lines->begin());464 EXPECT_NE(Line, nullptr);465 EXPECT_EQ(Line, LineTwo);466 467 ++IterZero;468 EXPECT_EQ(IterZero->first, NestedScope->getOffset());469 Lines = &IterZero->second;470 EXPECT_NE(Lines, nullptr);471 ASSERT_EQ(Lines->size(), 1u);472 Line = *(Lines->begin());473 EXPECT_NE(Line, nullptr);474 EXPECT_EQ(Line, LineFour);475 476 // Elements with invalid offsets.477 // Function (line zero)478 // NestedScope (line zero)479 // NestedVariable (invalid location)480 LVOffsetElementMap InvalidOffsets = CompileUnit->getWarningOffsets();481 ASSERT_EQ(InvalidOffsets.size(), 3u);482 483 LVOffsetElementMap::iterator IterOffset = InvalidOffsets.begin();484 EXPECT_EQ(IterOffset->second, Function);485 ++IterOffset;486 EXPECT_EQ(IterOffset->second, NestedScope);487 ++IterOffset;488 EXPECT_EQ(IterOffset->second, NestedVariable);489 490 // Invalid ranges.491 // Function492 LVOffsetLocationsMap InvalidRanges = CompileUnit->getInvalidRanges();493 ASSERT_EQ(InvalidRanges.size(), 1u);494 495 LVOffsetLocationsMap::iterator IterRange = InvalidRanges.begin();496 EXPECT_EQ(IterRange->first, Function->getOffset());497 LVLocations *Locations = &IterRange->second;498 EXPECT_NE(Locations, nullptr);499 ASSERT_EQ(Locations->size(), 1u);500 LVLocation *Location = *(Locations->begin());501 EXPECT_NE(Location, nullptr);502 EXPECT_EQ(Location, LocationFive);503 504 // Invalid location.505 // NestedVariable506 LVOffsetLocationsMap InvalidLocations = CompileUnit->getInvalidLocations();507 ASSERT_EQ(InvalidLocations.size(), 1u);508 509 LVOffsetLocationsMap::iterator IterLocations = InvalidLocations.begin();510 EXPECT_EQ(IterLocations->first, NestedVariable->getOffset());511 Locations = &IterLocations->second;512 EXPECT_NE(Locations, nullptr);513 ASSERT_EQ(Locations->size(), 1u);514 Location = *(Locations->begin());515 EXPECT_NE(Location, nullptr);516 EXPECT_EQ(Location->getLowerAddress(), LocationThree->getLowerAddress());517 EXPECT_EQ(Location->getUpperAddress(), LocationFour->getLowerAddress());518 EXPECT_EQ(Location->getLowerLine()->getLineNumber(),519 LineThree->getLineNumber());520 EXPECT_EQ(Location->getUpperLine()->getLineNumber(), 0u);521 522 // Invalid coverages.523 // NestedVariable524 LVOffsetSymbolMap InvalidCoverages = CompileUnit->getInvalidCoverages();525 ASSERT_EQ(InvalidCoverages.size(), 1u);526 527 LVOffsetSymbolMap::iterator IterCoverages = InvalidCoverages.begin();528 EXPECT_EQ(IterCoverages->first, NestedVariable->getOffset());529 EXPECT_EQ(IterCoverages->second, NestedVariable);530 EXPECT_GE((int)NestedVariable->getCoveragePercentage(), 100);531 EXPECT_EQ((int)NestedVariable->getCoveragePercentage(), 900);532 EXPECT_EQ(NestedVariable->getCoverageFactor(), 0x1200u);533 534 EXPECT_EQ((unsigned)Parameter->getCoveragePercentage(), 100u);535 EXPECT_EQ(Parameter->getCoverageFactor(), 100u);536 537 EXPECT_EQ((unsigned)LocalVariable->getCoveragePercentage(), 47u);538 EXPECT_EQ(LocalVariable->getCoverageFactor(),539 LineSix->getAddress() - LineOne->getAddress());540}541 542TEST(LogicalViewTest, WarningInternal) {543 ScopedPrinter W(outs());544 ReaderTestWarningInternal Reader(W);545 546 // Reader options.547 LVOptions ReaderOptions;548 ReaderOptions.setAttributeOffset();549 ReaderOptions.setAttributeRange();550 ReaderOptions.setAttributeLocation();551 ReaderOptions.setPrintAll();552 ReaderOptions.setWarningCoverages();553 ReaderOptions.setWarningLines();554 ReaderOptions.setWarningLocations();555 ReaderOptions.setWarningRanges();556 ReaderOptions.resolveDependencies();557 options().setOptions(&ReaderOptions);558 559 Reader.createElements();560 Reader.addElements();561 Reader.initElements();562 Reader.checkWarnings();563}564 565} // namespace566