1 //===- llvm/unittest/DebugInfo/LogicalView/WarningInternalTest.cpp --------===//
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-exception
7 //===----------------------------------------------------------------------===//
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"
18 #include "gtest/gtest.h"
21 using namespace llvm::logicalview
;
25 class MyLocation
: public LVLocation
{
27 bool validateRanges();
30 // This code emulates the work done by the Readers when processing the
31 // binary files and the creation of the AddressToLine mapping is done
32 // automatically, using the text sections.
33 class MyAddressToLine
{
34 using LVAddressToLine
= std::map
<LVAddress
, LVLine
*>;
35 LVAddressToLine AddressToLineData
;
38 MyAddressToLine() = default;
40 void insert(LVLine
*Line
) {
41 AddressToLineData
.emplace(Line
->getOffset(), Line
);
44 LVLine
*lineLowerBound(LVAddress Address
);
45 LVLine
*lineUpperBound(LVAddress Address
);
48 LVLine
*MyAddressToLine::lineLowerBound(LVAddress Address
) {
49 LVAddressToLine::const_iterator Iter
= AddressToLineData
.lower_bound(Address
);
50 return (Iter
!= AddressToLineData
.end()) ? Iter
->second
: nullptr;
53 LVLine
*MyAddressToLine::lineUpperBound(LVAddress Address
) {
54 if (AddressToLineData
.empty())
56 LVAddressToLine::const_iterator Iter
= AddressToLineData
.upper_bound(Address
);
57 if (Iter
!= AddressToLineData
.begin())
58 Iter
= std::prev(Iter
);
62 MyAddressToLine AddressToLine
;
64 class ReaderTestWarningInternal
: public LVReader
{
65 #define CREATE(VARIABLE, CREATE_FUNCTION) \
66 VARIABLE = CREATE_FUNCTION(); \
67 EXPECT_NE(VARIABLE, nullptr);
69 #define CREATE_CUSTOM(VARIABLE, CREATE_FUNCTION) \
70 VARIABLE = CREATE_FUNCTION(); \
71 EXPECT_NE(VARIABLE, nullptr);
74 LVType
*IntegerType
= nullptr;
77 LVScope
*NestedScope
= nullptr;
78 LVScopeFunction
*Function
= nullptr;
81 LVSymbol
*LocalVariable
= nullptr;
82 LVSymbol
*NestedVariable
= nullptr;
83 LVSymbol
*Parameter
= nullptr;
86 LVLine
*LineOne
= nullptr;
87 LVLine
*LineTwo
= nullptr;
88 LVLine
*LineThree
= nullptr;
89 LVLine
*LineFour
= nullptr;
90 LVLine
*LineFive
= nullptr;
91 LVLine
*LineSix
= nullptr;
94 MyLocation
*LocationOne
= nullptr;
95 MyLocation
*LocationTwo
= nullptr;
96 MyLocation
*LocationThree
= nullptr;
97 MyLocation
*LocationFour
= nullptr;
98 MyLocation
*LocationFive
= nullptr;
99 MyLocation
*LocationSix
= nullptr;
101 llvm::SpecificBumpPtrAllocator
<MyLocation
> AllocatedLocations
;
104 MyLocation
*createCustomLocation() {
105 return new (AllocatedLocations
.Allocate()) MyLocation();
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
);
116 ReaderTestWarningInternal(ScopedPrinter
&W
) : LVReader("", "", W
) {
120 Error
createScopes() { return LVReader::createScopes(); }
123 void createElements();
126 void resolveElements();
127 void checkWarnings();
130 bool MyLocation::validateRanges() {
131 // Traverse the locations and validate them against the address to line
132 // 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.
137 LVLine
*LowLine
= AddressToLine
.lineLowerBound(getLowerAddress());
138 LVLine
*HighLine
= AddressToLine
.lineUpperBound(getUpperAddress());
140 setLowerLine(LowLine
);
146 setUpperLine(HighLine
);
151 // Check for a valid interval.
152 if (LowLine
->getLineNumber() > HighLine
->getLineNumber()) {
160 // Map all logical lines with their addresses.
161 void 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
);
170 // Helper function to add a logical element to a given scope.
171 void ReaderTestWarningInternal::add(LVScope
*Parent
, LVElement
*Child
) {
172 Parent
->addElement(Child
);
173 EXPECT_EQ(Child
->getParent(), Parent
);
174 EXPECT_EQ(Child
->getLevel(), Parent
->getLevel() + 1);
177 // Helper function to set the initial values for a given logical element.
178 void ReaderTestWarningInternal::set(LVElement
*Element
, StringRef Name
,
179 LVOffset Offset
, uint32_t LineNumber
,
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
);
191 // Helper function to set the initial values for a given logical location.
192 void 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
);
205 // Helper function to add a logical location to a logical symbol.
206 void ReaderTestWarningInternal::add(LVSymbol
*Symbol
, LVLine
*LowerLine
,
208 dwarf::Attribute Attr
= dwarf::DW_AT_location
;
210 Symbol
->addLocation(Attr
, LowerLine
->getAddress(), UpperLine
->getAddress(),
211 /*SectionOffset=*/0, /*LocDesOffset=*/0);
214 // Create the logical elements.
215 void 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);
222 // Create the logical types.
223 CREATE(IntegerType
, createType
);
225 // Create the logical scopes.
226 CREATE(NestedScope
, createScope
);
227 CREATE(CompileUnit
, createScopeCompileUnit
);
228 CREATE(Function
, createScopeFunction
);
230 // Create the logical symbols.
231 CREATE(LocalVariable
, createSymbol
);
232 CREATE(NestedVariable
, createSymbol
);
233 CREATE(Parameter
, createSymbol
);
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
);
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
);
252 // Create the logical view adding the created logical elements.
253 void ReaderTestWarningInternal::addElements() {
254 setCompileUnit(CompileUnit
);
277 // Add elements to Root.
278 add(Root
, CompileUnit
);
280 // Add elements to CompileUnit.
281 add(CompileUnit
, IntegerType
);
282 add(CompileUnit
, Function
);
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
);
293 // Add elements to NestedScope.
294 add(NestedScope
, NestedVariable
);
295 add(NestedScope
, LineThree
);
296 add(NestedScope
, LineFour
);
299 void 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
);
310 auto Traverse
= [&](const auto *Set
) {
312 for (const auto &Entry
: *Set
) {
319 Traverse(Parent
->getSymbols());
320 Traverse(Parent
->getTypes());
321 Traverse(Parent
->getLines());
323 if (const LVScopes
*Scopes
= Parent
->getScopes())
324 for (LVScope
*Scope
: *Scopes
) {
326 TraverseScope(Scope
);
330 // Start traversing the scopes root and resolve the elements.
334 // Set initial values to logical elements.
335 void ReaderTestWarningInternal::initElements() {
337 set(IntegerType
, "int", 0x1000);
340 set(CompileUnit
, "foo.cpp", 0x2000);
341 set(Function
, "foo", 0x2010, 100, IntegerType
);
342 set(NestedScope
, "", 0x2020, 300);
345 set(Parameter
, "Param", 0x3000, 110, IntegerType
);
346 set(LocalVariable
, "LocalVariable", 0x3020, 120, IntegerType
);
347 set(NestedVariable
, "NestedVariable", 0x3010, 310, IntegerType
);
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();
364 set(LocationOne
, LineOne
, LineOne
, 0x5000, 0x5100);
365 EXPECT_STREQ(LocationOne
->getIntervalInfo().c_str(),
366 " Lines 100:100 [0x0000005000:0x0000005100]");
369 set(LocationTwo
, LineTwo
, LineTwo
, 0x5200, 0x5300);
370 EXPECT_STREQ(LocationTwo
->getIntervalInfo().c_str(),
371 " Lines -:- [0x0000005200:0x0000005300]");
373 set(LocationThree
, LineThree
, LineThree
, 0x5400, 0x5500);
374 EXPECT_STREQ(LocationThree
->getIntervalInfo().c_str(),
375 " Lines 300:300 [0x0000005400:0x0000005500]");
378 set(LocationFour
, LineFour
, LineFour
, 0x5600, 0x5700);
379 LocationFour
->setIsAddressRange();
380 EXPECT_STREQ(LocationFour
->getIntervalInfo().c_str(),
381 "{Range} Lines -:- [0x0000005600:0x0000005700]");
384 set(LocationFive
, LineFive
, LineFive
, 0x7800, 0x5900);
385 LocationFive
->setIsAddressRange();
386 EXPECT_STREQ(LocationFive
->getIntervalInfo().c_str(),
387 "{Range} Lines 500:500 [0x0000007800:0x0000005900]");
389 set(LocationSix
, LineSix
, LineSix
, 0x6000, 0x6100);
390 LocationSix
->setIsAddressRange();
391 EXPECT_STREQ(LocationSix
->getIntervalInfo().c_str(),
392 "{Range} Lines 600:600 [0x0000006000:0x0000006100]");
394 // Add ranges to Function.
395 // Function: LocationOne, LocationTwo, LocationFive, LocationSix
396 Function
->addObject(LocationOne
);
397 Function
->addObject(LocationTwo
);
398 Function
->addObject(LocationFive
);
399 Function
->addObject(LocationSix
);
400 EXPECT_EQ(Function
->rangeCount(), 4u);
402 // Add ranges to NestedScope.
403 // NestedScope: LocationThree, LocationFour
404 NestedScope
->addObject(LocationThree
);
405 NestedScope
->addObject(LocationFour
);
406 EXPECT_EQ(NestedScope
->rangeCount(), 2u);
410 CompileUnit
->getRanges(Ranges
);
411 Ranges
.startSearch();
412 EXPECT_EQ(Ranges
.getEntry(0x4000), nullptr);
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
);
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
);
426 EXPECT_EQ(Ranges
.getEntry(0x8000), nullptr);
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
);
440 // Check logical elements warnigs.
441 void ReaderTestWarningInternal::checkWarnings() {
442 // Map all lines with their addresses.
445 // Check for lines with line zero.
448 // Check invalid locations and ranges using a customized validation.
449 CompileUnit
->processRangeLocationCoverage(
450 (LVValidLocation
)(&MyLocation::validateRanges
));
452 // Get lines with line zero. [Parent, Line]
454 // NestedScope, LineFour
455 LVOffsetLinesMap LinesZero
= CompileUnit
->getLinesZero();
456 ASSERT_EQ(LinesZero
.size(), 2u);
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
);
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
);
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);
483 LVOffsetElementMap::iterator IterOffset
= InvalidOffsets
.begin();
484 EXPECT_EQ(IterOffset
->second
, Function
);
486 EXPECT_EQ(IterOffset
->second
, NestedScope
);
488 EXPECT_EQ(IterOffset
->second
, NestedVariable
);
492 LVOffsetLocationsMap InvalidRanges
= CompileUnit
->getInvalidRanges();
493 ASSERT_EQ(InvalidRanges
.size(), 1u);
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
);
506 LVOffsetLocationsMap InvalidLocations
= CompileUnit
->getInvalidLocations();
507 ASSERT_EQ(InvalidLocations
.size(), 1u);
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);
522 // Invalid coverages.
524 LVOffsetSymbolMap InvalidCoverages
= CompileUnit
->getInvalidCoverages();
525 ASSERT_EQ(InvalidCoverages
.size(), 1u);
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
);
534 EXPECT_EQ((unsigned)Parameter
->getCoveragePercentage(), 100u);
535 EXPECT_EQ(Parameter
->getCoverageFactor(), 100u);
537 EXPECT_EQ((unsigned)LocalVariable
->getCoveragePercentage(), 47u);
538 EXPECT_EQ(LocalVariable
->getCoverageFactor(),
539 LineSix
->getAddress() - LineOne
->getAddress());
542 TEST(LogicalViewTest
, WarningInternal
) {
543 ScopedPrinter
W(outs());
544 ReaderTestWarningInternal
Reader(W
);
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
);
559 Reader
.createElements();
560 Reader
.addElements();
561 Reader
.initElements();
562 Reader
.checkWarnings();