1 #include "clang/InstallAPI/DylibVerifier.h" 2 #include "clang/InstallAPI/FrontendRecords.h" 3 #include "llvm/Demangle/Demangle.h" 4 5 using namespace llvm::MachO; 6 7 namespace clang { 8 namespace installapi { 9 10 /// Metadata stored about a mapping of a declaration to a symbol. 11 struct DylibVerifier::SymbolContext { 12 // Name to use for printing in diagnostics. 13 std::string PrettyPrintName{""}; 14 15 // Name to use for all querying and verification 16 // purposes. 17 std::string SymbolName{""}; 18 19 // Kind to map symbol type against record. 20 EncodeKind Kind = EncodeKind::GlobalSymbol; 21 22 // Frontend Attributes tied to the AST. 23 const FrontendAttrs *FA = nullptr; 24 25 // The ObjCInterface symbol type, if applicable. 26 ObjCIFSymbolKind ObjCIFKind = ObjCIFSymbolKind::None; 27 }; 28 29 static std::string 30 getAnnotatedName(const Record *R, EncodeKind Kind, StringRef Name, 31 bool ValidSourceLoc = true, 32 ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) { 33 assert(!Name.empty() && "Need symbol name for printing"); 34 35 std::string Annotation; 36 if (R->isWeakDefined()) 37 Annotation += "(weak-def) "; 38 if (R->isWeakReferenced()) 39 Annotation += "(weak-ref) "; 40 if (R->isThreadLocalValue()) 41 Annotation += "(tlv) "; 42 43 // Check if symbol represents only part of a @interface declaration. 44 const bool IsAnnotatedObjCClass = ((ObjCIF != ObjCIFSymbolKind::None) && 45 (ObjCIF <= ObjCIFSymbolKind::EHType)); 46 47 if (IsAnnotatedObjCClass) { 48 if (ObjCIF == ObjCIFSymbolKind::EHType) 49 Annotation += "Exception Type of "; 50 if (ObjCIF == ObjCIFSymbolKind::MetaClass) 51 Annotation += "Metaclass of "; 52 if (ObjCIF == ObjCIFSymbolKind::Class) 53 Annotation += "Class of "; 54 } 55 56 // Only print symbol type prefix or leading "_" if there is no source location 57 // tied to it. This can only ever happen when the location has to come from 58 // debug info. 59 if (ValidSourceLoc) { 60 if ((Kind == EncodeKind::GlobalSymbol) && Name.starts_with("_")) 61 return Annotation + Name.drop_front(1).str(); 62 return Annotation + Name.str(); 63 } 64 65 if (IsAnnotatedObjCClass) 66 return Annotation + Name.str(); 67 68 switch (Kind) { 69 case EncodeKind::GlobalSymbol: 70 return Annotation + Name.str(); 71 case EncodeKind::ObjectiveCInstanceVariable: 72 return Annotation + "(ObjC IVar) " + Name.str(); 73 case EncodeKind::ObjectiveCClass: 74 return Annotation + "(ObjC Class) " + Name.str(); 75 case EncodeKind::ObjectiveCClassEHType: 76 return Annotation + "(ObjC Class EH) " + Name.str(); 77 } 78 79 llvm_unreachable("unexpected case for EncodeKind"); 80 } 81 82 static std::string demangle(StringRef Name) { 83 // Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'. 84 if (!(Name.starts_with("_Z") || Name.starts_with("___Z"))) 85 return Name.str(); 86 char *Result = llvm::itaniumDemangle(Name.data()); 87 if (!Result) 88 return Name.str(); 89 90 std::string Demangled(Result); 91 free(Result); 92 return Demangled; 93 } 94 95 static DylibVerifier::Result updateResult(const DylibVerifier::Result Prev, 96 const DylibVerifier::Result Curr) { 97 if (Prev == Curr) 98 return Prev; 99 100 // Never update from invalid or noverify state. 101 if ((Prev == DylibVerifier::Result::Invalid) || 102 (Prev == DylibVerifier::Result::NoVerify)) 103 return Prev; 104 105 // Don't let an ignored verification remove a valid one. 106 if (Prev == DylibVerifier::Result::Valid && 107 Curr == DylibVerifier::Result::Ignore) 108 return Prev; 109 110 return Curr; 111 } 112 113 void DylibVerifier::updateState(Result State) { 114 Ctx.FrontendState = updateResult(Ctx.FrontendState, State); 115 } 116 117 void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx, 118 TargetList &&Targets) { 119 if (Targets.empty()) 120 Targets = {Ctx.Target}; 121 122 Exports->addGlobal(SymCtx.Kind, SymCtx.SymbolName, R->getFlags(), Targets); 123 } 124 125 DylibVerifier::Result DylibVerifier::verifyImpl(Record *R, 126 SymbolContext &SymCtx) { 127 R->setVerify(); 128 if (!canVerify()) { 129 // Accumulate symbols when not in verifying against dylib. 130 if (R->isExported() && !SymCtx.FA->Avail.isUnconditionallyUnavailable() && 131 !SymCtx.FA->Avail.isObsoleted()) { 132 addSymbol(R, SymCtx); 133 } 134 return Ctx.FrontendState; 135 } 136 return Ctx.FrontendState; 137 } 138 139 bool DylibVerifier::canVerify() { 140 return Ctx.FrontendState != Result::NoVerify; 141 } 142 143 void DylibVerifier::setTarget(const Target &T) { 144 Ctx.Target = T; 145 Ctx.DiscoveredFirstError = false; 146 updateState(Dylib.empty() ? Result::NoVerify : Result::Ignore); 147 } 148 149 DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R, 150 const FrontendAttrs *FA, 151 const StringRef SuperClass) { 152 if (R->isVerified()) 153 return getState(); 154 155 std::string FullName = 156 ObjCIVarRecord::createScopedName(SuperClass, R->getName()); 157 SymbolContext SymCtx{ 158 getAnnotatedName(R, EncodeKind::ObjectiveCInstanceVariable, 159 Demangle ? demangle(FullName) : FullName), 160 FullName, EncodeKind::ObjectiveCInstanceVariable, FA}; 161 return verifyImpl(R, SymCtx); 162 } 163 164 static ObjCIFSymbolKind assignObjCIFSymbolKind(const ObjCInterfaceRecord *R) { 165 ObjCIFSymbolKind Result = ObjCIFSymbolKind::None; 166 if (R->getLinkageForSymbol(ObjCIFSymbolKind::Class) != RecordLinkage::Unknown) 167 Result |= ObjCIFSymbolKind::Class; 168 if (R->getLinkageForSymbol(ObjCIFSymbolKind::MetaClass) != 169 RecordLinkage::Unknown) 170 Result |= ObjCIFSymbolKind::MetaClass; 171 if (R->getLinkageForSymbol(ObjCIFSymbolKind::EHType) != 172 RecordLinkage::Unknown) 173 Result |= ObjCIFSymbolKind::EHType; 174 return Result; 175 } 176 177 DylibVerifier::Result DylibVerifier::verify(ObjCInterfaceRecord *R, 178 const FrontendAttrs *FA) { 179 if (R->isVerified()) 180 return getState(); 181 SymbolContext SymCtx; 182 SymCtx.SymbolName = R->getName(); 183 SymCtx.ObjCIFKind = assignObjCIFSymbolKind(R); 184 185 std::string DisplayName = 186 Demangle ? demangle(SymCtx.SymbolName) : SymCtx.SymbolName; 187 SymCtx.Kind = R->hasExceptionAttribute() ? EncodeKind::ObjectiveCClassEHType 188 : EncodeKind::ObjectiveCClass; 189 SymCtx.PrettyPrintName = getAnnotatedName(R, SymCtx.Kind, DisplayName); 190 SymCtx.FA = FA; 191 192 return verifyImpl(R, SymCtx); 193 } 194 195 DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R, 196 const FrontendAttrs *FA) { 197 if (R->isVerified()) 198 return getState(); 199 200 // Global classifications could be obfusciated with `asm`. 201 SimpleSymbol Sym = parseSymbol(R->getName()); 202 SymbolContext SymCtx; 203 SymCtx.SymbolName = Sym.Name; 204 SymCtx.PrettyPrintName = 205 getAnnotatedName(R, Sym.Kind, Demangle ? demangle(Sym.Name) : Sym.Name); 206 SymCtx.Kind = Sym.Kind; 207 SymCtx.FA = FA; 208 return verifyImpl(R, SymCtx); 209 } 210 211 } // namespace installapi 212 } // namespace clang 213