brintos

brintos / llvm-project-archived public Read only

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