xref: /llvm-project/llvm/unittests/DebugInfo/LogicalView/WarningInternalTest.cpp (revision 7fbcc24409efdb37cec79ad461ef383f6ffc5ef2)
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-exception
6 //
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 
20 using namespace llvm;
21 using namespace llvm::logicalview;
22 
23 namespace {
24 
25 class MyLocation : public LVLocation {
26 public:
27   bool validateRanges();
28 };
29 
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;
36 
37 public:
38   MyAddressToLine() = default;
39 
insert(LVLine * Line)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 
lineLowerBound(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;
51 }
52 
lineUpperBound(LVAddress Address)53 LVLine *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 
62 MyAddressToLine AddressToLine;
63 
64 class 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 
103 protected:
createCustomLocation()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 
115 public:
ReaderTestWarningInternal(ScopedPrinter & W)116   ReaderTestWarningInternal(ScopedPrinter &W) : LVReader("", "", W) {
117     setInstance(this);
118   }
119 
createScopes()120   Error createScopes() { return LVReader::createScopes(); }
121 
122   void setMapping();
123   void createElements();
124   void addElements();
125   void initElements();
126   void resolveElements();
127   void checkWarnings();
128 };
129 
validateRanges()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.
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.
setMapping()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);
168 }
169 
170 // Helper function to add a logical element to a given scope.
add(LVScope * Parent,LVElement * Child)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);
175 }
176 
177 // Helper function to set the initial values for a given logical element.
set(LVElement * Element,StringRef Name,LVOffset Offset,uint32_t LineNumber,LVElement * Type)178 void 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.
set(MyLocation * Location,LVLine * LowerLine,LVLine * UpperLine,LVAddress LowerAddress,LVAddress UpperAddress)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);
203 }
204 
205 // Helper function to add a logical location to a logical symbol.
add(LVSymbol * Symbol,LVLine * LowerLine,LVLine * UpperLine)206 void 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.
createElements()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);
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.
addElements()253 void ReaderTestWarningInternal::addElements() {
254   setCompileUnit(CompileUnit);
255 
256   // Root
257   //   CompileUnit
258   //     IntegerType
259   //     Function
260   //       LocationOne
261   //       LocationTwo
262   //       LocationFive
263   //       LocationSix
264   //       Parameter
265   //       LocalVariable
266   //       LineOne
267   //       LineTwo
268   //       NestedScope
269   //         LocationThree
270   //         LocationFour
271   //         NestedVariable
272   //         LineThree
273   //         LineFour
274   //       LineFive
275   //       LineSix
276 
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 
resolveElements()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);
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.
initElements()335 void 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, LocationSix
396   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, LocationFour
404   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.
checkWarnings()441 void 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, LineTwo
454   //   NestedScope, LineFour
455   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   //   Function
492   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   //   NestedVariable
506   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   //   NestedVariable
524   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 
TEST(LogicalViewTest,WarningInternal)542 TEST(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 } // namespace
566