1 //===- DylibVerifier.cpp ----------------------------------------*- C++--*-===// 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 "clang/InstallAPI/DylibVerifier.h" 10 #include "clang/InstallAPI/FrontendRecords.h" 11 #include "clang/InstallAPI/InstallAPIDiagnostic.h" 12 #include "llvm/Demangle/Demangle.h" 13 #include "llvm/TextAPI/DylibReader.h" 14 15 using namespace llvm::MachO; 16 17 namespace clang { 18 namespace installapi { 19 20 /// Metadata stored about a mapping of a declaration to a symbol. 21 struct DylibVerifier::SymbolContext { 22 // Name to use for all querying and verification 23 // purposes. 24 std::string SymbolName{""}; 25 26 // Kind to map symbol type against record. 27 EncodeKind Kind = EncodeKind::GlobalSymbol; 28 29 // Frontend Attributes tied to the AST. 30 const FrontendAttrs *FA = nullptr; 31 32 // The ObjCInterface symbol type, if applicable. 33 ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None; 34 35 // Whether Decl is inlined. 36 bool Inlined = false; 37 }; 38 39 struct DylibVerifier::DWARFContext { 40 // Track whether DSYM parsing has already been attempted to avoid re-parsing. 41 bool ParsedDSYM{false}; 42 43 // Lookup table for source locations by symbol name. 44 DylibReader::SymbolToSourceLocMap SourceLocs{}; 45 }; 46 47 static bool isCppMangled(StringRef Name) { 48 // InstallAPI currently only supports itanium manglings. 49 return (Name.starts_with("_Z") || Name.starts_with("__Z") || 50 Name.starts_with("___Z")); 51 } 52 53 static std::string demangle(StringRef Name) { 54 // InstallAPI currently only supports itanium manglings. 55 if (!isCppMangled(Name)) 56 return Name.str(); 57 char *Result = llvm::itaniumDemangle(Name); 58 if (!Result) 59 return Name.str(); 60 61 std::string Demangled(Result); 62 free(Result); 63 return Demangled; 64 } 65 66 std::string DylibVerifier::getAnnotatedName(const Record *R, 67 SymbolContext &SymCtx, 68 bool ValidSourceLoc) { 69 assert(!SymCtx.SymbolName.empty() && "Expected symbol name"); 70 71 const StringRef SymbolName = SymCtx.SymbolName; 72 std::string PrettyName = 73 (Demangle && (SymCtx.Kind == EncodeKind::GlobalSymbol)) 74 ? demangle(SymbolName) 75 : SymbolName.str(); 76 77 std::string Annotation; 78 if (R->isWeakDefined()) 79 Annotation += "(weak-def) "; 80 if (R->isWeakReferenced()) 81 Annotation += "(weak-ref) "; 82 if (R->isThreadLocalValue()) 83 Annotation += "(tlv) "; 84 85 // Check if symbol represents only part of a @interface declaration. 86 switch (SymCtx.ObjCIFKind) { 87 default: 88 break; 89 case ObjCIFSymbolKind::EHType: 90 return Annotation + "Exception Type of " + PrettyName; 91 case ObjCIFSymbolKind::MetaClass: 92 return Annotation + "Metaclass of " + PrettyName; 93 case ObjCIFSymbolKind::Class: 94 return Annotation + "Class of " + PrettyName; 95 } 96 97 // Only print symbol type prefix or leading "_" if there is no source location 98 // tied to it. This can only ever happen when the location has to come from 99 // debug info. 100 if (ValidSourceLoc) { 101 StringRef PrettyNameRef(PrettyName); 102 if ((SymCtx.Kind == EncodeKind::GlobalSymbol) && 103 !isCppMangled(SymbolName) && PrettyNameRef.starts_with("_")) 104 return Annotation + PrettyNameRef.drop_front(1).str(); 105 return Annotation + PrettyName; 106 } 107 108 switch (SymCtx.Kind) { 109 case EncodeKind::GlobalSymbol: 110 return Annotation + PrettyName; 111 case EncodeKind::ObjectiveCInstanceVariable: 112 return Annotation + "(ObjC IVar) " + PrettyName; 113 case EncodeKind::ObjectiveCClass: 114 return Annotation + "(ObjC Class) " + PrettyName; 115 case EncodeKind::ObjectiveCClassEHType: 116 return Annotation + "(ObjC Class EH) " + PrettyName; 117 } 118 119 llvm_unreachable("unexpected case for EncodeKind"); 120 } 121 122 static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev, 123 const DylibVerifier::Result Curr) { 124 if (Prev == Curr) 125 return Prev; 126 127 // Never update from invalid or noverify state. 128 if ((Prev == DylibVerifier::Result::Invalid) || 129 (Prev == DylibVerifier::Result::NoVerify)) 130 return Prev; 131 132 // Don't let an ignored verification remove a valid one. 133 if (Prev == DylibVerifier::Result::Valid && 134 Curr == DylibVerifier::Result::Ignore) 135 return Prev; 136 137 return Curr; 138 } 139 // __private_extern__ is a deprecated specifier that clang does not 140 // respect in all contexts, it should just be considered hidden for InstallAPI. 141 static bool shouldIgnorePrivateExternAttr(const Decl *D) { 142 if (const FunctionDecl *FD = cast<FunctionDecl>(D)) 143 return FD->getStorageClass() == StorageClass::SC_PrivateExtern; 144 if (const VarDecl *VD = cast<VarDecl>(D)) 145 return VD->getStorageClass() == StorageClass::SC_PrivateExtern; 146 147 return false; 148 } 149 150 Record *findRecordFromSlice(const RecordsSlice *Slice, StringRef Name, 151 EncodeKind Kind) { 152 switch (Kind) { 153 case EncodeKind::GlobalSymbol: 154 return Slice->findGlobal(Name); 155 case EncodeKind::ObjectiveCInstanceVariable: 156 return Slice->findObjCIVar(Name.contains('.'), Name); 157 case EncodeKind::ObjectiveCClass: 158 case EncodeKind::ObjectiveCClassEHType: 159 return Slice->findObjCInterface(Name); 160 } 161 llvm_unreachable("unexpected end when finding record"); 162 } 163 164 void DylibVerifier::updateState(Result State) { 165 Ctx.FrontendState = updateResult(Ctx.FrontendState, State); 166 } 167 168 void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx, 169 TargetList &&Targets) { 170 if (Targets.empty()) 171 Targets = {Ctx.Target}; 172 173 Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets); 174 } 175 176 bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx, 177 const Record *DR) { 178 return SymCtx.FA->Avail.isObsoleted(); 179 } 180 181 bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R, 182 SymbolContext &SymCtx, 183 const ObjCInterfaceRecord *DR) { 184 const bool IsDeclVersionComplete = 185 ((SymCtx.ObjCIFKind & ObjCIFSymbolKind::Class) == 186 ObjCIFSymbolKind::Class) && 187 ((SymCtx.ObjCIFKind & ObjCIFSymbolKind::MetaClass) == 188 ObjCIFSymbolKind::MetaClass); 189 190 const bool IsDylibVersionComplete = DR->isCompleteInterface(); 191 192 // The common case, a complete ObjCInterface. 193 if (IsDeclVersionComplete && IsDylibVersionComplete) 194 return true; 195 196 auto PrintDiagnostic = [&](auto SymLinkage, const Record *Record, 197 StringRef SymName, bool PrintAsWarning = false) { 198 if (SymLinkage == RecordLinkage::Unknown) 199 Ctx.emitDiag([&]() { 200 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 201 PrintAsWarning ? diag::warn_library_missing_symbol 202 : diag::err_library_missing_symbol) 203 << SymName; 204 }); 205 else 206 Ctx.emitDiag([&]() { 207 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 208 PrintAsWarning ? diag::warn_library_hidden_symbol 209 : diag::err_library_hidden_symbol) 210 << SymName; 211 }); 212 }; 213 214 if (IsDeclVersionComplete) { 215 // The decl represents a complete ObjCInterface, but the symbols in the 216 // dylib do not. Determine which symbol is missing. To keep older projects 217 // building, treat this as a warning. 218 if (!DR->isExportedSymbol(ObjCIFSymbolKind::Class)) { 219 SymCtx.ObjCIFKind = ObjCIFSymbolKind::Class; 220 PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::Class), R, 221 getAnnotatedName(R, SymCtx), 222 /*PrintAsWarning=*/true); 223 } 224 if (!DR->isExportedSymbol(ObjCIFSymbolKind::MetaClass)) { 225 SymCtx.ObjCIFKind = ObjCIFSymbolKind::MetaClass; 226 PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass), R, 227 getAnnotatedName(R, SymCtx), 228 /*PrintAsWarning=*/true); 229 } 230 return true; 231 } 232 233 if (DR->isExportedSymbol(SymCtx.ObjCIFKind)) { 234 if (!IsDylibVersionComplete) { 235 // Both the declaration and dylib have a non-complete interface. 236 SymCtx.Kind = EncodeKind::GlobalSymbol; 237 SymCtx.SymbolName = R->getName(); 238 } 239 return true; 240 } 241 242 // At this point that means there was not a matching class symbol 243 // to represent the one discovered as a declaration. 244 PrintDiagnostic(DR->getLinkageForSymbol(SymCtx.ObjCIFKind), R, 245 SymCtx.SymbolName); 246 return false; 247 } 248 249 DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, 250 SymbolContext &SymCtx, 251 const Record *DR) { 252 253 if (R->isExported()) { 254 if (!DR) { 255 Ctx.emitDiag([&]() { 256 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 257 diag::err_library_missing_symbol) 258 << getAnnotatedName(R, SymCtx); 259 }); 260 return Result::Invalid; 261 } 262 if (DR->isInternal()) { 263 Ctx.emitDiag([&]() { 264 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 265 diag::err_library_hidden_symbol) 266 << getAnnotatedName(R, SymCtx); 267 }); 268 return Result::Invalid; 269 } 270 } 271 272 // Emit a diagnostic for hidden declarations with external symbols, except 273 // when theres an inlined attribute. 274 if ((R->isInternal() && !SymCtx.Inlined) && DR && DR->isExported()) { 275 276 if (Mode == VerificationMode::ErrorsOnly) 277 return Result::Ignore; 278 279 if (shouldIgnorePrivateExternAttr(SymCtx.FA->D)) 280 return Result::Ignore; 281 282 unsigned ID; 283 Result Outcome; 284 if (Mode == VerificationMode::ErrorsAndWarnings) { 285 ID = diag::warn_header_hidden_symbol; 286 Outcome = Result::Ignore; 287 } else { 288 ID = diag::err_header_hidden_symbol; 289 Outcome = Result::Invalid; 290 } 291 Ctx.emitDiag([&]() { 292 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), ID) 293 << getAnnotatedName(R, SymCtx); 294 }); 295 return Outcome; 296 } 297 298 if (R->isInternal()) 299 return Result::Ignore; 300 301 return Result::Valid; 302 } 303 304 DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R, 305 SymbolContext &SymCtx, 306 const Record *DR) { 307 if (!SymCtx.FA->Avail.isUnavailable()) 308 return Result::Valid; 309 310 const bool IsDeclAvailable = SymCtx.FA->Avail.isUnavailable(); 311 312 switch (Mode) { 313 case VerificationMode::ErrorsAndWarnings: 314 Ctx.emitDiag([&]() { 315 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 316 diag::warn_header_availability_mismatch) 317 << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; 318 }); 319 return Result::Ignore; 320 case VerificationMode::Pedantic: 321 Ctx.emitDiag([&]() { 322 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 323 diag::err_header_availability_mismatch) 324 << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; 325 }); 326 return Result::Invalid; 327 case VerificationMode::ErrorsOnly: 328 return Result::Ignore; 329 case VerificationMode::Invalid: 330 llvm_unreachable("Unexpected verification mode symbol verification"); 331 } 332 llvm_unreachable("Unexpected verification mode symbol verification"); 333 } 334 335 bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx, 336 const Record *DR) { 337 if (DR->isThreadLocalValue() && !R->isThreadLocalValue()) { 338 Ctx.emitDiag([&]() { 339 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 340 diag::err_dylib_symbol_flags_mismatch) 341 << getAnnotatedName(DR, SymCtx) << DR->isThreadLocalValue(); 342 }); 343 return false; 344 } 345 if (!DR->isThreadLocalValue() && R->isThreadLocalValue()) { 346 Ctx.emitDiag([&]() { 347 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 348 diag::err_header_symbol_flags_mismatch) 349 << getAnnotatedName(R, SymCtx) << R->isThreadLocalValue(); 350 }); 351 return false; 352 } 353 354 if (DR->isWeakDefined() && !R->isWeakDefined()) { 355 Ctx.emitDiag([&]() { 356 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 357 diag::err_dylib_symbol_flags_mismatch) 358 << getAnnotatedName(DR, SymCtx) << R->isWeakDefined(); 359 }); 360 return false; 361 } 362 if (!DR->isWeakDefined() && R->isWeakDefined()) { 363 Ctx.emitDiag([&]() { 364 Ctx.Diag->Report(SymCtx.FA->D->getLocation(), 365 diag::err_header_symbol_flags_mismatch) 366 << getAnnotatedName(R, SymCtx) << R->isWeakDefined(); 367 }); 368 return false; 369 } 370 371 return true; 372 } 373 374 DylibVerifier::Result DylibVerifier::verifyImpl(Record *R, 375 SymbolContext &SymCtx) { 376 R->setVerify(); 377 if (!canVerify()) { 378 // Accumulate symbols when not in verifying against dylib. 379 if (R->isExported() && !SymCtx.FA->Avail.isUnavailable() && 380 !SymCtx.FA->Avail.isObsoleted()) { 381 addSymbol(R, SymCtx); 382 } 383 return Ctx.FrontendState; 384 } 385 386 Record *DR = 387 findRecordFromSlice(Ctx.DylibSlice, SymCtx.SymbolName, SymCtx.Kind); 388 if (DR) 389 DR->setVerify(); 390 391 if (shouldIgnoreObsolete(R, SymCtx, DR)) { 392 updateState(Result::Ignore); 393 return Ctx.FrontendState; 394 } 395 396 // Unavailable declarations don't need matching symbols. 397 if (SymCtx.FA->Avail.isUnavailable() && (!DR || DR->isInternal())) { 398 updateState(Result::Valid); 399 return Ctx.FrontendState; 400 } 401 402 Result VisibilityCheck = compareVisibility(R, SymCtx, DR); 403 if (VisibilityCheck != Result::Valid) { 404 updateState(VisibilityCheck); 405 return Ctx.FrontendState; 406 } 407 408 // All missing symbol cases to diagnose have been handled now. 409 if (!DR) { 410 updateState(Result::Ignore); 411 return Ctx.FrontendState; 412 } 413 414 // Check for mismatching ObjC interfaces. 415 if (SymCtx.ObjCIFKind != ObjCIFSymbolKind::None) { 416 if (!compareObjCInterfaceSymbols( 417 R, SymCtx, Ctx.DylibSlice->findObjCInterface(DR->getName()))) { 418 updateState(Result::Invalid); 419 return Ctx.FrontendState; 420 } 421 } 422 423 Result AvailabilityCheck = compareAvailability(R, SymCtx, DR); 424 if (AvailabilityCheck != Result::Valid) { 425 updateState(AvailabilityCheck); 426 return Ctx.FrontendState; 427 } 428 429 if (!compareSymbolFlags(R, SymCtx, DR)) { 430 updateState(Result::Invalid); 431 return Ctx.FrontendState; 432 } 433 434 addSymbol(R, SymCtx); 435 updateState(Result::Valid); 436 return Ctx.FrontendState; 437 } 438 439 bool DylibVerifier::canVerify() { 440 return Ctx.FrontendState != Result::NoVerify; 441 } 442 443 void DylibVerifier::assignSlice(const Target &T) { 444 assert(T == Ctx.Target && "Active targets should match."); 445 if (Dylib.empty()) 446 return; 447 448 // Note: there are no reexport slices with binaries, as opposed to TBD files, 449 // so it can be assumed that the target match is the active top-level library. 450 auto It = find_if( 451 Dylib, [&T](const auto &Slice) { return T == Slice->getTarget(); }); 452 453 assert(It != Dylib.end() && "Target slice should always exist."); 454 Ctx.DylibSlice = It->get(); 455 } 456 457 void DylibVerifier::setTarget(const Target &T) { 458 Ctx.Target = T; 459 Ctx.DiscoveredFirstError = false; 460 if (Dylib.empty()) { 461 updateState(Result::NoVerify); 462 return; 463 } 464 updateState(Result::Ignore); 465 assignSlice(T); 466 } 467 468 DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R, 469 const FrontendAttrs *FA, 470 const StringRef SuperClass) { 471 if (R->isVerified()) 472 return getState(); 473 474 std::string FullName = 475 ObjCIVarRecord::createScopedName(SuperClass, R->getName()); 476 SymbolContext SymCtx{FullName, EncodeKind::ObjectiveCInstanceVariable, FA}; 477 return verifyImpl(R, SymCtx); 478 } 479 480 static ObjCIFSymbolKind assignObjCIFSymbolKind(const ObjCInterfaceRecord *R) { 481 ObjCIFSymbolKind Result = ObjCIFSymbolKind::None; 482 if (R->getLinkageForSymbol(ObjCIFSymbolKind::Class) != RecordLinkage::Unknown) 483 Result |= ObjCIFSymbolKind::Class; 484 if (R->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass) != 485 RecordLinkage::Unknown) 486 Result |= ObjCIFSymbolKind::MetaClass; 487 if (R->getLinkageForSymbol(ObjCIFSymbolKind::EHType) != 488 RecordLinkage::Unknown) 489 Result |= ObjCIFSymbolKind::EHType; 490 return Result; 491 } 492 493 DylibVerifier::Result DylibVerifier::verify(ObjCInterfaceRecord *R, 494 const FrontendAttrs *FA) { 495 if (R->isVerified()) 496 return getState(); 497 SymbolContext SymCtx; 498 SymCtx.SymbolName = R->getName(); 499 SymCtx.ObjCIFKind = assignObjCIFSymbolKind(R); 500 501 SymCtx.Kind = R->hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType 502 : EncodeKind::ObjectiveCClass; 503 SymCtx.FA = FA; 504 505 return verifyImpl(R, SymCtx); 506 } 507 508 DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R, 509 const FrontendAttrs *FA) { 510 if (R->isVerified()) 511 return getState(); 512 513 // Global classifications could be obfusciated with `asm`. 514 SimpleSymbol Sym = parseSymbol(R->getName()); 515 SymbolContext SymCtx; 516 SymCtx.SymbolName = Sym.Name; 517 SymCtx.Kind = Sym.Kind; 518 SymCtx.FA = FA; 519 SymCtx.Inlined = R->isInlined(); 520 return verifyImpl(R, SymCtx); 521 } 522 523 void DylibVerifier::VerifierContext::emitDiag(llvm::function_ref<void()> Report, 524 RecordLoc *Loc) { 525 if (!DiscoveredFirstError) { 526 Diag->Report(diag::warn_target) 527 << (PrintArch ? getArchitectureName(Target.Arch) 528 : getTargetTripleName(Target)); 529 DiscoveredFirstError = true; 530 } 531 if (Loc && Loc->isValid()) 532 llvm::errs() << Loc->File << ":" << Loc->Line << ":" << 0 << ": "; 533 534 Report(); 535 } 536 537 // The existence of weak-defined RTTI can not always be inferred from the 538 // header files because they can be generated as part of an implementation 539 // file. 540 // InstallAPI doesn't warn about weak-defined RTTI, because this doesn't affect 541 // static linking and so can be ignored for text-api files. 542 static bool shouldIgnoreCpp(StringRef Name, bool IsWeakDef) { 543 return (IsWeakDef && 544 (Name.starts_with("__ZTI") || Name.starts_with("__ZTS"))); 545 } 546 void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { 547 // Undefined symbols should not be in InstallAPI generated text-api files. 548 if (R.isUndefined()) { 549 updateState(Result::Valid); 550 return; 551 } 552 553 // Internal symbols should not be in InstallAPI generated text-api files. 554 if (R.isInternal()) { 555 updateState(Result::Valid); 556 return; 557 } 558 559 // Allow zippered symbols with potentially mismatching availability 560 // between macOS and macCatalyst in the final text-api file. 561 const StringRef SymbolName(SymCtx.SymbolName); 562 if (const Symbol *Sym = Exports->findSymbol(SymCtx.Kind, SymCtx.SymbolName, 563 SymCtx.ObjCIFKind)) { 564 if (Sym->hasArchitecture(Ctx.Target.Arch)) { 565 updateState(Result::Ignore); 566 return; 567 } 568 } 569 570 if (shouldIgnoreCpp(SymbolName, R.isWeakDefined())) { 571 updateState(Result::Valid); 572 return; 573 } 574 575 const bool IsLinkerSymbol = SymbolName.starts_with("$ld$"); 576 577 // All checks at this point classify as some kind of violation. 578 // The different verification modes dictate whether they are reported to the 579 // user. 580 if (IsLinkerSymbol || (Mode > VerificationMode::ErrorsOnly)) 581 accumulateSrcLocForDylibSymbols(); 582 RecordLoc Loc = DWARFCtx->SourceLocs.lookup(SymCtx.SymbolName); 583 584 // Regardless of verification mode, error out on mismatched special linker 585 // symbols. 586 if (IsLinkerSymbol) { 587 Ctx.emitDiag( 588 [&]() { 589 Ctx.Diag->Report(diag::err_header_symbol_missing) 590 << getAnnotatedName(&R, SymCtx, Loc.isValid()); 591 }, 592 &Loc); 593 updateState(Result::Invalid); 594 return; 595 } 596 597 // Missing declarations for exported symbols are hard errors on Pedantic mode. 598 if (Mode == VerificationMode::Pedantic) { 599 Ctx.emitDiag( 600 [&]() { 601 Ctx.Diag->Report(diag::err_header_symbol_missing) 602 << getAnnotatedName(&R, SymCtx, Loc.isValid()); 603 }, 604 &Loc); 605 updateState(Result::Invalid); 606 return; 607 } 608 609 // Missing declarations for exported symbols are warnings on ErrorsAndWarnings 610 // mode. 611 if (Mode == VerificationMode::ErrorsAndWarnings) { 612 Ctx.emitDiag( 613 [&]() { 614 Ctx.Diag->Report(diag::warn_header_symbol_missing) 615 << getAnnotatedName(&R, SymCtx, Loc.isValid()); 616 }, 617 &Loc); 618 updateState(Result::Ignore); 619 return; 620 } 621 622 // Missing declarations are dropped for ErrorsOnly mode. It is the last 623 // remaining mode. 624 updateState(Result::Ignore); 625 return; 626 } 627 628 void DylibVerifier::visitGlobal(const GlobalRecord &R) { 629 if (R.isVerified()) 630 return; 631 SymbolContext SymCtx; 632 SimpleSymbol Sym = parseSymbol(R.getName()); 633 SymCtx.SymbolName = Sym.Name; 634 SymCtx.Kind = Sym.Kind; 635 visitSymbolInDylib(R, SymCtx); 636 } 637 638 void DylibVerifier::visitObjCIVar(const ObjCIVarRecord &R, 639 const StringRef Super) { 640 if (R.isVerified()) 641 return; 642 SymbolContext SymCtx; 643 SymCtx.SymbolName = ObjCIVarRecord::createScopedName(Super, R.getName()); 644 SymCtx.Kind = EncodeKind::ObjectiveCInstanceVariable; 645 visitSymbolInDylib(R, SymCtx); 646 } 647 648 void DylibVerifier::accumulateSrcLocForDylibSymbols() { 649 if (DSYMPath.empty()) 650 return; 651 652 assert(DWARFCtx != nullptr && "Expected an initialized DWARFContext"); 653 if (DWARFCtx->ParsedDSYM) 654 return; 655 DWARFCtx->ParsedDSYM = true; 656 DWARFCtx->SourceLocs = 657 DylibReader::accumulateSourceLocFromDSYM(DSYMPath, Ctx.Target); 658 } 659 660 void DylibVerifier::visitObjCInterface(const ObjCInterfaceRecord &R) { 661 if (R.isVerified()) 662 return; 663 SymbolContext SymCtx; 664 SymCtx.SymbolName = R.getName(); 665 SymCtx.ObjCIFKind = assignObjCIFSymbolKind(&R); 666 if (SymCtx.ObjCIFKind > ObjCIFSymbolKind::EHType) { 667 if (R.hasExceptionAttribute()) { 668 SymCtx.Kind = EncodeKind::ObjectiveCClassEHType; 669 visitSymbolInDylib(R, SymCtx); 670 } 671 SymCtx.Kind = EncodeKind::ObjectiveCClass; 672 visitSymbolInDylib(R, SymCtx); 673 } else { 674 SymCtx.Kind = R.hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType 675 : EncodeKind::ObjectiveCClass; 676 visitSymbolInDylib(R, SymCtx); 677 } 678 679 for (const ObjCIVarRecord *IV : R.getObjCIVars()) 680 visitObjCIVar(*IV, R.getName()); 681 } 682 683 void DylibVerifier::visitObjCCategory(const ObjCCategoryRecord &R) { 684 for (const ObjCIVarRecord *IV : R.getObjCIVars()) 685 visitObjCIVar(*IV, R.getSuperClassName()); 686 } 687 688 DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() { 689 if (getState() == Result::NoVerify) 690 return Result::NoVerify; 691 assert(!Dylib.empty() && "No binary to verify against"); 692 693 DWARFContext DWARFInfo; 694 DWARFCtx = &DWARFInfo; 695 Ctx.DiscoveredFirstError = false; 696 Ctx.PrintArch = true; 697 for (std::shared_ptr<RecordsSlice> Slice : Dylib) { 698 Ctx.Target = Slice->getTarget(); 699 Ctx.DylibSlice = Slice.get(); 700 Slice->visit(*this); 701 } 702 return getState(); 703 } 704 705 } // namespace installapi 706 } // namespace clang 707