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