1 //===- llvm/unittest/DebugInfo/LogicalView/DWARFReaderTest.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 *DwarfClang
= "test-dwarf-clang.o";
33 const char *DwarfGcc
= "test-dwarf-gcc.o";
35 // Helper function to get the first compile unit.
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);
42 LVScopes::const_iterator Iter
= CompileUnits
->begin();
43 EXPECT_NE(Iter
, nullptr);
44 LVScopeCompileUnit
*CompileUnit
= static_cast<LVScopeCompileUnit
*>(*Iter
);
45 EXPECT_NE(CompileUnit
, 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.
65 void checkElementProperties(LVReader
*Reader
) {
66 LVScopeRoot
*Root
= Reader
->getScopesRoot();
67 LVScopeCompileUnit
*CompileUnit
= getFirstCompileUnit(Root
);
69 EXPECT_EQ(Root
->getFileFormatName(), "elf64-x86-64");
70 EXPECT_EQ(Root
->getName(), DwarfClang
);
72 EXPECT_EQ(CompileUnit
->getBaseAddress(), 0u);
73 EXPECT_TRUE(CompileUnit
->getProducer().starts_with("clang"));
74 EXPECT_EQ(CompileUnit
->getName(), "test.cpp");
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);
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]");
91 CompileUnit
->getRanges(RangeList
);
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
);
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
);
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
);
121 // Lines (debug and assembler) for 'foo'.
122 const LVLines
*Lines
= Function
->getLines();
123 ASSERT_NE(Lines
, nullptr);
124 ASSERT_EQ(Lines
->size(), 0x12u
);
127 // Check the logical elements selection.
128 void checkElementSelection(LVReader
*Reader
) {
129 LVScopeRoot
*Root
= Reader
->getScopesRoot();
130 LVScopeCompileUnit
*CompileUnit
= getFirstCompileUnit(Root
);
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
);
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);
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);
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);
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);
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);
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);
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());
180 // Check the logical elements comparison.
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());
186 // Get comparison table.
187 LVPassTable PassTable
= Compare
.getPassTable();
188 ASSERT_EQ(PassTable
.size(), 5u);
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
);
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
);
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
);
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
);
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
);
245 // Logical elements properties.
246 void elementProperties(SmallString
<128> &InputsDir
) {
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();
259 std::vector
<std::string
> Objects
;
260 ScopedPrinter
W(outs());
261 LVReaderHandler
ReaderHandler(Objects
, W
, ReaderOptions
);
263 // Check logical elements properties.
264 std::unique_ptr
<LVReader
> Reader
=
265 createReader(ReaderHandler
, InputsDir
, DwarfClang
);
266 checkElementProperties(Reader
.get());
269 // Logical elements selection.
270 void elementSelection(SmallString
<128> &InputsDir
) {
272 LVOptions ReaderOptions
;
273 ReaderOptions
.setAttributeOffset();
274 ReaderOptions
.setPrintAll();
276 ReaderOptions
.setSelectIgnoreCase();
277 ReaderOptions
.setSelectUseRegex();
279 ReaderOptions
.setReportList(); // Matched elements.
280 ReaderOptions
.setReportView(); // Parents for matched elements.
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");
288 ReaderOptions
.resolveDependencies();
290 std::vector
<std::string
> Objects
;
291 ScopedPrinter
W(outs());
292 LVReaderHandler
ReaderHandler(Objects
, W
, ReaderOptions
);
294 // Check logical elements selection.
295 std::unique_ptr
<LVReader
> Reader
=
296 createReader(ReaderHandler
, InputsDir
, DwarfGcc
);
297 checkElementSelection(Reader
.get());
300 // Compare logical elements.
301 void compareElements(SmallString
<128> &InputsDir
) {
303 LVOptions ReaderOptions
;
304 ReaderOptions
.setAttributeOffset();
305 ReaderOptions
.setPrintLines();
306 ReaderOptions
.setPrintSymbols();
307 ReaderOptions
.setPrintTypes();
308 ReaderOptions
.setCompareLines();
309 ReaderOptions
.setCompareSymbols();
310 ReaderOptions
.setCompareTypes();
312 ReaderOptions
.resolveDependencies();
314 std::vector
<std::string
> Objects
;
315 ScopedPrinter
W(outs());
316 LVReaderHandler
ReaderHandler(Objects
, W
, ReaderOptions
);
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());
326 TEST(LogicalViewTest
, DWARFReader
) {
327 // Initialize targets and assembly printers/parsers.
328 llvm::InitializeAllTargetInfos();
329 llvm::InitializeAllTargetMCs();
330 InitializeAllDisassemblers();
332 llvm::sys::InitializeCOMRAII
COM(llvm::sys::COMThreadingMode::MultiThreaded
);
334 // This test requires a x86-registered-target.
336 TT
.setArch(Triple::x86_64
);
337 TT
.setVendor(Triple::UnknownVendor
);
338 TT
.setOS(Triple::UnknownOS
);
340 std::string TargetLookupError
;
341 if (!TargetRegistry::lookupTarget(std::string(TT
.str()), TargetLookupError
))
344 SmallString
<128> InputsDir
= unittest::getInputFileDirectory(TestMainArgv0
);
346 // Logical elements general properties and selection.
347 elementProperties(InputsDir
);
348 elementSelection(InputsDir
);
350 // Compare logical elements.
351 compareElements(InputsDir
);