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