xref: /freebsd/contrib/llvm-project/clang/include/clang/InstallAPI/DylibVerifier.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- InstallAPI/DylibVerifier.h -------------------------------*- 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 #ifndef LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
10 #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
11 
12 #include "clang/Basic/Diagnostic.h"
13 #include "clang/Basic/SourceManager.h"
14 #include "clang/InstallAPI/MachO.h"
15 
16 namespace clang {
17 namespace installapi {
18 struct FrontendAttrs;
19 
20 /// A list of InstallAPI verification modes.
21 enum class VerificationMode {
22   Invalid,
23   ErrorsOnly,
24   ErrorsAndWarnings,
25   Pedantic,
26 };
27 
28 using ReexportedInterfaces = llvm::SmallVector<llvm::MachO::InterfaceFile, 8>;
29 
30 /// Represents dynamic library specific attributes that are tied to
31 /// architecture slices. It is commonly used for comparing options
32 /// passed on the command line to installapi and what exists in dylib load
33 /// commands.
34 class LibAttrs {
35 public:
36   using Entry = std::pair<std::string, ArchitectureSet>;
37   using AttrsToArchs = llvm::SmallVector<Entry, 10>;
38 
39   // Mutable access to architecture set tied to the input attribute.
40   ArchitectureSet &getArchSet(StringRef Attr);
41   // Get entry based on the attribute.
42   std::optional<Entry> find(StringRef Attr) const;
43   // Immutable access to underlying container.
get()44   const AttrsToArchs &get() const { return LibraryAttributes; };
45   // Mutable access to underlying container.
get()46   AttrsToArchs &get() { return LibraryAttributes; };
47   bool operator==(const LibAttrs &Other) const { return Other.get() == get(); };
48 
49 private:
50   AttrsToArchs LibraryAttributes;
51 };
52 
53 // Pointers to information about a zippered declaration used for
54 // querying and reporting violations against different
55 // declarations that all map to the same symbol.
56 struct ZipperedDeclSource {
57   const FrontendAttrs *FA;
58   clang::SourceManager *SrcMgr;
59   Target T;
60 };
61 using ZipperedDeclSources = std::vector<ZipperedDeclSource>;
62 
63 /// Service responsible to tracking state of verification across the
64 /// lifetime of InstallAPI.
65 /// As declarations are collected during AST traversal, they are
66 /// compared as symbols against what is available in the binary dylib.
67 class DylibVerifier : llvm::MachO::RecordVisitor {
68 private:
69   struct SymbolContext;
70   struct DWARFContext;
71 
72 public:
73   enum class Result { NoVerify, Ignore, Valid, Invalid };
74   struct VerifierContext {
75     // Current target being verified against the AST.
76     llvm::MachO::Target Target;
77 
78     // Target specific API from binary.
79     RecordsSlice *DylibSlice = nullptr;
80 
81     // Query state of verification after AST has been traversed.
82     Result FrontendState = Result::Ignore;
83 
84     // First error for AST traversal, which is tied to the target triple.
85     bool DiscoveredFirstError = false;
86 
87     // Determines what kind of banner to print a violation for.
88     bool PrintArch = false;
89 
90     // Engine for reporting violations.
91     DiagnosticsEngine *Diag = nullptr;
92 
93     // Handle diagnostics reporting for target level violations.
94     void emitDiag(llvm::function_ref<void()> Report, RecordLoc *Loc = nullptr);
95 
96     VerifierContext() = default;
VerifierContextVerifierContext97     VerifierContext(DiagnosticsEngine *Diag) : Diag(Diag) {}
98   };
99 
100   DylibVerifier() = default;
101 
DylibVerifier(llvm::MachO::Records && Dylib,ReexportedInterfaces && Reexports,AliasMap Aliases,DiagnosticsEngine * Diag,VerificationMode Mode,bool Zippered,bool Demangle,StringRef DSYMPath)102   DylibVerifier(llvm::MachO::Records &&Dylib, ReexportedInterfaces &&Reexports,
103                 AliasMap Aliases, DiagnosticsEngine *Diag,
104                 VerificationMode Mode, bool Zippered, bool Demangle,
105                 StringRef DSYMPath)
106       : Dylib(std::move(Dylib)), Reexports(std::move(Reexports)),
107         Aliases(std::move(Aliases)), Mode(Mode), Zippered(Zippered),
108         Demangle(Demangle), DSYMPath(DSYMPath),
109         Exports(std::make_unique<SymbolSet>()), Ctx(VerifierContext{Diag}) {}
110 
111   Result verify(GlobalRecord *R, const FrontendAttrs *FA);
112   Result verify(ObjCInterfaceRecord *R, const FrontendAttrs *FA);
113   Result verify(ObjCIVarRecord *R, const FrontendAttrs *FA,
114                 const StringRef SuperClass);
115 
116   // Scan through dylib slices and report any remaining missing exports.
117   Result verifyRemainingSymbols();
118 
119   /// Compare and report the attributes represented as
120   /// load commands in the dylib to the attributes provided via options.
121   bool verifyBinaryAttrs(const ArrayRef<Target> ProvidedTargets,
122                          const BinaryAttrs &ProvidedBA,
123                          const LibAttrs &ProvidedReexports,
124                          const LibAttrs &ProvidedClients,
125                          const LibAttrs &ProvidedRPaths, const FileType &FT);
126 
127   /// Initialize target for verification.
128   void setTarget(const Target &T);
129 
130   /// Release ownership over exports.
131   std::unique_ptr<SymbolSet> takeExports();
132 
133   /// Get result of verification.
getState()134   Result getState() const { return Ctx.FrontendState; }
135 
136   /// Set different source managers to the same diagnostics engine.
137   void setSourceManager(IntrusiveRefCntPtr<SourceManager> SourceMgr);
138 
139 private:
140   /// Determine whether to compare declaration to symbol in binary.
141   bool canVerify();
142 
143   /// Shared implementation for verifying exported symbols.
144   Result verifyImpl(Record *R, SymbolContext &SymCtx);
145 
146   /// Check if declaration is marked as obsolete, they are
147   // expected to result in a symbol mismatch.
148   bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx,
149                             const Record *DR);
150 
151   /// Check if declaration is exported from a reexported library. These
152   /// symbols should be omitted from the text-api file.
153   bool shouldIgnoreReexport(const Record *R, SymbolContext &SymCtx) const;
154 
155   // Ignore and omit unavailable symbols in zippered libraries.
156   bool shouldIgnoreZipperedAvailability(const Record *R, SymbolContext &SymCtx);
157 
158   // Check if an internal declaration in zippered library has an
159   // external declaration for a different platform. This results
160   // in the symbol being in a "separate" platform slice.
161   bool shouldIgnoreInternalZipperedSymbol(const Record *R,
162                                           const SymbolContext &SymCtx) const;
163 
164   /// Compare the visibility declarations to the linkage of symbol found in
165   /// dylib.
166   Result compareVisibility(const Record *R, SymbolContext &SymCtx,
167                            const Record *DR);
168 
169   /// An ObjCInterfaceRecord can represent up to three symbols. When verifying,
170   // account for this granularity.
171   bool compareObjCInterfaceSymbols(const Record *R, SymbolContext &SymCtx,
172                                    const ObjCInterfaceRecord *DR);
173 
174   /// Validate availability annotations against dylib.
175   Result compareAvailability(const Record *R, SymbolContext &SymCtx,
176                              const Record *DR);
177 
178   /// Compare and validate matching symbol flags.
179   bool compareSymbolFlags(const Record *R, SymbolContext &SymCtx,
180                           const Record *DR);
181 
182   /// Update result state on each call to `verify`.
183   void updateState(Result State);
184 
185   /// Add verified exported symbol.
186   void addSymbol(const Record *R, SymbolContext &SymCtx,
187                  TargetList &&Targets = {});
188 
189   /// Find matching dylib slice for target triple that is being parsed.
190   void assignSlice(const Target &T);
191 
192   /// Shared implementation for verifying exported symbols in dylib.
193   void visitSymbolInDylib(const Record &R, SymbolContext &SymCtx);
194 
195   void visitGlobal(const GlobalRecord &R) override;
196   void visitObjCInterface(const ObjCInterfaceRecord &R) override;
197   void visitObjCCategory(const ObjCCategoryRecord &R) override;
198   void visitObjCIVar(const ObjCIVarRecord &R, const StringRef Super);
199 
200   /// Gather annotations for symbol for error reporting.
201   std::string getAnnotatedName(const Record *R, SymbolContext &SymCtx,
202                                bool ValidSourceLoc = true);
203 
204   /// Extract source location for symbol implementations.
205   /// As this is a relatively expensive operation, it is only used
206   /// when there is a violation to report and there is not a known declaration
207   /// in the interface.
208   void accumulateSrcLocForDylibSymbols();
209 
210   // Symbols in dylib.
211   llvm::MachO::Records Dylib;
212 
213   // Reexported interfaces apart of the library.
214   ReexportedInterfaces Reexports;
215 
216   // Symbol aliases.
217   AliasMap Aliases;
218 
219   // Controls what class of violations to report.
220   VerificationMode Mode = VerificationMode::Invalid;
221 
222   // Library is zippered.
223   bool Zippered = false;
224 
225   // Attempt to demangle when reporting violations.
226   bool Demangle = false;
227 
228   // File path to DSYM file.
229   StringRef DSYMPath;
230 
231   // Valid symbols in final text file.
232   std::unique_ptr<SymbolSet> Exports = std::make_unique<SymbolSet>();
233 
234   // Unavailable or obsoleted declarations for a zippered library.
235   // These are cross referenced against symbols in the dylib.
236   llvm::StringMap<ZipperedDeclSources> DeferredZipperedSymbols;
237 
238   // Track current state of verification while traversing AST.
239   VerifierContext Ctx;
240 
241   // Track DWARF provided source location for dylibs.
242   DWARFContext *DWARFCtx = nullptr;
243 
244   // Source manager for each unique compiler instance.
245   llvm::SmallVector<IntrusiveRefCntPtr<SourceManager>, 12> SourceManagers;
246 };
247 
248 } // namespace installapi
249 } // namespace clang
250 #endif // LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H
251