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