1*0fca6ea1SDimitry Andric //===- DylibVerifier.cpp ----------------------------------------*- C++--*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #include "clang/InstallAPI/DylibVerifier.h" 10*0fca6ea1SDimitry Andric #include "DiagnosticBuilderWrappers.h" 11*0fca6ea1SDimitry Andric #include "clang/InstallAPI/FrontendRecords.h" 12*0fca6ea1SDimitry Andric #include "clang/InstallAPI/InstallAPIDiagnostic.h" 13*0fca6ea1SDimitry Andric #include "llvm/Demangle/Demangle.h" 14*0fca6ea1SDimitry Andric #include "llvm/TextAPI/DylibReader.h" 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric using namespace llvm::MachO; 17*0fca6ea1SDimitry Andric 18*0fca6ea1SDimitry Andric namespace clang { 19*0fca6ea1SDimitry Andric namespace installapi { 20*0fca6ea1SDimitry Andric 21*0fca6ea1SDimitry Andric /// Metadata stored about a mapping of a declaration to a symbol. 22*0fca6ea1SDimitry Andric struct DylibVerifier::SymbolContext { 23*0fca6ea1SDimitry Andric // Name to use for all querying and verification 24*0fca6ea1SDimitry Andric // purposes. 25*0fca6ea1SDimitry Andric std::string SymbolName{""}; 26*0fca6ea1SDimitry Andric 27*0fca6ea1SDimitry Andric // Kind to map symbol type against record. 28*0fca6ea1SDimitry Andric EncodeKind Kind = EncodeKind::GlobalSymbol; 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric // Frontend Attributes tied to the AST. 31*0fca6ea1SDimitry Andric const FrontendAttrs *FA = nullptr; 32*0fca6ea1SDimitry Andric 33*0fca6ea1SDimitry Andric // The ObjCInterface symbol type, if applicable. 34*0fca6ea1SDimitry Andric ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None; 35*0fca6ea1SDimitry Andric 36*0fca6ea1SDimitry Andric // Whether Decl is inlined. 37*0fca6ea1SDimitry Andric bool Inlined = false; 38*0fca6ea1SDimitry Andric }; 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric struct DylibVerifier::DWARFContext { 41*0fca6ea1SDimitry Andric // Track whether DSYM parsing has already been attempted to avoid re-parsing. 42*0fca6ea1SDimitry Andric bool ParsedDSYM{false}; 43*0fca6ea1SDimitry Andric 44*0fca6ea1SDimitry Andric // Lookup table for source locations by symbol name. 45*0fca6ea1SDimitry Andric DylibReader::SymbolToSourceLocMap SourceLocs{}; 46*0fca6ea1SDimitry Andric }; 47*0fca6ea1SDimitry Andric 48*0fca6ea1SDimitry Andric static bool isCppMangled(StringRef Name) { 49*0fca6ea1SDimitry Andric // InstallAPI currently only supports itanium manglings. 50*0fca6ea1SDimitry Andric return (Name.starts_with("_Z") || Name.starts_with("__Z") || 51*0fca6ea1SDimitry Andric Name.starts_with("___Z")); 52*0fca6ea1SDimitry Andric } 53*0fca6ea1SDimitry Andric 54*0fca6ea1SDimitry Andric static std::string demangle(StringRef Name) { 55*0fca6ea1SDimitry Andric // InstallAPI currently only supports itanium manglings. 56*0fca6ea1SDimitry Andric if (!isCppMangled(Name)) 57*0fca6ea1SDimitry Andric return Name.str(); 58*0fca6ea1SDimitry Andric char *Result = llvm::itaniumDemangle(Name); 59*0fca6ea1SDimitry Andric if (!Result) 60*0fca6ea1SDimitry Andric return Name.str(); 61*0fca6ea1SDimitry Andric 62*0fca6ea1SDimitry Andric std::string Demangled(Result); 63*0fca6ea1SDimitry Andric free(Result); 64*0fca6ea1SDimitry Andric return Demangled; 65*0fca6ea1SDimitry Andric } 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric std::string DylibVerifier::getAnnotatedName(const Record *R, 68*0fca6ea1SDimitry Andric SymbolContext &SymCtx, 69*0fca6ea1SDimitry Andric bool ValidSourceLoc) { 70*0fca6ea1SDimitry Andric assert(!SymCtx.SymbolName.empty() && "Expected symbol name"); 71*0fca6ea1SDimitry Andric 72*0fca6ea1SDimitry Andric const StringRef SymbolName = SymCtx.SymbolName; 73*0fca6ea1SDimitry Andric std::string PrettyName = 74*0fca6ea1SDimitry Andric (Demangle && (SymCtx.Kind == EncodeKind::GlobalSymbol)) 75*0fca6ea1SDimitry Andric ? demangle(SymbolName) 76*0fca6ea1SDimitry Andric : SymbolName.str(); 77*0fca6ea1SDimitry Andric 78*0fca6ea1SDimitry Andric std::string Annotation; 79*0fca6ea1SDimitry Andric if (R->isWeakDefined()) 80*0fca6ea1SDimitry Andric Annotation += "(weak-def) "; 81*0fca6ea1SDimitry Andric if (R->isWeakReferenced()) 82*0fca6ea1SDimitry Andric Annotation += "(weak-ref) "; 83*0fca6ea1SDimitry Andric if (R->isThreadLocalValue()) 84*0fca6ea1SDimitry Andric Annotation += "(tlv) "; 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric // Check if symbol represents only part of a @interface declaration. 87*0fca6ea1SDimitry Andric switch (SymCtx.ObjCIFKind) { 88*0fca6ea1SDimitry Andric default: 89*0fca6ea1SDimitry Andric break; 90*0fca6ea1SDimitry Andric case ObjCIFSymbolKind::EHType: 91*0fca6ea1SDimitry Andric return Annotation + "Exception Type of " + PrettyName; 92*0fca6ea1SDimitry Andric case ObjCIFSymbolKind::MetaClass: 93*0fca6ea1SDimitry Andric return Annotation + "Metaclass of " + PrettyName; 94*0fca6ea1SDimitry Andric case ObjCIFSymbolKind::Class: 95*0fca6ea1SDimitry Andric return Annotation + "Class of " + PrettyName; 96*0fca6ea1SDimitry Andric } 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric // Only print symbol type prefix or leading "_" if there is no source location 99*0fca6ea1SDimitry Andric // tied to it. This can only ever happen when the location has to come from 100*0fca6ea1SDimitry Andric // debug info. 101*0fca6ea1SDimitry Andric if (ValidSourceLoc) { 102*0fca6ea1SDimitry Andric StringRef PrettyNameRef(PrettyName); 103*0fca6ea1SDimitry Andric if ((SymCtx.Kind == EncodeKind::GlobalSymbol) && 104*0fca6ea1SDimitry Andric !isCppMangled(SymbolName) && PrettyNameRef.starts_with("_")) 105*0fca6ea1SDimitry Andric return Annotation + PrettyNameRef.drop_front(1).str(); 106*0fca6ea1SDimitry Andric return Annotation + PrettyName; 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric switch (SymCtx.Kind) { 110*0fca6ea1SDimitry Andric case EncodeKind::GlobalSymbol: 111*0fca6ea1SDimitry Andric return Annotation + PrettyName; 112*0fca6ea1SDimitry Andric case EncodeKind::ObjectiveCInstanceVariable: 113*0fca6ea1SDimitry Andric return Annotation + "(ObjC IVar) " + PrettyName; 114*0fca6ea1SDimitry Andric case EncodeKind::ObjectiveCClass: 115*0fca6ea1SDimitry Andric return Annotation + "(ObjC Class) " + PrettyName; 116*0fca6ea1SDimitry Andric case EncodeKind::ObjectiveCClassEHType: 117*0fca6ea1SDimitry Andric return Annotation + "(ObjC Class EH) " + PrettyName; 118*0fca6ea1SDimitry Andric } 119*0fca6ea1SDimitry Andric 120*0fca6ea1SDimitry Andric llvm_unreachable("unexpected case for EncodeKind"); 121*0fca6ea1SDimitry Andric } 122*0fca6ea1SDimitry Andric 123*0fca6ea1SDimitry Andric static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev, 124*0fca6ea1SDimitry Andric const DylibVerifier::Result Curr) { 125*0fca6ea1SDimitry Andric if (Prev == Curr) 126*0fca6ea1SDimitry Andric return Prev; 127*0fca6ea1SDimitry Andric 128*0fca6ea1SDimitry Andric // Never update from invalid or noverify state. 129*0fca6ea1SDimitry Andric if ((Prev == DylibVerifier::Result::Invalid) || 130*0fca6ea1SDimitry Andric (Prev == DylibVerifier::Result::NoVerify)) 131*0fca6ea1SDimitry Andric return Prev; 132*0fca6ea1SDimitry Andric 133*0fca6ea1SDimitry Andric // Don't let an ignored verification remove a valid one. 134*0fca6ea1SDimitry Andric if (Prev == DylibVerifier::Result::Valid && 135*0fca6ea1SDimitry Andric Curr == DylibVerifier::Result::Ignore) 136*0fca6ea1SDimitry Andric return Prev; 137*0fca6ea1SDimitry Andric 138*0fca6ea1SDimitry Andric return Curr; 139*0fca6ea1SDimitry Andric } 140*0fca6ea1SDimitry Andric // __private_extern__ is a deprecated specifier that clang does not 141*0fca6ea1SDimitry Andric // respect in all contexts, it should just be considered hidden for InstallAPI. 142*0fca6ea1SDimitry Andric static bool shouldIgnorePrivateExternAttr(const Decl *D) { 143*0fca6ea1SDimitry Andric if (const FunctionDecl *FD = cast<FunctionDecl>(D)) 144*0fca6ea1SDimitry Andric return FD->getStorageClass() == StorageClass::SC_PrivateExtern; 145*0fca6ea1SDimitry Andric if (const VarDecl *VD = cast<VarDecl>(D)) 146*0fca6ea1SDimitry Andric return VD->getStorageClass() == StorageClass::SC_PrivateExtern; 147*0fca6ea1SDimitry Andric 148*0fca6ea1SDimitry Andric return false; 149*0fca6ea1SDimitry Andric } 150*0fca6ea1SDimitry Andric 151*0fca6ea1SDimitry Andric Record *findRecordFromSlice(const RecordsSlice *Slice, StringRef Name, 152*0fca6ea1SDimitry Andric EncodeKind Kind) { 153*0fca6ea1SDimitry Andric switch (Kind) { 154*0fca6ea1SDimitry Andric case EncodeKind::GlobalSymbol: 155*0fca6ea1SDimitry Andric return Slice->findGlobal(Name); 156*0fca6ea1SDimitry Andric case EncodeKind::ObjectiveCInstanceVariable: 157*0fca6ea1SDimitry Andric return Slice->findObjCIVar(Name.contains('.'), Name); 158*0fca6ea1SDimitry Andric case EncodeKind::ObjectiveCClass: 159*0fca6ea1SDimitry Andric case EncodeKind::ObjectiveCClassEHType: 160*0fca6ea1SDimitry Andric return Slice->findObjCInterface(Name); 161*0fca6ea1SDimitry Andric } 162*0fca6ea1SDimitry Andric llvm_unreachable("unexpected end when finding record"); 163*0fca6ea1SDimitry Andric } 164*0fca6ea1SDimitry Andric 165*0fca6ea1SDimitry Andric void DylibVerifier::updateState(Result State) { 166*0fca6ea1SDimitry Andric Ctx.FrontendState = updateResult(Ctx.FrontendState, State); 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx, 170*0fca6ea1SDimitry Andric TargetList &&Targets) { 171*0fca6ea1SDimitry Andric if (Targets.empty()) 172*0fca6ea1SDimitry Andric Targets = {Ctx.Target}; 173*0fca6ea1SDimitry Andric 174*0fca6ea1SDimitry Andric Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets); 175*0fca6ea1SDimitry Andric } 176*0fca6ea1SDimitry Andric 177*0fca6ea1SDimitry Andric bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx, 178*0fca6ea1SDimitry Andric const Record *DR) { 179*0fca6ea1SDimitry Andric if (!SymCtx.FA->Avail.isObsoleted()) 180*0fca6ea1SDimitry Andric return false; 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric if (Zippered) 183*0fca6ea1SDimitry Andric DeferredZipperedSymbols[SymCtx.SymbolName].emplace_back(ZipperedDeclSource{ 184*0fca6ea1SDimitry Andric SymCtx.FA, &Ctx.Diag->getSourceManager(), Ctx.Target}); 185*0fca6ea1SDimitry Andric return true; 186*0fca6ea1SDimitry Andric } 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric bool DylibVerifier::shouldIgnoreReexport(const Record *R, 189*0fca6ea1SDimitry Andric SymbolContext &SymCtx) const { 190*0fca6ea1SDimitry Andric StringRef SymName = SymCtx.SymbolName; 191*0fca6ea1SDimitry Andric // Linker directive symbols can never be ignored. 192*0fca6ea1SDimitry Andric if (SymName.starts_with("$ld$")) 193*0fca6ea1SDimitry Andric return false; 194*0fca6ea1SDimitry Andric 195*0fca6ea1SDimitry Andric if (Reexports.empty()) 196*0fca6ea1SDimitry Andric return false; 197*0fca6ea1SDimitry Andric 198*0fca6ea1SDimitry Andric for (const InterfaceFile &Lib : Reexports) { 199*0fca6ea1SDimitry Andric if (!Lib.hasTarget(Ctx.Target)) 200*0fca6ea1SDimitry Andric continue; 201*0fca6ea1SDimitry Andric if (auto Sym = Lib.getSymbol(SymCtx.Kind, SymName, SymCtx.ObjCIFKind)) 202*0fca6ea1SDimitry Andric if ((*Sym)->hasTarget(Ctx.Target)) 203*0fca6ea1SDimitry Andric return true; 204*0fca6ea1SDimitry Andric } 205*0fca6ea1SDimitry Andric return false; 206*0fca6ea1SDimitry Andric } 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric bool DylibVerifier::shouldIgnoreInternalZipperedSymbol( 209*0fca6ea1SDimitry Andric const Record *R, const SymbolContext &SymCtx) const { 210*0fca6ea1SDimitry Andric if (!Zippered) 211*0fca6ea1SDimitry Andric return false; 212*0fca6ea1SDimitry Andric 213*0fca6ea1SDimitry Andric return Exports->findSymbol(SymCtx.Kind, SymCtx.SymbolName, 214*0fca6ea1SDimitry Andric SymCtx.ObjCIFKind) != nullptr; 215*0fca6ea1SDimitry Andric } 216*0fca6ea1SDimitry Andric 217*0fca6ea1SDimitry Andric bool DylibVerifier::shouldIgnoreZipperedAvailability(const Record *R, 218*0fca6ea1SDimitry Andric SymbolContext &SymCtx) { 219*0fca6ea1SDimitry Andric if (!(Zippered && SymCtx.FA->Avail.isUnavailable())) 220*0fca6ea1SDimitry Andric return false; 221*0fca6ea1SDimitry Andric 222*0fca6ea1SDimitry Andric // Collect source location incase there is an exported symbol to diagnose 223*0fca6ea1SDimitry Andric // during `verifyRemainingSymbols`. 224*0fca6ea1SDimitry Andric DeferredZipperedSymbols[SymCtx.SymbolName].emplace_back( 225*0fca6ea1SDimitry Andric ZipperedDeclSource{SymCtx.FA, SourceManagers.back().get(), Ctx.Target}); 226*0fca6ea1SDimitry Andric 227*0fca6ea1SDimitry Andric return true; 228*0fca6ea1SDimitry Andric } 229*0fca6ea1SDimitry Andric 230*0fca6ea1SDimitry Andric bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R, 231*0fca6ea1SDimitry Andric SymbolContext &SymCtx, 232*0fca6ea1SDimitry Andric const ObjCInterfaceRecord *DR) { 233*0fca6ea1SDimitry Andric const bool IsDeclVersionComplete = 234*0fca6ea1SDimitry Andric ((SymCtx.ObjCIFKind & ObjCIFSymbolKind::Class) == 235*0fca6ea1SDimitry Andric ObjCIFSymbolKind::Class) && 236*0fca6ea1SDimitry Andric ((SymCtx.ObjCIFKind & ObjCIFSymbolKind::MetaClass) == 237*0fca6ea1SDimitry Andric ObjCIFSymbolKind::MetaClass); 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric const bool IsDylibVersionComplete = DR->isCompleteInterface(); 240*0fca6ea1SDimitry Andric 241*0fca6ea1SDimitry Andric // The common case, a complete ObjCInterface. 242*0fca6ea1SDimitry Andric if (IsDeclVersionComplete && IsDylibVersionComplete) 243*0fca6ea1SDimitry Andric return true; 244*0fca6ea1SDimitry Andric 245*0fca6ea1SDimitry Andric auto PrintDiagnostic = [&](auto SymLinkage, const Record *Record, 246*0fca6ea1SDimitry Andric StringRef SymName, bool PrintAsWarning = false) { 247*0fca6ea1SDimitry Andric if (SymLinkage == RecordLinkage::Unknown) 248*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 249*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, PrintAsWarning 250*0fca6ea1SDimitry Andric ? diag::warn_library_missing_symbol 251*0fca6ea1SDimitry Andric : diag::err_library_missing_symbol) 252*0fca6ea1SDimitry Andric << SymName; 253*0fca6ea1SDimitry Andric }); 254*0fca6ea1SDimitry Andric else 255*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 256*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, PrintAsWarning 257*0fca6ea1SDimitry Andric ? diag::warn_library_hidden_symbol 258*0fca6ea1SDimitry Andric : diag::err_library_hidden_symbol) 259*0fca6ea1SDimitry Andric << SymName; 260*0fca6ea1SDimitry Andric }); 261*0fca6ea1SDimitry Andric }; 262*0fca6ea1SDimitry Andric 263*0fca6ea1SDimitry Andric if (IsDeclVersionComplete) { 264*0fca6ea1SDimitry Andric // The decl represents a complete ObjCInterface, but the symbols in the 265*0fca6ea1SDimitry Andric // dylib do not. Determine which symbol is missing. To keep older projects 266*0fca6ea1SDimitry Andric // building, treat this as a warning. 267*0fca6ea1SDimitry Andric if (!DR->isExportedSymbol(ObjCIFSymbolKind::Class)) { 268*0fca6ea1SDimitry Andric SymCtx.ObjCIFKind = ObjCIFSymbolKind::Class; 269*0fca6ea1SDimitry Andric PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::Class), R, 270*0fca6ea1SDimitry Andric getAnnotatedName(R, SymCtx), 271*0fca6ea1SDimitry Andric /*PrintAsWarning=*/true); 272*0fca6ea1SDimitry Andric } 273*0fca6ea1SDimitry Andric if (!DR->isExportedSymbol(ObjCIFSymbolKind::MetaClass)) { 274*0fca6ea1SDimitry Andric SymCtx.ObjCIFKind = ObjCIFSymbolKind::MetaClass; 275*0fca6ea1SDimitry Andric PrintDiagnostic(DR->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass), R, 276*0fca6ea1SDimitry Andric getAnnotatedName(R, SymCtx), 277*0fca6ea1SDimitry Andric /*PrintAsWarning=*/true); 278*0fca6ea1SDimitry Andric } 279*0fca6ea1SDimitry Andric return true; 280*0fca6ea1SDimitry Andric } 281*0fca6ea1SDimitry Andric 282*0fca6ea1SDimitry Andric if (DR->isExportedSymbol(SymCtx.ObjCIFKind)) { 283*0fca6ea1SDimitry Andric if (!IsDylibVersionComplete) { 284*0fca6ea1SDimitry Andric // Both the declaration and dylib have a non-complete interface. 285*0fca6ea1SDimitry Andric SymCtx.Kind = EncodeKind::GlobalSymbol; 286*0fca6ea1SDimitry Andric SymCtx.SymbolName = R->getName(); 287*0fca6ea1SDimitry Andric } 288*0fca6ea1SDimitry Andric return true; 289*0fca6ea1SDimitry Andric } 290*0fca6ea1SDimitry Andric 291*0fca6ea1SDimitry Andric // At this point that means there was not a matching class symbol 292*0fca6ea1SDimitry Andric // to represent the one discovered as a declaration. 293*0fca6ea1SDimitry Andric PrintDiagnostic(DR->getLinkageForSymbol(SymCtx.ObjCIFKind), R, 294*0fca6ea1SDimitry Andric SymCtx.SymbolName); 295*0fca6ea1SDimitry Andric return false; 296*0fca6ea1SDimitry Andric } 297*0fca6ea1SDimitry Andric 298*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, 299*0fca6ea1SDimitry Andric SymbolContext &SymCtx, 300*0fca6ea1SDimitry Andric const Record *DR) { 301*0fca6ea1SDimitry Andric 302*0fca6ea1SDimitry Andric if (R->isExported()) { 303*0fca6ea1SDimitry Andric if (!DR) { 304*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 305*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_library_missing_symbol) 306*0fca6ea1SDimitry Andric << getAnnotatedName(R, SymCtx); 307*0fca6ea1SDimitry Andric }); 308*0fca6ea1SDimitry Andric return Result::Invalid; 309*0fca6ea1SDimitry Andric } 310*0fca6ea1SDimitry Andric if (DR->isInternal()) { 311*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 312*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_library_hidden_symbol) 313*0fca6ea1SDimitry Andric << getAnnotatedName(R, SymCtx); 314*0fca6ea1SDimitry Andric }); 315*0fca6ea1SDimitry Andric return Result::Invalid; 316*0fca6ea1SDimitry Andric } 317*0fca6ea1SDimitry Andric } 318*0fca6ea1SDimitry Andric 319*0fca6ea1SDimitry Andric // Emit a diagnostic for hidden declarations with external symbols, except 320*0fca6ea1SDimitry Andric // when theres an inlined attribute. 321*0fca6ea1SDimitry Andric if ((R->isInternal() && !SymCtx.Inlined) && DR && DR->isExported()) { 322*0fca6ea1SDimitry Andric 323*0fca6ea1SDimitry Andric if (Mode == VerificationMode::ErrorsOnly) 324*0fca6ea1SDimitry Andric return Result::Ignore; 325*0fca6ea1SDimitry Andric 326*0fca6ea1SDimitry Andric if (shouldIgnorePrivateExternAttr(SymCtx.FA->D)) 327*0fca6ea1SDimitry Andric return Result::Ignore; 328*0fca6ea1SDimitry Andric 329*0fca6ea1SDimitry Andric if (shouldIgnoreInternalZipperedSymbol(R, SymCtx)) 330*0fca6ea1SDimitry Andric return Result::Ignore; 331*0fca6ea1SDimitry Andric 332*0fca6ea1SDimitry Andric unsigned ID; 333*0fca6ea1SDimitry Andric Result Outcome; 334*0fca6ea1SDimitry Andric if (Mode == VerificationMode::ErrorsAndWarnings) { 335*0fca6ea1SDimitry Andric ID = diag::warn_header_hidden_symbol; 336*0fca6ea1SDimitry Andric Outcome = Result::Ignore; 337*0fca6ea1SDimitry Andric } else { 338*0fca6ea1SDimitry Andric ID = diag::err_header_hidden_symbol; 339*0fca6ea1SDimitry Andric Outcome = Result::Invalid; 340*0fca6ea1SDimitry Andric } 341*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 342*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, ID) << getAnnotatedName(R, SymCtx); 343*0fca6ea1SDimitry Andric }); 344*0fca6ea1SDimitry Andric return Outcome; 345*0fca6ea1SDimitry Andric } 346*0fca6ea1SDimitry Andric 347*0fca6ea1SDimitry Andric if (R->isInternal()) 348*0fca6ea1SDimitry Andric return Result::Ignore; 349*0fca6ea1SDimitry Andric 350*0fca6ea1SDimitry Andric return Result::Valid; 351*0fca6ea1SDimitry Andric } 352*0fca6ea1SDimitry Andric 353*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R, 354*0fca6ea1SDimitry Andric SymbolContext &SymCtx, 355*0fca6ea1SDimitry Andric const Record *DR) { 356*0fca6ea1SDimitry Andric if (!SymCtx.FA->Avail.isUnavailable()) 357*0fca6ea1SDimitry Andric return Result::Valid; 358*0fca6ea1SDimitry Andric 359*0fca6ea1SDimitry Andric if (shouldIgnoreZipperedAvailability(R, SymCtx)) 360*0fca6ea1SDimitry Andric return Result::Ignore; 361*0fca6ea1SDimitry Andric 362*0fca6ea1SDimitry Andric const bool IsDeclAvailable = SymCtx.FA->Avail.isUnavailable(); 363*0fca6ea1SDimitry Andric 364*0fca6ea1SDimitry Andric switch (Mode) { 365*0fca6ea1SDimitry Andric case VerificationMode::ErrorsAndWarnings: 366*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 367*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::warn_header_availability_mismatch) 368*0fca6ea1SDimitry Andric << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; 369*0fca6ea1SDimitry Andric }); 370*0fca6ea1SDimitry Andric return Result::Ignore; 371*0fca6ea1SDimitry Andric case VerificationMode::Pedantic: 372*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 373*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_availability_mismatch) 374*0fca6ea1SDimitry Andric << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; 375*0fca6ea1SDimitry Andric }); 376*0fca6ea1SDimitry Andric return Result::Invalid; 377*0fca6ea1SDimitry Andric case VerificationMode::ErrorsOnly: 378*0fca6ea1SDimitry Andric return Result::Ignore; 379*0fca6ea1SDimitry Andric case VerificationMode::Invalid: 380*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected verification mode symbol verification"); 381*0fca6ea1SDimitry Andric } 382*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected verification mode symbol verification"); 383*0fca6ea1SDimitry Andric } 384*0fca6ea1SDimitry Andric 385*0fca6ea1SDimitry Andric bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx, 386*0fca6ea1SDimitry Andric const Record *DR) { 387*0fca6ea1SDimitry Andric if (DR->isThreadLocalValue() && !R->isThreadLocalValue()) { 388*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 389*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_dylib_symbol_flags_mismatch) 390*0fca6ea1SDimitry Andric << getAnnotatedName(DR, SymCtx) << DR->isThreadLocalValue(); 391*0fca6ea1SDimitry Andric }); 392*0fca6ea1SDimitry Andric return false; 393*0fca6ea1SDimitry Andric } 394*0fca6ea1SDimitry Andric if (!DR->isThreadLocalValue() && R->isThreadLocalValue()) { 395*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 396*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_symbol_flags_mismatch) 397*0fca6ea1SDimitry Andric << getAnnotatedName(R, SymCtx) << R->isThreadLocalValue(); 398*0fca6ea1SDimitry Andric }); 399*0fca6ea1SDimitry Andric return false; 400*0fca6ea1SDimitry Andric } 401*0fca6ea1SDimitry Andric 402*0fca6ea1SDimitry Andric if (DR->isWeakDefined() && !R->isWeakDefined()) { 403*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 404*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_dylib_symbol_flags_mismatch) 405*0fca6ea1SDimitry Andric << getAnnotatedName(DR, SymCtx) << R->isWeakDefined(); 406*0fca6ea1SDimitry Andric }); 407*0fca6ea1SDimitry Andric return false; 408*0fca6ea1SDimitry Andric } 409*0fca6ea1SDimitry Andric if (!DR->isWeakDefined() && R->isWeakDefined()) { 410*0fca6ea1SDimitry Andric Ctx.emitDiag([&]() { 411*0fca6ea1SDimitry Andric Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_symbol_flags_mismatch) 412*0fca6ea1SDimitry Andric << getAnnotatedName(R, SymCtx) << R->isWeakDefined(); 413*0fca6ea1SDimitry Andric }); 414*0fca6ea1SDimitry Andric return false; 415*0fca6ea1SDimitry Andric } 416*0fca6ea1SDimitry Andric 417*0fca6ea1SDimitry Andric return true; 418*0fca6ea1SDimitry Andric } 419*0fca6ea1SDimitry Andric 420*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::verifyImpl(Record *R, 421*0fca6ea1SDimitry Andric SymbolContext &SymCtx) { 422*0fca6ea1SDimitry Andric R->setVerify(); 423*0fca6ea1SDimitry Andric if (!canVerify()) { 424*0fca6ea1SDimitry Andric // Accumulate symbols when not in verifying against dylib. 425*0fca6ea1SDimitry Andric if (R->isExported() && !SymCtx.FA->Avail.isUnavailable() && 426*0fca6ea1SDimitry Andric !SymCtx.FA->Avail.isObsoleted()) { 427*0fca6ea1SDimitry Andric addSymbol(R, SymCtx); 428*0fca6ea1SDimitry Andric } 429*0fca6ea1SDimitry Andric return Ctx.FrontendState; 430*0fca6ea1SDimitry Andric } 431*0fca6ea1SDimitry Andric 432*0fca6ea1SDimitry Andric if (shouldIgnoreReexport(R, SymCtx)) { 433*0fca6ea1SDimitry Andric updateState(Result::Ignore); 434*0fca6ea1SDimitry Andric return Ctx.FrontendState; 435*0fca6ea1SDimitry Andric } 436*0fca6ea1SDimitry Andric 437*0fca6ea1SDimitry Andric Record *DR = 438*0fca6ea1SDimitry Andric findRecordFromSlice(Ctx.DylibSlice, SymCtx.SymbolName, SymCtx.Kind); 439*0fca6ea1SDimitry Andric if (DR) 440*0fca6ea1SDimitry Andric DR->setVerify(); 441*0fca6ea1SDimitry Andric 442*0fca6ea1SDimitry Andric if (shouldIgnoreObsolete(R, SymCtx, DR)) { 443*0fca6ea1SDimitry Andric updateState(Result::Ignore); 444*0fca6ea1SDimitry Andric return Ctx.FrontendState; 445*0fca6ea1SDimitry Andric } 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric // Unavailable declarations don't need matching symbols. 448*0fca6ea1SDimitry Andric if (SymCtx.FA->Avail.isUnavailable() && (!DR || DR->isInternal())) { 449*0fca6ea1SDimitry Andric updateState(Result::Valid); 450*0fca6ea1SDimitry Andric return Ctx.FrontendState; 451*0fca6ea1SDimitry Andric } 452*0fca6ea1SDimitry Andric 453*0fca6ea1SDimitry Andric Result VisibilityCheck = compareVisibility(R, SymCtx, DR); 454*0fca6ea1SDimitry Andric if (VisibilityCheck != Result::Valid) { 455*0fca6ea1SDimitry Andric updateState(VisibilityCheck); 456*0fca6ea1SDimitry Andric return Ctx.FrontendState; 457*0fca6ea1SDimitry Andric } 458*0fca6ea1SDimitry Andric 459*0fca6ea1SDimitry Andric // All missing symbol cases to diagnose have been handled now. 460*0fca6ea1SDimitry Andric if (!DR) { 461*0fca6ea1SDimitry Andric updateState(Result::Ignore); 462*0fca6ea1SDimitry Andric return Ctx.FrontendState; 463*0fca6ea1SDimitry Andric } 464*0fca6ea1SDimitry Andric 465*0fca6ea1SDimitry Andric // Check for mismatching ObjC interfaces. 466*0fca6ea1SDimitry Andric if (SymCtx.ObjCIFKind != ObjCIFSymbolKind::None) { 467*0fca6ea1SDimitry Andric if (!compareObjCInterfaceSymbols( 468*0fca6ea1SDimitry Andric R, SymCtx, Ctx.DylibSlice->findObjCInterface(DR->getName()))) { 469*0fca6ea1SDimitry Andric updateState(Result::Invalid); 470*0fca6ea1SDimitry Andric return Ctx.FrontendState; 471*0fca6ea1SDimitry Andric } 472*0fca6ea1SDimitry Andric } 473*0fca6ea1SDimitry Andric 474*0fca6ea1SDimitry Andric Result AvailabilityCheck = compareAvailability(R, SymCtx, DR); 475*0fca6ea1SDimitry Andric if (AvailabilityCheck != Result::Valid) { 476*0fca6ea1SDimitry Andric updateState(AvailabilityCheck); 477*0fca6ea1SDimitry Andric return Ctx.FrontendState; 478*0fca6ea1SDimitry Andric } 479*0fca6ea1SDimitry Andric 480*0fca6ea1SDimitry Andric if (!compareSymbolFlags(R, SymCtx, DR)) { 481*0fca6ea1SDimitry Andric updateState(Result::Invalid); 482*0fca6ea1SDimitry Andric return Ctx.FrontendState; 483*0fca6ea1SDimitry Andric } 484*0fca6ea1SDimitry Andric 485*0fca6ea1SDimitry Andric addSymbol(R, SymCtx); 486*0fca6ea1SDimitry Andric updateState(Result::Valid); 487*0fca6ea1SDimitry Andric return Ctx.FrontendState; 488*0fca6ea1SDimitry Andric } 489*0fca6ea1SDimitry Andric 490*0fca6ea1SDimitry Andric bool DylibVerifier::canVerify() { 491*0fca6ea1SDimitry Andric return Ctx.FrontendState != Result::NoVerify; 492*0fca6ea1SDimitry Andric } 493*0fca6ea1SDimitry Andric 494*0fca6ea1SDimitry Andric void DylibVerifier::assignSlice(const Target &T) { 495*0fca6ea1SDimitry Andric assert(T == Ctx.Target && "Active targets should match."); 496*0fca6ea1SDimitry Andric if (Dylib.empty()) 497*0fca6ea1SDimitry Andric return; 498*0fca6ea1SDimitry Andric 499*0fca6ea1SDimitry Andric // Note: there are no reexport slices with binaries, as opposed to TBD files, 500*0fca6ea1SDimitry Andric // so it can be assumed that the target match is the active top-level library. 501*0fca6ea1SDimitry Andric auto It = find_if( 502*0fca6ea1SDimitry Andric Dylib, [&T](const auto &Slice) { return T == Slice->getTarget(); }); 503*0fca6ea1SDimitry Andric 504*0fca6ea1SDimitry Andric assert(It != Dylib.end() && "Target slice should always exist."); 505*0fca6ea1SDimitry Andric Ctx.DylibSlice = It->get(); 506*0fca6ea1SDimitry Andric } 507*0fca6ea1SDimitry Andric 508*0fca6ea1SDimitry Andric void DylibVerifier::setTarget(const Target &T) { 509*0fca6ea1SDimitry Andric Ctx.Target = T; 510*0fca6ea1SDimitry Andric Ctx.DiscoveredFirstError = false; 511*0fca6ea1SDimitry Andric if (Dylib.empty()) { 512*0fca6ea1SDimitry Andric updateState(Result::NoVerify); 513*0fca6ea1SDimitry Andric return; 514*0fca6ea1SDimitry Andric } 515*0fca6ea1SDimitry Andric updateState(Result::Ignore); 516*0fca6ea1SDimitry Andric assignSlice(T); 517*0fca6ea1SDimitry Andric } 518*0fca6ea1SDimitry Andric 519*0fca6ea1SDimitry Andric void DylibVerifier::setSourceManager( 520*0fca6ea1SDimitry Andric IntrusiveRefCntPtr<SourceManager> SourceMgr) { 521*0fca6ea1SDimitry Andric if (!Ctx.Diag) 522*0fca6ea1SDimitry Andric return; 523*0fca6ea1SDimitry Andric SourceManagers.push_back(std::move(SourceMgr)); 524*0fca6ea1SDimitry Andric Ctx.Diag->setSourceManager(SourceManagers.back().get()); 525*0fca6ea1SDimitry Andric } 526*0fca6ea1SDimitry Andric 527*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R, 528*0fca6ea1SDimitry Andric const FrontendAttrs *FA, 529*0fca6ea1SDimitry Andric const StringRef SuperClass) { 530*0fca6ea1SDimitry Andric if (R->isVerified()) 531*0fca6ea1SDimitry Andric return getState(); 532*0fca6ea1SDimitry Andric 533*0fca6ea1SDimitry Andric std::string FullName = 534*0fca6ea1SDimitry Andric ObjCIVarRecord::createScopedName(SuperClass, R->getName()); 535*0fca6ea1SDimitry Andric SymbolContext SymCtx{FullName, EncodeKind::ObjectiveCInstanceVariable, FA}; 536*0fca6ea1SDimitry Andric return verifyImpl(R, SymCtx); 537*0fca6ea1SDimitry Andric } 538*0fca6ea1SDimitry Andric 539*0fca6ea1SDimitry Andric static ObjCIFSymbolKind assignObjCIFSymbolKind(const ObjCInterfaceRecord *R) { 540*0fca6ea1SDimitry Andric ObjCIFSymbolKind Result = ObjCIFSymbolKind::None; 541*0fca6ea1SDimitry Andric if (R->getLinkageForSymbol(ObjCIFSymbolKind::Class) != RecordLinkage::Unknown) 542*0fca6ea1SDimitry Andric Result |= ObjCIFSymbolKind::Class; 543*0fca6ea1SDimitry Andric if (R->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass) != 544*0fca6ea1SDimitry Andric RecordLinkage::Unknown) 545*0fca6ea1SDimitry Andric Result |= ObjCIFSymbolKind::MetaClass; 546*0fca6ea1SDimitry Andric if (R->getLinkageForSymbol(ObjCIFSymbolKind::EHType) != 547*0fca6ea1SDimitry Andric RecordLinkage::Unknown) 548*0fca6ea1SDimitry Andric Result |= ObjCIFSymbolKind::EHType; 549*0fca6ea1SDimitry Andric return Result; 550*0fca6ea1SDimitry Andric } 551*0fca6ea1SDimitry Andric 552*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::verify(ObjCInterfaceRecord *R, 553*0fca6ea1SDimitry Andric const FrontendAttrs *FA) { 554*0fca6ea1SDimitry Andric if (R->isVerified()) 555*0fca6ea1SDimitry Andric return getState(); 556*0fca6ea1SDimitry Andric SymbolContext SymCtx; 557*0fca6ea1SDimitry Andric SymCtx.SymbolName = R->getName(); 558*0fca6ea1SDimitry Andric SymCtx.ObjCIFKind = assignObjCIFSymbolKind(R); 559*0fca6ea1SDimitry Andric 560*0fca6ea1SDimitry Andric SymCtx.Kind = R->hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType 561*0fca6ea1SDimitry Andric : EncodeKind::ObjectiveCClass; 562*0fca6ea1SDimitry Andric SymCtx.FA = FA; 563*0fca6ea1SDimitry Andric 564*0fca6ea1SDimitry Andric return verifyImpl(R, SymCtx); 565*0fca6ea1SDimitry Andric } 566*0fca6ea1SDimitry Andric 567*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R, 568*0fca6ea1SDimitry Andric const FrontendAttrs *FA) { 569*0fca6ea1SDimitry Andric if (R->isVerified()) 570*0fca6ea1SDimitry Andric return getState(); 571*0fca6ea1SDimitry Andric 572*0fca6ea1SDimitry Andric // Global classifications could be obfusciated with `asm`. 573*0fca6ea1SDimitry Andric SimpleSymbol Sym = parseSymbol(R->getName()); 574*0fca6ea1SDimitry Andric SymbolContext SymCtx; 575*0fca6ea1SDimitry Andric SymCtx.SymbolName = Sym.Name; 576*0fca6ea1SDimitry Andric SymCtx.Kind = Sym.Kind; 577*0fca6ea1SDimitry Andric SymCtx.FA = FA; 578*0fca6ea1SDimitry Andric SymCtx.Inlined = R->isInlined(); 579*0fca6ea1SDimitry Andric return verifyImpl(R, SymCtx); 580*0fca6ea1SDimitry Andric } 581*0fca6ea1SDimitry Andric 582*0fca6ea1SDimitry Andric void DylibVerifier::VerifierContext::emitDiag(llvm::function_ref<void()> Report, 583*0fca6ea1SDimitry Andric RecordLoc *Loc) { 584*0fca6ea1SDimitry Andric if (!DiscoveredFirstError) { 585*0fca6ea1SDimitry Andric Diag->Report(diag::warn_target) 586*0fca6ea1SDimitry Andric << (PrintArch ? getArchitectureName(Target.Arch) 587*0fca6ea1SDimitry Andric : getTargetTripleName(Target)); 588*0fca6ea1SDimitry Andric DiscoveredFirstError = true; 589*0fca6ea1SDimitry Andric } 590*0fca6ea1SDimitry Andric if (Loc && Loc->isValid()) 591*0fca6ea1SDimitry Andric llvm::errs() << Loc->File << ":" << Loc->Line << ":" << 0 << ": "; 592*0fca6ea1SDimitry Andric 593*0fca6ea1SDimitry Andric Report(); 594*0fca6ea1SDimitry Andric } 595*0fca6ea1SDimitry Andric 596*0fca6ea1SDimitry Andric // The existence of weak-defined RTTI can not always be inferred from the 597*0fca6ea1SDimitry Andric // header files because they can be generated as part of an implementation 598*0fca6ea1SDimitry Andric // file. 599*0fca6ea1SDimitry Andric // InstallAPI doesn't warn about weak-defined RTTI, because this doesn't affect 600*0fca6ea1SDimitry Andric // static linking and so can be ignored for text-api files. 601*0fca6ea1SDimitry Andric static bool shouldIgnoreCpp(StringRef Name, bool IsWeakDef) { 602*0fca6ea1SDimitry Andric return (IsWeakDef && 603*0fca6ea1SDimitry Andric (Name.starts_with("__ZTI") || Name.starts_with("__ZTS"))); 604*0fca6ea1SDimitry Andric } 605*0fca6ea1SDimitry Andric void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { 606*0fca6ea1SDimitry Andric // Undefined symbols should not be in InstallAPI generated text-api files. 607*0fca6ea1SDimitry Andric if (R.isUndefined()) { 608*0fca6ea1SDimitry Andric updateState(Result::Valid); 609*0fca6ea1SDimitry Andric return; 610*0fca6ea1SDimitry Andric } 611*0fca6ea1SDimitry Andric 612*0fca6ea1SDimitry Andric // Internal symbols should not be in InstallAPI generated text-api files. 613*0fca6ea1SDimitry Andric if (R.isInternal()) { 614*0fca6ea1SDimitry Andric updateState(Result::Valid); 615*0fca6ea1SDimitry Andric return; 616*0fca6ea1SDimitry Andric } 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric // Allow zippered symbols with potentially mismatching availability 619*0fca6ea1SDimitry Andric // between macOS and macCatalyst in the final text-api file. 620*0fca6ea1SDimitry Andric const StringRef SymbolName(SymCtx.SymbolName); 621*0fca6ea1SDimitry Andric if (const Symbol *Sym = Exports->findSymbol(SymCtx.Kind, SymCtx.SymbolName, 622*0fca6ea1SDimitry Andric SymCtx.ObjCIFKind)) { 623*0fca6ea1SDimitry Andric if (Sym->hasArchitecture(Ctx.Target.Arch)) { 624*0fca6ea1SDimitry Andric updateState(Result::Ignore); 625*0fca6ea1SDimitry Andric return; 626*0fca6ea1SDimitry Andric } 627*0fca6ea1SDimitry Andric } 628*0fca6ea1SDimitry Andric 629*0fca6ea1SDimitry Andric const bool IsLinkerSymbol = SymbolName.starts_with("$ld$"); 630*0fca6ea1SDimitry Andric 631*0fca6ea1SDimitry Andric if (R.isVerified()) { 632*0fca6ea1SDimitry Andric // Check for unavailable symbols. 633*0fca6ea1SDimitry Andric // This should only occur in the zippered case where we ignored 634*0fca6ea1SDimitry Andric // availability until all headers have been parsed. 635*0fca6ea1SDimitry Andric auto It = DeferredZipperedSymbols.find(SymCtx.SymbolName); 636*0fca6ea1SDimitry Andric if (It == DeferredZipperedSymbols.end()) { 637*0fca6ea1SDimitry Andric updateState(Result::Valid); 638*0fca6ea1SDimitry Andric return; 639*0fca6ea1SDimitry Andric } 640*0fca6ea1SDimitry Andric 641*0fca6ea1SDimitry Andric ZipperedDeclSources Locs; 642*0fca6ea1SDimitry Andric for (const ZipperedDeclSource &ZSource : It->second) { 643*0fca6ea1SDimitry Andric if (ZSource.FA->Avail.isObsoleted()) { 644*0fca6ea1SDimitry Andric updateState(Result::Ignore); 645*0fca6ea1SDimitry Andric return; 646*0fca6ea1SDimitry Andric } 647*0fca6ea1SDimitry Andric if (ZSource.T.Arch != Ctx.Target.Arch) 648*0fca6ea1SDimitry Andric continue; 649*0fca6ea1SDimitry Andric Locs.emplace_back(ZSource); 650*0fca6ea1SDimitry Andric } 651*0fca6ea1SDimitry Andric assert(Locs.size() == 2 && "Expected two decls for zippered symbol"); 652*0fca6ea1SDimitry Andric 653*0fca6ea1SDimitry Andric // Print violating declarations per platform. 654*0fca6ea1SDimitry Andric for (const ZipperedDeclSource &ZSource : Locs) { 655*0fca6ea1SDimitry Andric unsigned DiagID = 0; 656*0fca6ea1SDimitry Andric if (Mode == VerificationMode::Pedantic || IsLinkerSymbol) { 657*0fca6ea1SDimitry Andric updateState(Result::Invalid); 658*0fca6ea1SDimitry Andric DiagID = diag::err_header_availability_mismatch; 659*0fca6ea1SDimitry Andric } else if (Mode == VerificationMode::ErrorsAndWarnings) { 660*0fca6ea1SDimitry Andric updateState(Result::Ignore); 661*0fca6ea1SDimitry Andric DiagID = diag::warn_header_availability_mismatch; 662*0fca6ea1SDimitry Andric } else { 663*0fca6ea1SDimitry Andric updateState(Result::Ignore); 664*0fca6ea1SDimitry Andric return; 665*0fca6ea1SDimitry Andric } 666*0fca6ea1SDimitry Andric // Bypass emitDiag banner and print the target everytime. 667*0fca6ea1SDimitry Andric Ctx.Diag->setSourceManager(ZSource.SrcMgr); 668*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::warn_target) << getTargetTripleName(ZSource.T); 669*0fca6ea1SDimitry Andric Ctx.Diag->Report(ZSource.FA->Loc, DiagID) 670*0fca6ea1SDimitry Andric << getAnnotatedName(&R, SymCtx) << ZSource.FA->Avail.isUnavailable() 671*0fca6ea1SDimitry Andric << ZSource.FA->Avail.isUnavailable(); 672*0fca6ea1SDimitry Andric } 673*0fca6ea1SDimitry Andric return; 674*0fca6ea1SDimitry Andric } 675*0fca6ea1SDimitry Andric 676*0fca6ea1SDimitry Andric if (shouldIgnoreCpp(SymbolName, R.isWeakDefined())) { 677*0fca6ea1SDimitry Andric updateState(Result::Valid); 678*0fca6ea1SDimitry Andric return; 679*0fca6ea1SDimitry Andric } 680*0fca6ea1SDimitry Andric 681*0fca6ea1SDimitry Andric if (Aliases.count({SymbolName.str(), SymCtx.Kind})) { 682*0fca6ea1SDimitry Andric updateState(Result::Valid); 683*0fca6ea1SDimitry Andric return; 684*0fca6ea1SDimitry Andric } 685*0fca6ea1SDimitry Andric 686*0fca6ea1SDimitry Andric // All checks at this point classify as some kind of violation. 687*0fca6ea1SDimitry Andric // The different verification modes dictate whether they are reported to the 688*0fca6ea1SDimitry Andric // user. 689*0fca6ea1SDimitry Andric if (IsLinkerSymbol || (Mode > VerificationMode::ErrorsOnly)) 690*0fca6ea1SDimitry Andric accumulateSrcLocForDylibSymbols(); 691*0fca6ea1SDimitry Andric RecordLoc Loc = DWARFCtx->SourceLocs.lookup(SymCtx.SymbolName); 692*0fca6ea1SDimitry Andric 693*0fca6ea1SDimitry Andric // Regardless of verification mode, error out on mismatched special linker 694*0fca6ea1SDimitry Andric // symbols. 695*0fca6ea1SDimitry Andric if (IsLinkerSymbol) { 696*0fca6ea1SDimitry Andric Ctx.emitDiag( 697*0fca6ea1SDimitry Andric [&]() { 698*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_header_symbol_missing) 699*0fca6ea1SDimitry Andric << getAnnotatedName(&R, SymCtx, Loc.isValid()); 700*0fca6ea1SDimitry Andric }, 701*0fca6ea1SDimitry Andric &Loc); 702*0fca6ea1SDimitry Andric updateState(Result::Invalid); 703*0fca6ea1SDimitry Andric return; 704*0fca6ea1SDimitry Andric } 705*0fca6ea1SDimitry Andric 706*0fca6ea1SDimitry Andric // Missing declarations for exported symbols are hard errors on Pedantic mode. 707*0fca6ea1SDimitry Andric if (Mode == VerificationMode::Pedantic) { 708*0fca6ea1SDimitry Andric Ctx.emitDiag( 709*0fca6ea1SDimitry Andric [&]() { 710*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_header_symbol_missing) 711*0fca6ea1SDimitry Andric << getAnnotatedName(&R, SymCtx, Loc.isValid()); 712*0fca6ea1SDimitry Andric }, 713*0fca6ea1SDimitry Andric &Loc); 714*0fca6ea1SDimitry Andric updateState(Result::Invalid); 715*0fca6ea1SDimitry Andric return; 716*0fca6ea1SDimitry Andric } 717*0fca6ea1SDimitry Andric 718*0fca6ea1SDimitry Andric // Missing declarations for exported symbols are warnings on ErrorsAndWarnings 719*0fca6ea1SDimitry Andric // mode. 720*0fca6ea1SDimitry Andric if (Mode == VerificationMode::ErrorsAndWarnings) { 721*0fca6ea1SDimitry Andric Ctx.emitDiag( 722*0fca6ea1SDimitry Andric [&]() { 723*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::warn_header_symbol_missing) 724*0fca6ea1SDimitry Andric << getAnnotatedName(&R, SymCtx, Loc.isValid()); 725*0fca6ea1SDimitry Andric }, 726*0fca6ea1SDimitry Andric &Loc); 727*0fca6ea1SDimitry Andric updateState(Result::Ignore); 728*0fca6ea1SDimitry Andric return; 729*0fca6ea1SDimitry Andric } 730*0fca6ea1SDimitry Andric 731*0fca6ea1SDimitry Andric // Missing declarations are dropped for ErrorsOnly mode. It is the last 732*0fca6ea1SDimitry Andric // remaining mode. 733*0fca6ea1SDimitry Andric updateState(Result::Ignore); 734*0fca6ea1SDimitry Andric return; 735*0fca6ea1SDimitry Andric } 736*0fca6ea1SDimitry Andric 737*0fca6ea1SDimitry Andric void DylibVerifier::visitGlobal(const GlobalRecord &R) { 738*0fca6ea1SDimitry Andric SymbolContext SymCtx; 739*0fca6ea1SDimitry Andric SimpleSymbol Sym = parseSymbol(R.getName()); 740*0fca6ea1SDimitry Andric SymCtx.SymbolName = Sym.Name; 741*0fca6ea1SDimitry Andric SymCtx.Kind = Sym.Kind; 742*0fca6ea1SDimitry Andric visitSymbolInDylib(R, SymCtx); 743*0fca6ea1SDimitry Andric } 744*0fca6ea1SDimitry Andric 745*0fca6ea1SDimitry Andric void DylibVerifier::visitObjCIVar(const ObjCIVarRecord &R, 746*0fca6ea1SDimitry Andric const StringRef Super) { 747*0fca6ea1SDimitry Andric SymbolContext SymCtx; 748*0fca6ea1SDimitry Andric SymCtx.SymbolName = ObjCIVarRecord::createScopedName(Super, R.getName()); 749*0fca6ea1SDimitry Andric SymCtx.Kind = EncodeKind::ObjectiveCInstanceVariable; 750*0fca6ea1SDimitry Andric visitSymbolInDylib(R, SymCtx); 751*0fca6ea1SDimitry Andric } 752*0fca6ea1SDimitry Andric 753*0fca6ea1SDimitry Andric void DylibVerifier::accumulateSrcLocForDylibSymbols() { 754*0fca6ea1SDimitry Andric if (DSYMPath.empty()) 755*0fca6ea1SDimitry Andric return; 756*0fca6ea1SDimitry Andric 757*0fca6ea1SDimitry Andric assert(DWARFCtx != nullptr && "Expected an initialized DWARFContext"); 758*0fca6ea1SDimitry Andric if (DWARFCtx->ParsedDSYM) 759*0fca6ea1SDimitry Andric return; 760*0fca6ea1SDimitry Andric DWARFCtx->ParsedDSYM = true; 761*0fca6ea1SDimitry Andric DWARFCtx->SourceLocs = 762*0fca6ea1SDimitry Andric DylibReader::accumulateSourceLocFromDSYM(DSYMPath, Ctx.Target); 763*0fca6ea1SDimitry Andric } 764*0fca6ea1SDimitry Andric 765*0fca6ea1SDimitry Andric void DylibVerifier::visitObjCInterface(const ObjCInterfaceRecord &R) { 766*0fca6ea1SDimitry Andric SymbolContext SymCtx; 767*0fca6ea1SDimitry Andric SymCtx.SymbolName = R.getName(); 768*0fca6ea1SDimitry Andric SymCtx.ObjCIFKind = assignObjCIFSymbolKind(&R); 769*0fca6ea1SDimitry Andric if (SymCtx.ObjCIFKind > ObjCIFSymbolKind::EHType) { 770*0fca6ea1SDimitry Andric if (R.hasExceptionAttribute()) { 771*0fca6ea1SDimitry Andric SymCtx.Kind = EncodeKind::ObjectiveCClassEHType; 772*0fca6ea1SDimitry Andric visitSymbolInDylib(R, SymCtx); 773*0fca6ea1SDimitry Andric } 774*0fca6ea1SDimitry Andric SymCtx.Kind = EncodeKind::ObjectiveCClass; 775*0fca6ea1SDimitry Andric visitSymbolInDylib(R, SymCtx); 776*0fca6ea1SDimitry Andric } else { 777*0fca6ea1SDimitry Andric SymCtx.Kind = R.hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType 778*0fca6ea1SDimitry Andric : EncodeKind::ObjectiveCClass; 779*0fca6ea1SDimitry Andric visitSymbolInDylib(R, SymCtx); 780*0fca6ea1SDimitry Andric } 781*0fca6ea1SDimitry Andric 782*0fca6ea1SDimitry Andric for (const ObjCIVarRecord *IV : R.getObjCIVars()) 783*0fca6ea1SDimitry Andric visitObjCIVar(*IV, R.getName()); 784*0fca6ea1SDimitry Andric } 785*0fca6ea1SDimitry Andric 786*0fca6ea1SDimitry Andric void DylibVerifier::visitObjCCategory(const ObjCCategoryRecord &R) { 787*0fca6ea1SDimitry Andric for (const ObjCIVarRecord *IV : R.getObjCIVars()) 788*0fca6ea1SDimitry Andric visitObjCIVar(*IV, R.getSuperClassName()); 789*0fca6ea1SDimitry Andric } 790*0fca6ea1SDimitry Andric 791*0fca6ea1SDimitry Andric DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() { 792*0fca6ea1SDimitry Andric if (getState() == Result::NoVerify) 793*0fca6ea1SDimitry Andric return Result::NoVerify; 794*0fca6ea1SDimitry Andric assert(!Dylib.empty() && "No binary to verify against"); 795*0fca6ea1SDimitry Andric 796*0fca6ea1SDimitry Andric DWARFContext DWARFInfo; 797*0fca6ea1SDimitry Andric DWARFCtx = &DWARFInfo; 798*0fca6ea1SDimitry Andric Ctx.Target = Target(Architecture::AK_unknown, PlatformType::PLATFORM_UNKNOWN); 799*0fca6ea1SDimitry Andric for (std::shared_ptr<RecordsSlice> Slice : Dylib) { 800*0fca6ea1SDimitry Andric if (Ctx.Target.Arch == Slice->getTarget().Arch) 801*0fca6ea1SDimitry Andric continue; 802*0fca6ea1SDimitry Andric Ctx.DiscoveredFirstError = false; 803*0fca6ea1SDimitry Andric Ctx.PrintArch = true; 804*0fca6ea1SDimitry Andric Ctx.Target = Slice->getTarget(); 805*0fca6ea1SDimitry Andric Ctx.DylibSlice = Slice.get(); 806*0fca6ea1SDimitry Andric Slice->visit(*this); 807*0fca6ea1SDimitry Andric } 808*0fca6ea1SDimitry Andric return getState(); 809*0fca6ea1SDimitry Andric } 810*0fca6ea1SDimitry Andric 811*0fca6ea1SDimitry Andric bool DylibVerifier::verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets, 812*0fca6ea1SDimitry Andric const BinaryAttrs &ProvidedBA, 813*0fca6ea1SDimitry Andric const LibAttrs &ProvidedReexports, 814*0fca6ea1SDimitry Andric const LibAttrs &ProvidedClients, 815*0fca6ea1SDimitry Andric const LibAttrs &ProvidedRPaths, 816*0fca6ea1SDimitry Andric const FileType &FT) { 817*0fca6ea1SDimitry Andric assert(!Dylib.empty() && "Need dylib to verify."); 818*0fca6ea1SDimitry Andric 819*0fca6ea1SDimitry Andric // Pickup any load commands that can differ per slice to compare. 820*0fca6ea1SDimitry Andric TargetList DylibTargets; 821*0fca6ea1SDimitry Andric LibAttrs DylibReexports; 822*0fca6ea1SDimitry Andric LibAttrs DylibClients; 823*0fca6ea1SDimitry Andric LibAttrs DylibRPaths; 824*0fca6ea1SDimitry Andric for (const std::shared_ptr<RecordsSlice> &RS : Dylib) { 825*0fca6ea1SDimitry Andric DylibTargets.push_back(RS->getTarget()); 826*0fca6ea1SDimitry Andric const BinaryAttrs &BinInfo = RS->getBinaryAttrs(); 827*0fca6ea1SDimitry Andric for (const StringRef LibName : BinInfo.RexportedLibraries) 828*0fca6ea1SDimitry Andric DylibReexports[LibName].set(DylibTargets.back().Arch); 829*0fca6ea1SDimitry Andric for (const StringRef LibName : BinInfo.AllowableClients) 830*0fca6ea1SDimitry Andric DylibClients[LibName].set(DylibTargets.back().Arch); 831*0fca6ea1SDimitry Andric // Compare attributes that are only representable in >= TBD_V5. 832*0fca6ea1SDimitry Andric if (FT >= FileType::TBD_V5) 833*0fca6ea1SDimitry Andric for (const StringRef Name : BinInfo.RPaths) 834*0fca6ea1SDimitry Andric DylibRPaths[Name].set(DylibTargets.back().Arch); 835*0fca6ea1SDimitry Andric } 836*0fca6ea1SDimitry Andric 837*0fca6ea1SDimitry Andric // Check targets first. 838*0fca6ea1SDimitry Andric ArchitectureSet ProvidedArchs = mapToArchitectureSet(ProvidedTargets); 839*0fca6ea1SDimitry Andric ArchitectureSet DylibArchs = mapToArchitectureSet(DylibTargets); 840*0fca6ea1SDimitry Andric if (ProvidedArchs != DylibArchs) { 841*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_architecture_mismatch) 842*0fca6ea1SDimitry Andric << ProvidedArchs << DylibArchs; 843*0fca6ea1SDimitry Andric return false; 844*0fca6ea1SDimitry Andric } 845*0fca6ea1SDimitry Andric auto ProvidedPlatforms = mapToPlatformVersionSet(ProvidedTargets); 846*0fca6ea1SDimitry Andric auto DylibPlatforms = mapToPlatformVersionSet(DylibTargets); 847*0fca6ea1SDimitry Andric if (ProvidedPlatforms != DylibPlatforms) { 848*0fca6ea1SDimitry Andric const bool DiffMinOS = 849*0fca6ea1SDimitry Andric mapToPlatformSet(ProvidedTargets) == mapToPlatformSet(DylibTargets); 850*0fca6ea1SDimitry Andric if (DiffMinOS) 851*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::warn_platform_mismatch) 852*0fca6ea1SDimitry Andric << ProvidedPlatforms << DylibPlatforms; 853*0fca6ea1SDimitry Andric else { 854*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_platform_mismatch) 855*0fca6ea1SDimitry Andric << ProvidedPlatforms << DylibPlatforms; 856*0fca6ea1SDimitry Andric return false; 857*0fca6ea1SDimitry Andric } 858*0fca6ea1SDimitry Andric } 859*0fca6ea1SDimitry Andric 860*0fca6ea1SDimitry Andric // Because InstallAPI requires certain attributes to match across architecture 861*0fca6ea1SDimitry Andric // slices, take the first one to compare those with. 862*0fca6ea1SDimitry Andric const BinaryAttrs &DylibBA = (*Dylib.begin())->getBinaryAttrs(); 863*0fca6ea1SDimitry Andric 864*0fca6ea1SDimitry Andric if (ProvidedBA.InstallName != DylibBA.InstallName) { 865*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_install_name_mismatch) 866*0fca6ea1SDimitry Andric << ProvidedBA.InstallName << DylibBA.InstallName; 867*0fca6ea1SDimitry Andric return false; 868*0fca6ea1SDimitry Andric } 869*0fca6ea1SDimitry Andric 870*0fca6ea1SDimitry Andric if (ProvidedBA.CurrentVersion != DylibBA.CurrentVersion) { 871*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_current_version_mismatch) 872*0fca6ea1SDimitry Andric << ProvidedBA.CurrentVersion << DylibBA.CurrentVersion; 873*0fca6ea1SDimitry Andric return false; 874*0fca6ea1SDimitry Andric } 875*0fca6ea1SDimitry Andric 876*0fca6ea1SDimitry Andric if (ProvidedBA.CompatVersion != DylibBA.CompatVersion) { 877*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_compatibility_version_mismatch) 878*0fca6ea1SDimitry Andric << ProvidedBA.CompatVersion << DylibBA.CompatVersion; 879*0fca6ea1SDimitry Andric return false; 880*0fca6ea1SDimitry Andric } 881*0fca6ea1SDimitry Andric 882*0fca6ea1SDimitry Andric if (ProvidedBA.AppExtensionSafe != DylibBA.AppExtensionSafe) { 883*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_appextension_safe_mismatch) 884*0fca6ea1SDimitry Andric << (ProvidedBA.AppExtensionSafe ? "true" : "false") 885*0fca6ea1SDimitry Andric << (DylibBA.AppExtensionSafe ? "true" : "false"); 886*0fca6ea1SDimitry Andric return false; 887*0fca6ea1SDimitry Andric } 888*0fca6ea1SDimitry Andric 889*0fca6ea1SDimitry Andric if (!DylibBA.TwoLevelNamespace) { 890*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_no_twolevel_namespace); 891*0fca6ea1SDimitry Andric return false; 892*0fca6ea1SDimitry Andric } 893*0fca6ea1SDimitry Andric 894*0fca6ea1SDimitry Andric if (ProvidedBA.OSLibNotForSharedCache != DylibBA.OSLibNotForSharedCache) { 895*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_shared_cache_eligiblity_mismatch) 896*0fca6ea1SDimitry Andric << (ProvidedBA.OSLibNotForSharedCache ? "true" : "false") 897*0fca6ea1SDimitry Andric << (DylibBA.OSLibNotForSharedCache ? "true" : "false"); 898*0fca6ea1SDimitry Andric return false; 899*0fca6ea1SDimitry Andric } 900*0fca6ea1SDimitry Andric 901*0fca6ea1SDimitry Andric if (ProvidedBA.ParentUmbrella.empty() && !DylibBA.ParentUmbrella.empty()) { 902*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_parent_umbrella_missing) 903*0fca6ea1SDimitry Andric << "installAPI option" << DylibBA.ParentUmbrella; 904*0fca6ea1SDimitry Andric return false; 905*0fca6ea1SDimitry Andric } 906*0fca6ea1SDimitry Andric 907*0fca6ea1SDimitry Andric if (!ProvidedBA.ParentUmbrella.empty() && DylibBA.ParentUmbrella.empty()) { 908*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_parent_umbrella_missing) 909*0fca6ea1SDimitry Andric << "binary file" << ProvidedBA.ParentUmbrella; 910*0fca6ea1SDimitry Andric return false; 911*0fca6ea1SDimitry Andric } 912*0fca6ea1SDimitry Andric 913*0fca6ea1SDimitry Andric if ((!ProvidedBA.ParentUmbrella.empty()) && 914*0fca6ea1SDimitry Andric (ProvidedBA.ParentUmbrella != DylibBA.ParentUmbrella)) { 915*0fca6ea1SDimitry Andric Ctx.Diag->Report(diag::err_parent_umbrella_mismatch) 916*0fca6ea1SDimitry Andric << ProvidedBA.ParentUmbrella << DylibBA.ParentUmbrella; 917*0fca6ea1SDimitry Andric return false; 918*0fca6ea1SDimitry Andric } 919*0fca6ea1SDimitry Andric 920*0fca6ea1SDimitry Andric auto CompareLibraries = [&](const LibAttrs &Provided, const LibAttrs &Dylib, 921*0fca6ea1SDimitry Andric unsigned DiagID_missing, unsigned DiagID_mismatch, 922*0fca6ea1SDimitry Andric bool Fatal = true) { 923*0fca6ea1SDimitry Andric if (Provided == Dylib) 924*0fca6ea1SDimitry Andric return true; 925*0fca6ea1SDimitry Andric 926*0fca6ea1SDimitry Andric for (const llvm::StringMapEntry<ArchitectureSet> &PAttr : Provided) { 927*0fca6ea1SDimitry Andric const auto DAttrIt = Dylib.find(PAttr.getKey()); 928*0fca6ea1SDimitry Andric if (DAttrIt == Dylib.end()) { 929*0fca6ea1SDimitry Andric Ctx.Diag->Report(DiagID_missing) << "binary file" << PAttr; 930*0fca6ea1SDimitry Andric if (Fatal) 931*0fca6ea1SDimitry Andric return false; 932*0fca6ea1SDimitry Andric } 933*0fca6ea1SDimitry Andric 934*0fca6ea1SDimitry Andric if (PAttr.getValue() != DAttrIt->getValue()) { 935*0fca6ea1SDimitry Andric Ctx.Diag->Report(DiagID_mismatch) << PAttr << *DAttrIt; 936*0fca6ea1SDimitry Andric if (Fatal) 937*0fca6ea1SDimitry Andric return false; 938*0fca6ea1SDimitry Andric } 939*0fca6ea1SDimitry Andric } 940*0fca6ea1SDimitry Andric 941*0fca6ea1SDimitry Andric for (const llvm::StringMapEntry<ArchitectureSet> &DAttr : Dylib) { 942*0fca6ea1SDimitry Andric const auto PAttrIt = Provided.find(DAttr.getKey()); 943*0fca6ea1SDimitry Andric if (PAttrIt == Provided.end()) { 944*0fca6ea1SDimitry Andric Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DAttr; 945*0fca6ea1SDimitry Andric if (!Fatal) 946*0fca6ea1SDimitry Andric continue; 947*0fca6ea1SDimitry Andric return false; 948*0fca6ea1SDimitry Andric } 949*0fca6ea1SDimitry Andric 950*0fca6ea1SDimitry Andric if (PAttrIt->getValue() != DAttr.getValue()) { 951*0fca6ea1SDimitry Andric if (Fatal) 952*0fca6ea1SDimitry Andric llvm_unreachable("this case was already covered above."); 953*0fca6ea1SDimitry Andric } 954*0fca6ea1SDimitry Andric } 955*0fca6ea1SDimitry Andric return true; 956*0fca6ea1SDimitry Andric }; 957*0fca6ea1SDimitry Andric 958*0fca6ea1SDimitry Andric if (!CompareLibraries(ProvidedReexports, DylibReexports, 959*0fca6ea1SDimitry Andric diag::err_reexported_libraries_missing, 960*0fca6ea1SDimitry Andric diag::err_reexported_libraries_mismatch)) 961*0fca6ea1SDimitry Andric return false; 962*0fca6ea1SDimitry Andric 963*0fca6ea1SDimitry Andric if (!CompareLibraries(ProvidedClients, DylibClients, 964*0fca6ea1SDimitry Andric diag::err_allowable_clients_missing, 965*0fca6ea1SDimitry Andric diag::err_allowable_clients_mismatch)) 966*0fca6ea1SDimitry Andric return false; 967*0fca6ea1SDimitry Andric 968*0fca6ea1SDimitry Andric if (FT >= FileType::TBD_V5) { 969*0fca6ea1SDimitry Andric // Ignore rpath differences if building an asan variant, since the 970*0fca6ea1SDimitry Andric // compiler injects additional paths. 971*0fca6ea1SDimitry Andric // FIXME: Building with sanitizers does not always change the install 972*0fca6ea1SDimitry Andric // name, so this is not a foolproof solution. 973*0fca6ea1SDimitry Andric if (!ProvidedBA.InstallName.ends_with("_asan")) { 974*0fca6ea1SDimitry Andric if (!CompareLibraries(ProvidedRPaths, DylibRPaths, 975*0fca6ea1SDimitry Andric diag::warn_rpaths_missing, 976*0fca6ea1SDimitry Andric diag::warn_rpaths_mismatch, 977*0fca6ea1SDimitry Andric /*Fatal=*/false)) 978*0fca6ea1SDimitry Andric return true; 979*0fca6ea1SDimitry Andric } 980*0fca6ea1SDimitry Andric } 981*0fca6ea1SDimitry Andric 982*0fca6ea1SDimitry Andric return true; 983*0fca6ea1SDimitry Andric } 984*0fca6ea1SDimitry Andric 985*0fca6ea1SDimitry Andric std::unique_ptr<SymbolSet> DylibVerifier::takeExports() { 986*0fca6ea1SDimitry Andric for (const auto &[Alias, Base] : Aliases) { 987*0fca6ea1SDimitry Andric TargetList Targets; 988*0fca6ea1SDimitry Andric SymbolFlags Flags = SymbolFlags::None; 989*0fca6ea1SDimitry Andric if (const Symbol *Sym = Exports->findSymbol(Base.second, Base.first)) { 990*0fca6ea1SDimitry Andric Flags = Sym->getFlags(); 991*0fca6ea1SDimitry Andric Targets = {Sym->targets().begin(), Sym->targets().end()}; 992*0fca6ea1SDimitry Andric } 993*0fca6ea1SDimitry Andric 994*0fca6ea1SDimitry Andric Record R(Alias.first, RecordLinkage::Exported, Flags); 995*0fca6ea1SDimitry Andric SymbolContext SymCtx; 996*0fca6ea1SDimitry Andric SymCtx.SymbolName = Alias.first; 997*0fca6ea1SDimitry Andric SymCtx.Kind = Alias.second; 998*0fca6ea1SDimitry Andric addSymbol(&R, SymCtx, std::move(Targets)); 999*0fca6ea1SDimitry Andric } 1000*0fca6ea1SDimitry Andric 1001*0fca6ea1SDimitry Andric return std::move(Exports); 1002*0fca6ea1SDimitry Andric } 1003*0fca6ea1SDimitry Andric 1004*0fca6ea1SDimitry Andric } // namespace installapi 1005*0fca6ea1SDimitry Andric } // namespace clang 1006