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