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