xref: /llvm-project/llvm/unittests/DebugInfo/LogicalView/DWARFReaderTest.cpp (revision c1ccf0781bf96f8609066bbed1389751926818c1)
1 //===- llvm/unittest/DebugInfo/LogicalView/DWARFReaderTest.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 *DwarfClang = "test-dwarf-clang.o";
33 const char *DwarfGcc = "test-dwarf-gcc.o";
34 
35 // Helper function to get the first compile unit.
getFirstCompileUnit(LVScopeRoot * Root)36 LVScopeCompileUnit *getFirstCompileUnit(LVScopeRoot *Root) {
37   EXPECT_NE(Root, nullptr);
38   const LVScopes *CompileUnits = Root->getScopes();
39   EXPECT_NE(CompileUnits, nullptr);
40   EXPECT_EQ(CompileUnits->size(), 1u);
41 
42   LVScopes::const_iterator Iter = CompileUnits->begin();
43   EXPECT_NE(Iter, nullptr);
44   LVScopeCompileUnit *CompileUnit = static_cast<LVScopeCompileUnit *>(*Iter);
45   EXPECT_NE(CompileUnit, nullptr);
46   return CompileUnit;
47 }
48 
49 // Helper function to create a reader.
createReader(LVReaderHandler & ReaderHandler,SmallString<128> & InputsDir,StringRef Filename)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.
checkElementProperties(LVReader * Reader)65 void checkElementProperties(LVReader *Reader) {
66   LVScopeRoot *Root = Reader->getScopesRoot();
67   LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
68 
69   EXPECT_EQ(Root->getFileFormatName(), "elf64-x86-64");
70   EXPECT_EQ(Root->getName(), DwarfClang);
71 
72   EXPECT_EQ(CompileUnit->getBaseAddress(), 0u);
73   EXPECT_TRUE(CompileUnit->getProducer().starts_with("clang"));
74   EXPECT_EQ(CompileUnit->getName(), "test.cpp");
75 
76   EXPECT_EQ(CompileUnit->lineCount(), 0u);
77   EXPECT_EQ(CompileUnit->scopeCount(), 1u);
78   EXPECT_EQ(CompileUnit->symbolCount(), 0u);
79   EXPECT_EQ(CompileUnit->typeCount(), 7u);
80   EXPECT_EQ(CompileUnit->rangeCount(), 1u);
81 
82   const LVLocations *Ranges = CompileUnit->getRanges();
83   ASSERT_NE(Ranges, nullptr);
84   ASSERT_EQ(Ranges->size(), 1u);
85   LVLocations::const_iterator IterLocation = Ranges->begin();
86   LVLocation *Location = (*IterLocation);
87   EXPECT_STREQ(Location->getIntervalInfo().c_str(),
88                "{Range} Lines 2:9 [0x0000000000:0x000000003a]");
89 
90   LVRange RangeList;
91   CompileUnit->getRanges(RangeList);
92 
93   const LVRangeEntries &RangeEntries = RangeList.getEntries();
94   ASSERT_EQ(RangeEntries.size(), 2u);
95   LVRangeEntries::const_iterator IterRanges = RangeEntries.cbegin();
96   LVRangeEntry RangeEntry = *IterRanges;
97   EXPECT_EQ(RangeEntry.lower(), 0u);
98   EXPECT_EQ(RangeEntry.upper(), 0x3au);
99   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
100   EXPECT_EQ(RangeEntry.scope()->getName(), "test.cpp");
101   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x0bu);
102 
103   ++IterRanges;
104   RangeEntry = *IterRanges;
105   EXPECT_EQ(RangeEntry.lower(), 0x1cu);
106   EXPECT_EQ(RangeEntry.upper(), 0x2fu);
107   EXPECT_EQ(RangeEntry.scope()->getLineNumber(), 0u);
108   EXPECT_EQ(RangeEntry.scope()->getName(), "foo::?");
109   EXPECT_EQ(RangeEntry.scope()->getOffset(), 0x71u);
110 
111   const LVPublicNames &PublicNames = CompileUnit->getPublicNames();
112   ASSERT_EQ(PublicNames.size(), 1u);
113   LVPublicNames::const_iterator IterNames = PublicNames.cbegin();
114   LVScope *Function = (*IterNames).first;
115   EXPECT_EQ(Function->getName(), "foo");
116   EXPECT_EQ(Function->getLineNumber(), 2u);
117   LVNameInfo NameInfo = (*IterNames).second;
118   EXPECT_EQ(NameInfo.first, 0u);
119   EXPECT_EQ(NameInfo.second, 0x3au);
120 
121   // Lines (debug and assembler) for 'foo'.
122   const LVLines *Lines = Function->getLines();
123   ASSERT_NE(Lines, nullptr);
124   ASSERT_EQ(Lines->size(), 0x12u);
125 }
126 
127 // Check the logical elements selection.
checkElementSelection(LVReader * Reader)128 void checkElementSelection(LVReader *Reader) {
129   LVScopeRoot *Root = Reader->getScopesRoot();
130   LVScopeCompileUnit *CompileUnit = getFirstCompileUnit(Root);
131 
132   // Get the matched elements.
133   LVElements MatchedElements = CompileUnit->getMatchedElements();
134   std::map<LVOffset, LVElement *> MapElements;
135   for (LVElement *Element : MatchedElements)
136     MapElements[Element->getOffset()] = Element;
137   ASSERT_EQ(MapElements.size(), 0xeu);
138 
139   LVElement *Element = MapElements[0x000000004b]; // 'foo'
140   ASSERT_NE(Element, nullptr);
141   EXPECT_NE(Element->getName().find("foo"), StringRef::npos);
142   EXPECT_EQ(Element->getIsScope(), 1);
143 
144   Element = MapElements[0x00000000c0]; // 'CONSTANT'
145   ASSERT_NE(Element, nullptr);
146   EXPECT_NE(Element->getName().find("CONSTANT"), StringRef::npos);
147   EXPECT_EQ(Element->getIsSymbol(), 1);
148 
149   Element = MapElements[0x000000002d]; // 'INTPTR'
150   ASSERT_NE(Element, nullptr);
151   EXPECT_NE(Element->getName().find("INTPTR"), StringRef::npos);
152   EXPECT_EQ(Element->getIsType(), 1);
153 
154   Element = MapElements[0x00000000af]; // 'INTEGER'
155   ASSERT_NE(Element, nullptr);
156   EXPECT_NE(Element->getName().find("INTEGER"), StringRef::npos);
157   EXPECT_EQ(Element->getIsType(), 1);
158 
159   Element = MapElements[0x000000000f]; // 'movl	%edx, %eax'
160   ASSERT_NE(Element, nullptr);
161   EXPECT_NE(Element->getName().find("movl"), StringRef::npos);
162   EXPECT_EQ(Element->getIsLine(), 1);
163 
164   // Get the parents for the matched elements.
165   LVScopes MatchedScopes = CompileUnit->getMatchedScopes();
166   std::set<LVOffset> SetScopes;
167   for (LVScope *Scope : MatchedScopes)
168     SetScopes.insert(Scope->getOffset());
169   std::set<LVOffset>::iterator Iter;
170   ASSERT_EQ(SetScopes.size(), 3u);
171 
172   Iter = SetScopes.find(0x000000000b); // CompileUnit <- 'foo'
173   EXPECT_NE(Iter, SetScopes.end());
174   Iter = SetScopes.find(0x000000009e); // Function <- 'movl	%edx, %eax'
175   EXPECT_NE(Iter, SetScopes.end());
176   Iter = SetScopes.find(0x000000009e); // LexicalScope <- 'INTEGER'
177   EXPECT_NE(Iter, SetScopes.end());
178 }
179 
180 // Check the logical elements comparison.
checkElementComparison(LVReader * Reference,LVReader * Target)181 void checkElementComparison(LVReader *Reference, LVReader *Target) {
182   LVCompare Compare(nulls());
183   Error Err = Compare.execute(Reference, Target);
184   ASSERT_THAT_ERROR(std::move(Err), Succeeded());
185 
186   // Get comparison table.
187   LVPassTable PassTable = Compare.getPassTable();
188   ASSERT_EQ(PassTable.size(), 5u);
189 
190   LVReader *Reader;
191   LVElement *Element;
192   LVComparePass Pass;
193 
194   // Reference: Missing Variable 'CONSTANT'
195   std::tie(Reader, Element, Pass) = PassTable[0];
196   ASSERT_NE(Reader, nullptr);
197   ASSERT_NE(Element, nullptr);
198   EXPECT_EQ(Reader, Reference);
199   EXPECT_EQ(Element->getLevel(), 4u);
200   EXPECT_EQ(Element->getLineNumber(), 5u);
201   EXPECT_EQ(Element->getName(), "CONSTANT");
202   EXPECT_EQ(Pass, LVComparePass::Missing);
203 
204   // Reference: Missing TypeDefinition 'INTEGER'
205   std::tie(Reader, Element, Pass) = PassTable[1];
206   ASSERT_NE(Reader, nullptr);
207   ASSERT_NE(Element, nullptr);
208   EXPECT_EQ(Reader, Reference);
209   EXPECT_EQ(Element->getLevel(), 3u);
210   EXPECT_EQ(Element->getLineNumber(), 4u);
211   EXPECT_EQ(Element->getName(), "INTEGER");
212   EXPECT_EQ(Pass, LVComparePass::Missing);
213 
214   // Reference: Missing DebugLine
215   std::tie(Reader, Element, Pass) = PassTable[2];
216   ASSERT_NE(Reader, nullptr);
217   ASSERT_NE(Element, nullptr);
218   EXPECT_EQ(Reader, Reference);
219   EXPECT_EQ(Element->getLevel(), 3u);
220   EXPECT_EQ(Element->getLineNumber(), 8u);
221   EXPECT_EQ(Element->getName(), "");
222   EXPECT_EQ(Pass, LVComparePass::Missing);
223 
224   // Target: Added Variable 'CONSTANT'
225   std::tie(Reader, Element, Pass) = PassTable[3];
226   ASSERT_NE(Reader, nullptr);
227   ASSERT_NE(Element, nullptr);
228   EXPECT_EQ(Reader, Target);
229   EXPECT_EQ(Element->getLevel(), 4u);
230   EXPECT_EQ(Element->getLineNumber(), 5u);
231   EXPECT_EQ(Element->getName(), "CONSTANT");
232   EXPECT_EQ(Pass, LVComparePass::Added);
233 
234   // Target: Added TypeDefinition 'INTEGER'
235   std::tie(Reader, Element, Pass) = PassTable[4];
236   ASSERT_NE(Reader, nullptr);
237   ASSERT_NE(Element, nullptr);
238   EXPECT_EQ(Reader, Target);
239   EXPECT_EQ(Element->getLevel(), 4u);
240   EXPECT_EQ(Element->getLineNumber(), 4u);
241   EXPECT_EQ(Element->getName(), "INTEGER");
242   EXPECT_EQ(Pass, LVComparePass::Added);
243 }
244 
245 // Logical elements properties.
elementProperties(SmallString<128> & InputsDir)246 void elementProperties(SmallString<128> &InputsDir) {
247   // Reader options.
248   LVOptions ReaderOptions;
249   ReaderOptions.setAttributeOffset();
250   ReaderOptions.setAttributeFormat();
251   ReaderOptions.setAttributeFilename();
252   ReaderOptions.setAttributeProducer();
253   ReaderOptions.setAttributePublics();
254   ReaderOptions.setAttributeRange();
255   ReaderOptions.setAttributeLocation();
256   ReaderOptions.setPrintAll();
257   ReaderOptions.resolveDependencies();
258 
259   std::vector<std::string> Objects;
260   ScopedPrinter W(outs());
261   LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
262 
263   // Check logical elements properties.
264   std::unique_ptr<LVReader> Reader =
265       createReader(ReaderHandler, InputsDir, DwarfClang);
266   checkElementProperties(Reader.get());
267 }
268 
269 // Logical elements selection.
elementSelection(SmallString<128> & InputsDir)270 void elementSelection(SmallString<128> &InputsDir) {
271   // Reader options.
272   LVOptions ReaderOptions;
273   ReaderOptions.setAttributeOffset();
274   ReaderOptions.setPrintAll();
275 
276   ReaderOptions.setSelectIgnoreCase();
277   ReaderOptions.setSelectUseRegex();
278 
279   ReaderOptions.setReportList(); // Matched elements.
280   ReaderOptions.setReportView(); // Parents for matched elements.
281 
282   // Add patterns.
283   ReaderOptions.Select.Generic.insert("foo");
284   ReaderOptions.Select.Generic.insert("movl[ \t]?%");
285   ReaderOptions.Select.Generic.insert("INT[a-z]*");
286   ReaderOptions.Select.Generic.insert("CONSTANT");
287 
288   ReaderOptions.resolveDependencies();
289 
290   std::vector<std::string> Objects;
291   ScopedPrinter W(outs());
292   LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
293 
294   // Check logical elements selection.
295   std::unique_ptr<LVReader> Reader =
296       createReader(ReaderHandler, InputsDir, DwarfGcc);
297   checkElementSelection(Reader.get());
298 }
299 
300 // Compare logical elements.
compareElements(SmallString<128> & InputsDir)301 void compareElements(SmallString<128> &InputsDir) {
302   // Reader options.
303   LVOptions ReaderOptions;
304   ReaderOptions.setAttributeOffset();
305   ReaderOptions.setPrintLines();
306   ReaderOptions.setPrintSymbols();
307   ReaderOptions.setPrintTypes();
308   ReaderOptions.setCompareLines();
309   ReaderOptions.setCompareSymbols();
310   ReaderOptions.setCompareTypes();
311 
312   ReaderOptions.resolveDependencies();
313 
314   std::vector<std::string> Objects;
315   ScopedPrinter W(outs());
316   LVReaderHandler ReaderHandler(Objects, W, ReaderOptions);
317 
318   // Check logical comparison.
319   std::unique_ptr<LVReader> Reference =
320       createReader(ReaderHandler, InputsDir, DwarfClang);
321   std::unique_ptr<LVReader> Target =
322       createReader(ReaderHandler, InputsDir, DwarfGcc);
323   checkElementComparison(Reference.get(), Target.get());
324 }
325 
TEST(LogicalViewTest,DWARFReader)326 TEST(LogicalViewTest, DWARFReader) {
327   // Initialize targets and assembly printers/parsers.
328   llvm::InitializeAllTargetInfos();
329   llvm::InitializeAllTargetMCs();
330   InitializeAllDisassemblers();
331 
332   llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
333 
334   // This test requires a x86-registered-target.
335   Triple TT;
336   TT.setArch(Triple::x86_64);
337   TT.setVendor(Triple::UnknownVendor);
338   TT.setOS(Triple::UnknownOS);
339 
340   std::string TargetLookupError;
341   if (!TargetRegistry::lookupTarget(std::string(TT.str()), TargetLookupError))
342     GTEST_SKIP();
343 
344   SmallString<128> InputsDir = unittest::getInputFileDirectory(TestMainArgv0);
345 
346   // Logical elements general properties and selection.
347   elementProperties(InputsDir);
348   elementSelection(InputsDir);
349 
350   // Compare logical elements.
351   compareElements(InputsDir);
352 }
353 
354 } // namespace
355