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().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(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().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(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().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(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