xref: /llvm-project/llvm/unittests/DebugInfo/LogicalView/CodeViewReaderTest.cpp (revision e7950fceb1e7f82370f6cff80b258e552eb410a6)
1 //===- llvm/unittest/DebugInfo/LogicalView/CodeViewReaderTest.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/LVCompare.h"
10 #include "llvm/DebugInfo/LogicalView/Core/LVLine.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/DebugInfo/LogicalView/LVReaderHandler.h"
15 #include "llvm/MC/TargetRegistry.h"
16 #include "llvm/Support/COM.h"
17 #include "llvm/Support/InitLLVM.h"
18 #include "llvm/Support/ScopedPrinter.h"
19 #include "llvm/Support/TargetSelect.h"
20 #include "llvm/Support/ToolOutputFile.h"
21 #include "llvm/Testing/Support/Error.h"
22 
23 #include "gtest/gtest.h"
24 
25 using namespace llvm;
26 using namespace llvm::logicalview;
27 
28 extern const char *TestMainArgv0;
29 
30 namespace {
31 
32 const char *CodeViewClang = "test-codeview-clang.o";
33 const char *CodeViewMsvc = "test-codeview-msvc.o";
34 const char *CodeViewPdbMsvc = "test-codeview-pdb-msvc.o";
35 
36 // Helper function to get the first scope child from the given parent.
37 LVScope *getFirstScopeChild(LVScope *Parent) {
38   EXPECT_NE(Parent, nullptr);
39   const LVScopes *Scopes = Parent->getScopes();
40   EXPECT_NE(Scopes, nullptr);
41   EXPECT_EQ(Scopes->size(), 1u);
42 
43   LVScopes::const_iterator Iter = Scopes->begin();
44   LVScope *Child = *Iter;
45   EXPECT_NE(Child, nullptr);
46   return Child;
47 }
48 
49 // Helper function to create a reader.
50 std::unique_ptr<LVReader> createReader(LVReaderHandler &ReaderHandler,
51                                        SmallString<128> &InputsDir,
52                                        StringRef Filename) {
53   SmallString<128> ObjectName(InputsDir);
54   llvm::sys::path::append(ObjectName, Filename);
55 
56   Expected<std::unique_ptr<LVReader>> ReaderOrErr =
57       ReaderHandler.createReader(std::string(ObjectName));
58   EXPECT_THAT_EXPECTED(ReaderOrErr, Succeeded());
59   std::unique_ptr<LVReader> Reader = std::move(*ReaderOrErr);
60   EXPECT_NE(Reader, nullptr);
61   return Reader;
62 }
63 
64 // Check the logical elements basic properties (Clang - Codeview).
65 void checkElementPropertiesClangCodeview(LVReader *Reader) {
66   LVScopeRoot *Root = Reader->getScopesRoot();
67   LVScopeCompileUnit *CompileUnit =
68       static_cast<LVScopeCompileUnit *>(getFirstScopeChild(Root));
69   LVScopeFunction *Function =
70       static_cast<LVScopeFunction *>(getFirstScopeChild(CompileUnit));
71 
72   EXPECT_EQ(Root->getFileFormatName(), "COFF-x86-64");
73   EXPECT_EQ(Root->getName(), CodeViewClang);
74 
75   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
76   EXPECT_TRUE(CompileUnit->getProducer().startswith("clang"));
77   EXPECT_EQ(CompileUnit->getName(), "test.cpp");
78 
79   EXPECT_EQ(Function->lineCount(), 16u);
80   EXPECT_EQ(Function->scopeCount(), 1u);
81   EXPECT_EQ(Function->symbolCount(), 3u);
82   EXPECT_EQ(Function->typeCount(), 1u);
83   EXPECT_EQ(Function->rangeCount(), 1u);
84 
85   const LVLocations *Ranges = Function->getRanges();
86   ASSERT_NE(Ranges, nullptr);
87   ASSERT_EQ(Ranges->size(), 1u);
88   LVLocations::const_iterator IterLocation = Ranges->begin();
89   LVLocation *Location = (*IterLocation);
90   EXPECT_STREQ(Location->getIntervalInfo().c_str(),
91                "{Range} Lines 2:9 [0x0000000000:0x0000000046]");
92 
93   LVRange RangeList;
94   Function->getRanges(RangeList);
95 
96   const LVRangeEntries &RangeEntries = RangeList.getEntries();
97   ASSERT_EQ(RangeEntries.size(), 2u);
98   LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();
99   LVRangeEntry RangeEntry = *IterRanges;
100   EXPECT_EQ(RangeEntry.lower(), 0u);
101   EXPECT_EQ(RangeEntry.upper(), 0x46u);
102   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
103   EXPECT_EQ(RangeEntry.scope()->getName(), "foo");
104   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0u);
105 
106   ++IterRanges;
107   RangeEntry = *IterRanges;
108   EXPECT_EQ(RangeEntry.lower(), 0x21u);
109   EXPECT_EQ(RangeEntry.upper(), 0x35u);
110   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
111   EXPECT_EQ(RangeEntry.scope()->getName(), "foo::?");
112   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0u);
113 
114   const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
115   ASSERT_EQ(PublicNames.size(), 1u);
116   LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
117   LVScope *Foo = (*IterNames).first;
118   EXPECT_EQ(Foo->getName(), "foo");
119   EXPECT_EQ(Foo->getLineNumber(), 0u);
120   LVNameInfo NameInfo = (*IterNames).second;
121   EXPECT_EQ(NameInfo.first, 0u);
122   EXPECT_EQ(NameInfo.second, 0x46u);
123 
124   // Lines (debug and assembler) for 'foo'.
125   const LVLines *Lines = Foo->getLines();
126   ASSERT_NE(Lines, nullptr);
127   EXPECT_EQ(Lines->size(), 0x10u);
128 }
129 
130 // Check the logical elements basic properties (MSVC - Codeview).
131 void checkElementPropertiesMsvcCodeview(LVReader *Reader) {
132   LVScopeRoot *Root = Reader->getScopesRoot();
133   LVScopeCompileUnit *CompileUnit =
134       static_cast<LVScopeCompileUnit *>(getFirstScopeChild(Root));
135   LVScopeFunction *Function =
136       static_cast<LVScopeFunction *>(getFirstScopeChild(CompileUnit));
137 
138   EXPECT_EQ(Root->getFileFormatName(), "COFF-x86-64");
139   EXPECT_EQ(Root->getName(), CodeViewMsvc);
140 
141   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
142   EXPECT_TRUE(CompileUnit->getProducer().startswith("Microsoft"));
143   EXPECT_EQ(CompileUnit->getName(), "test.cpp");
144 
145   EXPECT_EQ(Function->lineCount(), 14u);
146   EXPECT_EQ(Function->scopeCount(), 1u);
147   EXPECT_EQ(Function->symbolCount(), 3u);
148   EXPECT_EQ(Function->typeCount(), 0u);
149   EXPECT_EQ(Function->rangeCount(), 1u);
150 
151   const LVLocations *Ranges = Function->getRanges();
152   ASSERT_NE(Ranges, nullptr);
153   ASSERT_EQ(Ranges->size(), 1u);
154   LVLocations::const_iterator IterLocation = Ranges->begin();
155   LVLocation *Location = (*IterLocation);
156   EXPECT_STREQ(Location->getIntervalInfo().c_str(),
157                "{Range} Lines 2:9 [0x0000000000:0x0000000031]");
158 
159   LVRange RangeList;
160   Function->getRanges(RangeList);
161 
162   const LVRangeEntries &RangeEntries = RangeList.getEntries();
163   ASSERT_EQ(RangeEntries.size(), 2u);
164   LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();
165   LVRangeEntry RangeEntry = *IterRanges;
166   EXPECT_EQ(RangeEntry.lower(), 0u);
167   EXPECT_EQ(RangeEntry.upper(), 0x31u);
168   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
169   EXPECT_EQ(RangeEntry.scope()->getName(), "foo");
170   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0u);
171 
172   ++IterRanges;
173   RangeEntry = *IterRanges;
174   EXPECT_EQ(RangeEntry.lower(), 0x1bu);
175   EXPECT_EQ(RangeEntry.upper(), 0x28u);
176   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
177   EXPECT_EQ(RangeEntry.scope()->getName(), "foo::?");
178   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0u);
179 
180   const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
181   ASSERT_EQ(PublicNames.size(), 1u);
182   LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
183   LVScope *Foo = (*IterNames).first;
184   EXPECT_EQ(Foo->getName(), "foo");
185   EXPECT_EQ(Foo->getLineNumber(), 0u);
186   LVNameInfo NameInfo = (*IterNames).second;
187   EXPECT_EQ(NameInfo.first, 0u);
188   EXPECT_EQ(NameInfo.second, 0x31u);
189 
190   // Lines (debug and assembler) for 'foo'.
191   const LVLines *Lines = Foo->getLines();
192   ASSERT_NE(Lines, nullptr);
193   EXPECT_EQ(Lines->size(), 0x0eu);
194 }
195 
196 // Check the logical elements basic properties (MSVC - PDB).
197 void checkElementPropertiesMsvcCodeviewPdb(LVReader *Reader) {
198   LVScopeRoot *Root = Reader->getScopesRoot();
199   LVScopeCompileUnit *CompileUnit =
200       static_cast<LVScopeCompileUnit *>(getFirstScopeChild(Root));
201   LVScopeFunction *Function =
202       static_cast<LVScopeFunction *>(getFirstScopeChild(CompileUnit));
203 
204   EXPECT_EQ(Root->getFileFormatName(), "COFF-x86-64");
205   EXPECT_EQ(Root->getName(), CodeViewPdbMsvc);
206 
207   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
208   EXPECT_TRUE(CompileUnit->getProducer().startswith("Microsoft"));
209   EXPECT_EQ(CompileUnit->getName(), "test.cpp");
210 
211   EXPECT_EQ(Function->lineCount(), 14u);
212   EXPECT_EQ(Function->scopeCount(), 1u);
213   EXPECT_EQ(Function->symbolCount(), 3u);
214   EXPECT_EQ(Function->typeCount(), 0u);
215   EXPECT_EQ(Function->rangeCount(), 1u);
216 
217   const LVLocations *Ranges = Function->getRanges();
218   ASSERT_NE(Ranges, nullptr);
219   ASSERT_EQ(Ranges->size(), 1u);
220   LVLocations::const_iterator IterLocation = Ranges->begin();
221   LVLocation *Location = (*IterLocation);
222   EXPECT_STREQ(Location->getIntervalInfo().c_str(),
223                "{Range} Lines 2:9 [0x0000000000:0x0000000031]");
224 
225   LVRange RangeList;
226   Function->getRanges(RangeList);
227 
228   const LVRangeEntries &RangeEntries = RangeList.getEntries();
229   ASSERT_EQ(RangeEntries.size(), 2u);
230   LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();
231   LVRangeEntry RangeEntry = *IterRanges;
232   EXPECT_EQ(RangeEntry.lower(), 0u);
233   EXPECT_EQ(RangeEntry.upper(), 0x31u);
234   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
235   EXPECT_EQ(RangeEntry.scope()->getName(), "foo");
236   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0u);
237 
238   ++IterRanges;
239   RangeEntry = *IterRanges;
240   EXPECT_EQ(RangeEntry.lower(), 0x1bu);
241   EXPECT_EQ(RangeEntry.upper(), 0x28u);
242   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
243   EXPECT_EQ(RangeEntry.scope()->getName(), "foo::?");
244   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0u);
245 
246   const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
247   ASSERT_EQ(PublicNames.size(), 1u);
248   LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
249   LVScope *Foo = (*IterNames).first;
250   EXPECT_EQ(Foo->getName(), "foo");
251   EXPECT_EQ(Foo->getLineNumber(), 0u);
252   LVNameInfo NameInfo = (*IterNames).second;
253   EXPECT_EQ(NameInfo.first, 0u);
254   EXPECT_EQ(NameInfo.second, 0x31u);
255 
256   // Lines (debug and assembler) for 'foo'.
257   const LVLines *Lines = Foo->getLines();
258   ASSERT_NE(Lines, nullptr);
259   EXPECT_EQ(Lines->size(), 0x0eu);
260 }
261 
262 struct SelectionInfo {
263   const char *Name;
264   LVElementGetFunction Function;
265 };
266 
267 // Check the logical elements selection.
268 void checkElementSelection(LVReader *Reader, std::vector<SelectionInfo> &Data,
269                            size_t Size) {
270   LVScopeRoot *Root = Reader->getScopesRoot();
271   LVScopeCompileUnit *CompileUnit =
272       static_cast<LVScopeCompileUnit *>(getFirstScopeChild(Root));
273 
274   // Get the matched elements.
275   LVElements MatchedElements = CompileUnit->getMatchedElements();
276   std::map<StringRef, LVElement *> MapElements;
277   for (LVElement *Element : MatchedElements)
278     MapElements[Element->getName()] = Element;
279   ASSERT_EQ(MapElements.size(), Size);
280 
281   std::map<StringRef, LVElement *>::iterator Iter = MapElements.begin();
282   for (const SelectionInfo &Entry : Data) {
283     // Get matched element.
284     EXPECT_NE(Iter, MapElements.end());
285     LVElement *Element = Iter->second;
286     ASSERT_NE(Element, nullptr);
287     EXPECT_NE(Element->getName().find(Entry.Name), StringRef::npos);
288     EXPECT_EQ((Element->*Entry.Function)(), 1u);
289     ++Iter;
290   }
291 
292   // Get the parents for the matched elements.
293   LVScopes MatchedScopes = CompileUnit->getMatchedScopes();
294   std::set<StringRef> SetScopes;
295   for (LVScope *Scope : MatchedScopes)
296     SetScopes.insert(Scope->getName());
297   ASSERT_EQ(SetScopes.size(), 3u);
298 
299   // Parents of selected elements.
300   std::set<StringRef>::iterator IterScope;
301   IterScope = SetScopes.find("foo");
302   EXPECT_NE(IterScope, SetScopes.end());
303   IterScope = SetScopes.find("foo::?");
304   EXPECT_NE(IterScope, SetScopes.end());
305   IterScope = SetScopes.find("test.cpp");
306   EXPECT_NE(IterScope, SetScopes.end());
307 }
308 
309 // Check the logical elements comparison.
310 void checkElementComparison(LVReader *Reference, LVReader *Target) {
311   LVCompare Compare(nulls());
312   Error Err = Compare.execute(Reference, Target);
313   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
314 
315   // Get comparison table.
316   LVPassTable PassTable = Compare.getPassTable();
317   ASSERT_EQ(PassTable.size(), 2u);
318 
319   LVReader *Reader;
320   LVElement *Element;
321   LVComparePass Pass;
322 
323   // Reference: Missing TypeDefinition 'INTEGER'
324   std::tie(Reader, Element, Pass) = PassTable[0];
325   ASSERT_NE(Reader, nullptr);
326   ASSERT_NE(Element, nullptr);
327   EXPECT_EQ(Reader, Reference);
328   EXPECT_EQ(Element->getLevel(), 3u);
329   EXPECT_EQ(Element->getLineNumber(), 0u);
330   EXPECT_EQ(Element->getName(), "INTEGER");
331   EXPECT_EQ(Pass, LVComparePass::Missing);
332 
333   // Target: Added TypeDefinition 'INTEGER'
334   std::tie(Reader, Element, Pass) = PassTable[1];
335   ASSERT_NE(Reader, nullptr);
336   ASSERT_NE(Element, nullptr);
337   EXPECT_EQ(Reader, Target);
338   EXPECT_EQ(Element->getLevel(), 4u);
339   EXPECT_EQ(Element->getLineNumber(), 0u);
340   EXPECT_EQ(Element->getName(), "INTEGER");
341   EXPECT_EQ(Pass, LVComparePass::Added);
342 }
343 
344 // Logical elements properties.
345 void elementProperties(SmallString<128> &InputsDir) {
346   // Reader options.
347   LVOptions ReaderOptions;
348   ReaderOptions.setAttributeOffset();
349   ReaderOptions.setAttributeFormat();
350   ReaderOptions.setAttributeFilename();
351   ReaderOptions.setAttributeProducer();
352   ReaderOptions.setAttributePublics();
353   ReaderOptions.setAttributeRange();
354   ReaderOptions.setAttributeLocation();
355   ReaderOptions.setPrintAll();
356   ReaderOptions.resolveDependencies();
357 
358   std::vector<std::string> Objects;
359   ScopedPrinter W(outs());
360   LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
361 
362   // Check logical elements properties.
363   {
364     std::unique_ptr<LVReader> Reader =
365         createReader(ReaderHandler, InputsDir, CodeViewClang);
366     checkElementPropertiesClangCodeview(Reader.get());
367   }
368   {
369     std::unique_ptr<LVReader> Reader =
370         createReader(ReaderHandler, InputsDir, CodeViewMsvc);
371     checkElementPropertiesMsvcCodeview(Reader.get());
372   }
373   {
374     std::unique_ptr<LVReader> Reader =
375         createReader(ReaderHandler, InputsDir, CodeViewPdbMsvc);
376     checkElementPropertiesMsvcCodeviewPdb(Reader.get());
377   }
378 }
379 
380 // Logical elements selection.
381 void elementSelection(SmallString<128> &InputsDir) {
382   // Reader options.
383   LVOptions ReaderOptions;
384   ReaderOptions.setAttributeOffset();
385   ReaderOptions.setPrintAll();
386 
387   ReaderOptions.setSelectIgnoreCase();
388   ReaderOptions.setSelectUseRegex();
389 
390   ReaderOptions.setReportList(); // Matched elements.
391   ReaderOptions.setReportView(); // Parents for matched elements.
392 
393   // Add patterns.
394   ReaderOptions.Select.Generic.insert("foo");
395   ReaderOptions.Select.Generic.insert("movl[ \t]?%");
396   ReaderOptions.Select.Generic.insert("INT[a-z]*");
397   ReaderOptions.Select.Generic.insert("CONSTANT");
398 
399   ReaderOptions.resolveDependencies();
400 
401   std::vector<std::string> Objects;
402   ScopedPrinter W(outs());
403   LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
404 
405   // Check logical elements selection.
406   {
407     std::vector<SelectionInfo> DataClang = {
408         {"* const int", &LVElement::getIsType},
409         {"CONSTANT", &LVElement::getIsSymbol},
410         {"INTEGER", &LVElement::getIsType},
411         {"INTPTR", &LVElement::getIsType},
412         {"ParamPtr", &LVElement::getIsSymbol},
413         {"const int", &LVElement::getIsType},
414         {"foo", &LVElement::getIsScope},
415         {"foo::?", &LVElement::getIsScope},
416         {"int", &LVElement::getIsType},
417         {"movl", &LVElement::getIsLine},
418         {"movl", &LVElement::getIsLine}};
419     std::unique_ptr<LVReader> Reader =
420         createReader(ReaderHandler, InputsDir, CodeViewClang);
421     checkElementSelection(Reader.get(), DataClang, DataClang.size());
422   }
423   {
424     std::vector<SelectionInfo> DataMsvc = {
425         {"* const int", &LVElement::getIsType},
426         {"CONSTANT", &LVElement::getIsSymbol},
427         {"INTEGER", &LVElement::getIsType},
428         {"INTPTR", &LVElement::getIsType},
429         {"ParamPtr", &LVElement::getIsSymbol},
430         {"const int", &LVElement::getIsType},
431         {"foo", &LVElement::getIsScope},
432         {"foo::?", &LVElement::getIsScope},
433         {"int", &LVElement::getIsType},
434         {"movl", &LVElement::getIsLine}};
435     std::unique_ptr<LVReader> Reader =
436         createReader(ReaderHandler, InputsDir, CodeViewMsvc);
437     checkElementSelection(Reader.get(), DataMsvc, DataMsvc.size());
438   }
439 }
440 
441 // Compare logical elements.
442 void compareElements(SmallString<128> &InputsDir) {
443   // Reader options.
444   LVOptions ReaderOptions;
445   ReaderOptions.setAttributeOffset();
446   ReaderOptions.setPrintLines();
447   ReaderOptions.setPrintSymbols();
448   ReaderOptions.setPrintTypes();
449   ReaderOptions.setCompareLines();
450   ReaderOptions.setCompareSymbols();
451   ReaderOptions.setCompareTypes();
452 
453   ReaderOptions.resolveDependencies();
454 
455   std::vector<std::string> Objects;
456   ScopedPrinter W(outs());
457   LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
458 
459   // Check logical comparison.
460   std::unique_ptr<LVReader> Reference =
461       createReader(ReaderHandler, InputsDir, CodeViewClang);
462   std::unique_ptr<LVReader> Target =
463       createReader(ReaderHandler, InputsDir, CodeViewMsvc);
464   checkElementComparison(Reference.get(), Target.get());
465 }
466 
467 TEST(LogicalViewTest, CodeViewReader) {
468   // Initialize targets and assembly printers/parsers.
469   llvm::InitializeAllTargetInfos();
470   llvm::InitializeAllTargetMCs();
471   InitializeAllDisassemblers();
472 
473   llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
474 
475   // This test requires a x86-registered-target.
476   Triple TT;
477   TT.setArch(Triple::x86_64);
478   TT.setVendor(Triple::UnknownVendor);
479   TT.setOS(Triple::UnknownOS);
480 
481   std::string TargetLookupError;
482   if (!TargetRegistry::lookupTarget(std::string(TT.str()), TargetLookupError))
483     return;
484 
485   SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
486 
487   // Logical elements general properties and selection.
488   elementProperties(InputsDir);
489   elementSelection(InputsDir);
490 
491   // Compare logical elements.
492   compareElements(InputsDir);
493 }
494 
495 } // namespace
496