1 //===- llvm/unittest/DebugInfo/LogicalView/CodeViewReaderTest.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/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"
23 #include "gtest/gtest.h"
26 using namespace llvm::logicalview
;
28 extern const char *TestMainArgv0
;
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";
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);
43 LVScopes::const_iterator Iter
= Scopes
->begin();
44 LVScope
*Child
= *Iter
;
45 EXPECT_NE(Child
, nullptr);
49 // Helper function to create a reader.
50 std::unique_ptr
<LVReader
> createReader(LVReaderHandler
&ReaderHandler
,
51 SmallString
<128> &InputsDir
,
53 SmallString
<128> ObjectName(InputsDir
);
54 llvm::sys::path::append(ObjectName
, Filename
);
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);
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
));
72 EXPECT_EQ(Root
->getFileFormatName(), "COFF-x86-64");
73 EXPECT_EQ(Root
->getName(), CodeViewClang
);
75 EXPECT_EQ(CompileUnit
->getBaseAddress(), 0u);
76 EXPECT_TRUE(CompileUnit
->getProducer().startswith("clang"));
77 EXPECT_EQ(CompileUnit
->getName(), "test.cpp");
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);
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]");
94 Function
->getRanges(RangeList
);
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);
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);
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
);
124 // Lines (debug and assembler) for 'foo'.
125 const LVLines
*Lines
= Foo
->getLines();
126 ASSERT_NE(Lines
, nullptr);
127 EXPECT_EQ(Lines
->size(), 0x10u
);
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
));
138 EXPECT_EQ(Root
->getFileFormatName(), "COFF-x86-64");
139 EXPECT_EQ(Root
->getName(), CodeViewMsvc
);
141 EXPECT_EQ(CompileUnit
->getBaseAddress(), 0u);
142 EXPECT_TRUE(CompileUnit
->getProducer().startswith("Microsoft"));
143 EXPECT_EQ(CompileUnit
->getName(), "test.cpp");
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);
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]");
160 Function
->getRanges(RangeList
);
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);
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);
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
);
190 // Lines (debug and assembler) for 'foo'.
191 const LVLines
*Lines
= Foo
->getLines();
192 ASSERT_NE(Lines
, nullptr);
193 EXPECT_EQ(Lines
->size(), 0x0eu
);
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
));
204 EXPECT_EQ(Root
->getFileFormatName(), "COFF-x86-64");
205 EXPECT_EQ(Root
->getName(), CodeViewPdbMsvc
);
207 EXPECT_EQ(CompileUnit
->getBaseAddress(), 0u);
208 EXPECT_TRUE(CompileUnit
->getProducer().startswith("Microsoft"));
209 EXPECT_EQ(CompileUnit
->getName(), "test.cpp");
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);
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]");
226 Function
->getRanges(RangeList
);
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);
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);
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
);
256 // Lines (debug and assembler) for 'foo'.
257 const LVLines
*Lines
= Foo
->getLines();
258 ASSERT_NE(Lines
, nullptr);
259 EXPECT_EQ(Lines
->size(), 0x0eu
);
262 struct SelectionInfo
{
264 LVElementGetFunction Function
;
267 // Check the logical elements selection.
268 void checkElementSelection(LVReader
*Reader
, std::vector
<SelectionInfo
> &Data
,
270 LVScopeRoot
*Root
= Reader
->getScopesRoot();
271 LVScopeCompileUnit
*CompileUnit
=
272 static_cast<LVScopeCompileUnit
*>(getFirstScopeChild(Root
));
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
);
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);
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);
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());
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());
315 // Get comparison table.
316 LVPassTable PassTable
= Compare
.getPassTable();
317 ASSERT_EQ(PassTable
.size(), 2u);
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
);
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
);
344 // Logical elements properties.
345 void elementProperties(SmallString
<128> &InputsDir
) {
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();
358 std::vector
<std::string
> Objects
;
359 ScopedPrinter
W(outs());
360 LVReaderHandler
ReaderHandler(Objects
, W
, ReaderOptions
);
362 // Check logical elements properties.
364 std::unique_ptr
<LVReader
> Reader
=
365 createReader(ReaderHandler
, InputsDir
, CodeViewClang
);
366 checkElementPropertiesClangCodeview(Reader
.get());
369 std::unique_ptr
<LVReader
> Reader
=
370 createReader(ReaderHandler
, InputsDir
, CodeViewMsvc
);
371 checkElementPropertiesMsvcCodeview(Reader
.get());
374 std::unique_ptr
<LVReader
> Reader
=
375 createReader(ReaderHandler
, InputsDir
, CodeViewPdbMsvc
);
376 checkElementPropertiesMsvcCodeviewPdb(Reader
.get());
380 // Logical elements selection.
381 void elementSelection(SmallString
<128> &InputsDir
) {
383 LVOptions ReaderOptions
;
384 ReaderOptions
.setAttributeOffset();
385 ReaderOptions
.setPrintAll();
387 ReaderOptions
.setSelectIgnoreCase();
388 ReaderOptions
.setSelectUseRegex();
390 ReaderOptions
.setReportList(); // Matched elements.
391 ReaderOptions
.setReportView(); // Parents for matched elements.
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");
399 ReaderOptions
.resolveDependencies();
401 std::vector
<std::string
> Objects
;
402 ScopedPrinter
W(outs());
403 LVReaderHandler
ReaderHandler(Objects
, W
, ReaderOptions
);
405 // Check logical elements selection.
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());
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());
441 // Compare logical elements.
442 void compareElements(SmallString
<128> &InputsDir
) {
444 LVOptions ReaderOptions
;
445 ReaderOptions
.setAttributeOffset();
446 ReaderOptions
.setPrintLines();
447 ReaderOptions
.setPrintSymbols();
448 ReaderOptions
.setPrintTypes();
449 ReaderOptions
.setCompareLines();
450 ReaderOptions
.setCompareSymbols();
451 ReaderOptions
.setCompareTypes();
453 ReaderOptions
.resolveDependencies();
455 std::vector
<std::string
> Objects
;
456 ScopedPrinter
W(outs());
457 LVReaderHandler
ReaderHandler(Objects
, W
, ReaderOptions
);
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());
467 TEST(LogicalViewTest
, CodeViewReader
) {
468 // Initialize targets and assembly printers/parsers.
469 llvm::InitializeAllTargetInfos();
470 llvm::InitializeAllTargetMCs();
471 InitializeAllDisassemblers();
473 llvm::sys::InitializeCOMRAII
COM(llvm::sys::COMThreadingMode::MultiThreaded
);
475 // This test requires a x86-registered-target.
477 TT
.setArch(Triple::x86_64
);
478 TT
.setVendor(Triple::UnknownVendor
);
479 TT
.setOS(Triple::UnknownOS
);
481 std::string TargetLookupError
;
482 if (!TargetRegistry::lookupTarget(std::string(TT
.str()), TargetLookupError
))
485 SmallString
<128> InputsDir
= unittest::getInputFileDirectory(TestMainArgv0
);
487 // Logical elements general properties and selection.
488 elementProperties(InputsDir
);
489 elementSelection(InputsDir
);
491 // Compare logical elements.
492 compareElements(InputsDir
);