xref: /freebsd/contrib/llvm-project/clang/lib/InstallAPI/DylibVerifier.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
isCppMangled(StringRef Name)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 
demangle(StringRef Name)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 
getAnnotatedName(const Record * R,SymbolContext & SymCtx,bool ValidSourceLoc)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 
updateResult(const DylibVerifier::Result Prev,const DylibVerifier::Result Curr)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.
shouldIgnorePrivateExternAttr(const Decl * D)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 
findRecordFromSlice(const RecordsSlice * Slice,StringRef Name,EncodeKind Kind)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 
updateState(Result State)165*0fca6ea1SDimitry Andric void DylibVerifier::updateState(Result State) {
166*0fca6ea1SDimitry Andric   Ctx.FrontendState = updateResult(Ctx.FrontendState, State);
167*0fca6ea1SDimitry Andric }
168*0fca6ea1SDimitry Andric 
addSymbol(const Record * R,SymbolContext & SymCtx,TargetList && Targets)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 
shouldIgnoreObsolete(const Record * R,SymbolContext & SymCtx,const Record * DR)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 
shouldIgnoreReexport(const Record * R,SymbolContext & SymCtx) const188*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 
shouldIgnoreInternalZipperedSymbol(const Record * R,const SymbolContext & SymCtx) const208*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 
shouldIgnoreZipperedAvailability(const Record * R,SymbolContext & SymCtx)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 
compareObjCInterfaceSymbols(const Record * R,SymbolContext & SymCtx,const ObjCInterfaceRecord * DR)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 
compareVisibility(const Record * R,SymbolContext & SymCtx,const Record * DR)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 
compareAvailability(const Record * R,SymbolContext & SymCtx,const Record * DR)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 
compareSymbolFlags(const Record * R,SymbolContext & SymCtx,const Record * DR)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 
verifyImpl(Record * R,SymbolContext & SymCtx)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 
canVerify()490*0fca6ea1SDimitry Andric bool DylibVerifier::canVerify() {
491*0fca6ea1SDimitry Andric   return Ctx.FrontendState != Result::NoVerify;
492*0fca6ea1SDimitry Andric }
493*0fca6ea1SDimitry Andric 
assignSlice(const Target & T)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 
setTarget(const Target & T)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 
setSourceManager(IntrusiveRefCntPtr<SourceManager> SourceMgr)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 
verify(ObjCIVarRecord * R,const FrontendAttrs * FA,const StringRef SuperClass)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 
assignObjCIFSymbolKind(const ObjCInterfaceRecord * R)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 
verify(ObjCInterfaceRecord * R,const FrontendAttrs * FA)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 
verify(GlobalRecord * R,const FrontendAttrs * FA)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 
emitDiag(llvm::function_ref<void ()> Report,RecordLoc * Loc)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.
shouldIgnoreCpp(StringRef Name,bool IsWeakDef)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 }
visitSymbolInDylib(const Record & R,SymbolContext & SymCtx)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 
visitGlobal(const GlobalRecord & R)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 
visitObjCIVar(const ObjCIVarRecord & R,const StringRef Super)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 
accumulateSrcLocForDylibSymbols()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 
visitObjCInterface(const ObjCInterfaceRecord & R)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 
visitObjCCategory(const ObjCCategoryRecord & R)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 
verifyRemainingSymbols()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 
verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,const BinaryAttrs & ProvidedBA,const LibAttrs & ProvidedReexports,const LibAttrs & ProvidedClients,const LibAttrs & ProvidedRPaths,const FileType & FT)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 
takeExports()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