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(path&: ObjectName, a: Filename); |
55 | |
56 | Expected<std::unique_ptr<LVReader>> ReaderOrErr = |
57 | ReaderHandler.createReader(Pathname: 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(Parent: Root)); |
69 | LVScopeFunction *Function = |
70 | static_cast<LVScopeFunction *>(getFirstScopeChild(Parent: 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().starts_with("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(Parent: Root)); |
135 | LVScopeFunction *Function = |
136 | static_cast<LVScopeFunction *>(getFirstScopeChild(Parent: 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().starts_with("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(Parent: Root)); |
201 | LVScopeFunction *Function = |
202 | static_cast<LVScopeFunction *>(getFirstScopeChild(Parent: 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().starts_with("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(Parent: 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(x: Scope->getName()); |
297 | ASSERT_EQ(SetScopes.size(), 3u); |
298 | |
299 | // Parents of selected elements. |
300 | std::set<StringRef>::iterator IterScope; |
301 | IterScope = SetScopes.find(x: "foo" ); |
302 | EXPECT_NE(IterScope, SetScopes.end()); |
303 | IterScope = SetScopes.find(x: "foo::?" ); |
304 | EXPECT_NE(IterScope, SetScopes.end()); |
305 | IterScope = SetScopes.find(x: "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(ReferenceReader: Reference, TargetReader: 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(args&: Reader, args&: Element, args&: 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(args&: Reader, args&: Element, args&: 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, Filename: CodeViewClang); |
366 | checkElementPropertiesClangCodeview(Reader: Reader.get()); |
367 | } |
368 | { |
369 | std::unique_ptr<LVReader> Reader = |
370 | createReader(ReaderHandler, InputsDir, Filename: CodeViewMsvc); |
371 | checkElementPropertiesMsvcCodeview(Reader: Reader.get()); |
372 | } |
373 | { |
374 | std::unique_ptr<LVReader> Reader = |
375 | createReader(ReaderHandler, InputsDir, Filename: CodeViewPdbMsvc); |
376 | checkElementPropertiesMsvcCodeviewPdb(Reader: 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(key: "foo" ); |
395 | ReaderOptions.Select.Generic.insert(key: "movl[ \t]?%" ); |
396 | ReaderOptions.Select.Generic.insert(key: "INT[a-z]*" ); |
397 | ReaderOptions.Select.Generic.insert(key: "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 | {.Name: "* const int" , .Function: &LVElement::getIsType}, |
409 | {.Name: "CONSTANT" , .Function: &LVElement::getIsSymbol}, |
410 | {.Name: "INTEGER" , .Function: &LVElement::getIsType}, |
411 | {.Name: "INTPTR" , .Function: &LVElement::getIsType}, |
412 | {.Name: "ParamPtr" , .Function: &LVElement::getIsSymbol}, |
413 | {.Name: "const int" , .Function: &LVElement::getIsType}, |
414 | {.Name: "foo" , .Function: &LVElement::getIsScope}, |
415 | {.Name: "foo::?" , .Function: &LVElement::getIsScope}, |
416 | {.Name: "int" , .Function: &LVElement::getIsType}, |
417 | {.Name: "movl" , .Function: &LVElement::getIsLine}, |
418 | {.Name: "movl" , .Function: &LVElement::getIsLine}}; |
419 | std::unique_ptr<LVReader> Reader = |
420 | createReader(ReaderHandler, InputsDir, Filename: CodeViewClang); |
421 | checkElementSelection(Reader: Reader.get(), Data&: DataClang, Size: DataClang.size()); |
422 | } |
423 | { |
424 | std::vector<SelectionInfo> DataMsvc = { |
425 | {.Name: "* const int" , .Function: &LVElement::getIsType}, |
426 | {.Name: "CONSTANT" , .Function: &LVElement::getIsSymbol}, |
427 | {.Name: "INTEGER" , .Function: &LVElement::getIsType}, |
428 | {.Name: "INTPTR" , .Function: &LVElement::getIsType}, |
429 | {.Name: "ParamPtr" , .Function: &LVElement::getIsSymbol}, |
430 | {.Name: "const int" , .Function: &LVElement::getIsType}, |
431 | {.Name: "foo" , .Function: &LVElement::getIsScope}, |
432 | {.Name: "foo::?" , .Function: &LVElement::getIsScope}, |
433 | {.Name: "int" , .Function: &LVElement::getIsType}, |
434 | {.Name: "movl" , .Function: &LVElement::getIsLine}}; |
435 | std::unique_ptr<LVReader> Reader = |
436 | createReader(ReaderHandler, InputsDir, Filename: CodeViewMsvc); |
437 | checkElementSelection(Reader: Reader.get(), Data&: DataMsvc, Size: 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, Filename: CodeViewClang); |
462 | std::unique_ptr<LVReader> Target = |
463 | createReader(ReaderHandler, InputsDir, Filename: CodeViewMsvc); |
464 | checkElementComparison(Reference: Reference.get(), Target: 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(Kind: Triple::x86_64); |
478 | TT.setVendor(Triple::UnknownVendor); |
479 | TT.setOS(Triple::UnknownOS); |
480 | |
481 | std::string TargetLookupError; |
482 | if (!TargetRegistry::lookupTarget(Triple: std::string(TT.str()), Error&: TargetLookupError)) |
483 | return; |
484 | |
485 | SmallString<128> InputsDir = unittest::getInputFileDirectory(Argv0: 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 | |