1 //===- RecordsSlice.cpp --------------------------------------------------===// 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 // Implements the Records Slice APIs. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/TextAPI/RecordsSlice.h" 14 #include "llvm/ADT/SetVector.h" 15 #include "llvm/TextAPI/Record.h" 16 #include "llvm/TextAPI/Symbol.h" 17 #include <utility> 18 19 using namespace llvm; 20 using namespace llvm::MachO; 21 22 Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags, 23 GlobalRecord::Kind GV, RecordLinkage Linkage) { 24 // Find a specific Record type to capture. 25 auto [APIName, SymKind, InterfaceType] = parseSymbol(Name); 26 Name = APIName; 27 switch (SymKind) { 28 case EncodeKind::GlobalSymbol: 29 return addGlobal(Name, Linkage, GV, Flags); 30 case EncodeKind::ObjectiveCClass: 31 return addObjCInterface(Name, Linkage, InterfaceType); 32 case EncodeKind::ObjectiveCClassEHType: { 33 ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType); 34 // When classes without ehtype are used in try/catch blocks 35 // a weak-defined symbol is exported. 36 if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined) 37 updateFlags(Rec, SymbolFlags::WeakDefined); 38 return Rec; 39 } 40 case EncodeKind::ObjectiveCInstanceVariable: { 41 auto [Super, IVar] = Name.split('.'); 42 // Attempt to find super class. 43 ObjCContainerRecord *Container = findContainer(/*isIVar=*/false, Super); 44 // If not found, create extension since there is no mapped class symbol. 45 if (Container == nullptr) 46 Container = addObjCCategory(Super, {}); 47 return addObjCIVar(Container, IVar, Linkage); 48 } 49 } 50 51 llvm_unreachable("unexpected symbol kind when adding to Record Slice"); 52 } 53 54 ObjCContainerRecord *RecordsSlice::findContainer(bool IsIVar, 55 StringRef Name) const { 56 StringRef Super = IsIVar ? Name.split('.').first : Name; 57 ObjCContainerRecord *Container = findObjCInterface(Super); 58 // Ivars can only exist with extensions, if they did not come from 59 // class. 60 if (Container == nullptr) 61 Container = findObjCCategory(Super, ""); 62 return Container; 63 } 64 65 template <typename R, typename C = RecordMap<R>, typename K = StringRef> 66 R *findRecord(K Key, const C &Container) { 67 const auto *Record = Container.find(Key); 68 if (Record == Container.end()) 69 return nullptr; 70 return Record->second.get(); 71 } 72 73 GlobalRecord *RecordsSlice::findGlobal(StringRef Name, 74 GlobalRecord::Kind GV) const { 75 auto *Record = findRecord<GlobalRecord>(Name, Globals); 76 if (!Record) 77 return nullptr; 78 79 switch (GV) { 80 case GlobalRecord::Kind::Variable: { 81 if (!Record->isVariable()) 82 return nullptr; 83 break; 84 } 85 case GlobalRecord::Kind::Function: { 86 if (!Record->isFunction()) 87 return nullptr; 88 break; 89 } 90 case GlobalRecord::Kind::Unknown: 91 return Record; 92 } 93 94 return Record; 95 } 96 97 RecordLinkage 98 ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const { 99 assert(CurrType <= ObjCIFSymbolKind::EHType && 100 "expected single ObjCIFSymbolKind enum value"); 101 if (CurrType == ObjCIFSymbolKind::Class) 102 return Linkages.Class; 103 104 if (CurrType == ObjCIFSymbolKind::MetaClass) 105 return Linkages.MetaClass; 106 107 if (CurrType == ObjCIFSymbolKind::EHType) 108 return Linkages.EHType; 109 110 llvm_unreachable("unexpected ObjCIFSymbolKind"); 111 } 112 113 void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType, 114 RecordLinkage Link) { 115 if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class) 116 Linkages.Class = std::max(Link, Linkages.Class); 117 if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass) 118 Linkages.MetaClass = std::max(Link, Linkages.MetaClass); 119 if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType) 120 Linkages.EHType = std::max(Link, Linkages.EHType); 121 122 // Obj-C Classes represent multiple symbols that could have competing 123 // linkages, in this case assign the largest one, when querying the linkage of 124 // the record itself. This allows visitors pick whether they want to account 125 // for complete symbol information. 126 Linkage = 127 std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType)); 128 } 129 130 ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const { 131 return findRecord<ObjCInterfaceRecord>(Name, Classes); 132 } 133 134 ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend, 135 StringRef Category) const { 136 return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category), 137 Categories); 138 } 139 140 ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const { 141 return findRecord<ObjCIVarRecord>(IVar, IVars); 142 } 143 144 ObjCIVarRecord *RecordsSlice::findObjCIVar(bool IsScopedName, 145 StringRef Name) const { 146 // If scoped name, the name of the container is known. 147 if (IsScopedName) { 148 // IVar does not exist if there is not a container assigned to it. 149 auto *Container = findContainer(/*IsIVar=*/true, Name); 150 if (!Container) 151 return nullptr; 152 153 StringRef IVar = Name.substr(Name.find_first_of('.') + 1); 154 return Container->findObjCIVar(IVar); 155 } 156 157 // Otherwise traverse through containers and attempt to find IVar. 158 auto getIVar = [Name](auto &Records) -> ObjCIVarRecord * { 159 for (const auto &[_, Container] : Records) { 160 if (auto *IVarR = Container->findObjCIVar(Name)) 161 return IVarR; 162 } 163 return nullptr; 164 }; 165 166 if (auto *IVarRecord = getIVar(Classes)) 167 return IVarRecord; 168 169 return getIVar(Categories); 170 } 171 172 GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage, 173 GlobalRecord::Kind GV, 174 SymbolFlags Flags) { 175 if (GV == GlobalRecord::Kind::Function) 176 Flags |= SymbolFlags::Text; 177 else if (GV == GlobalRecord::Kind::Variable) 178 Flags |= SymbolFlags::Data; 179 180 Name = copyString(Name); 181 auto Result = Globals.insert({Name, nullptr}); 182 if (Result.second) 183 Result.first->second = 184 std::make_unique<GlobalRecord>(Name, Linkage, Flags, GV); 185 else { 186 updateLinkage(Result.first->second.get(), Linkage); 187 updateFlags(Result.first->second.get(), Flags); 188 } 189 return Result.first->second.get(); 190 } 191 192 ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name, 193 RecordLinkage Linkage, 194 ObjCIFSymbolKind SymType) { 195 Name = copyString(Name); 196 auto Result = Classes.insert({Name, nullptr}); 197 if (Result.second) 198 Result.first->second = 199 std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType); 200 else 201 Result.first->second->updateLinkageForSymbols(SymType, Linkage); 202 return Result.first->second.get(); 203 } 204 205 SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) { 206 // Add Linkage properties into Flags. 207 switch (Linkage) { 208 case RecordLinkage::Rexported: 209 Flags |= SymbolFlags::Rexported; 210 return Flags; 211 case RecordLinkage::Undefined: 212 Flags |= SymbolFlags::Undefined; 213 return Flags; 214 default: 215 return Flags; 216 } 217 } 218 219 bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) { 220 auto Result = Categories.insert({Name, Record}); 221 return Result.second; 222 } 223 224 ObjCCategoryRecord *RecordsSlice::addObjCCategory(StringRef ClassToExtend, 225 StringRef Category) { 226 Category = copyString(Category); 227 228 // Add owning record first into record slice. 229 auto Result = 230 Categories.insert({std::make_pair(ClassToExtend, Category), nullptr}); 231 if (Result.second) 232 Result.first->second = 233 std::make_unique<ObjCCategoryRecord>(ClassToExtend, Category); 234 235 // Then add reference to it in in the class. 236 if (auto *ObjCClass = findObjCInterface(ClassToExtend)) 237 ObjCClass->addObjCCategory(Result.first->second.get()); 238 239 return Result.first->second.get(); 240 } 241 242 std::vector<ObjCIVarRecord *> ObjCContainerRecord::getObjCIVars() const { 243 std::vector<ObjCIVarRecord *> Records; 244 llvm::for_each(IVars, 245 [&](auto &Record) { Records.push_back(Record.second.get()); }); 246 return Records; 247 } 248 249 std::vector<ObjCCategoryRecord *> 250 ObjCInterfaceRecord::getObjCCategories() const { 251 std::vector<ObjCCategoryRecord *> Records; 252 llvm::for_each(Categories, 253 [&](auto &Record) { Records.push_back(Record.second); }); 254 return Records; 255 } 256 257 ObjCIVarRecord *ObjCContainerRecord::addObjCIVar(StringRef IVar, 258 RecordLinkage Linkage) { 259 auto Result = IVars.insert({IVar, nullptr}); 260 if (Result.second) 261 Result.first->second = std::make_unique<ObjCIVarRecord>(IVar, Linkage); 262 return Result.first->second.get(); 263 } 264 265 ObjCIVarRecord *RecordsSlice::addObjCIVar(ObjCContainerRecord *Container, 266 StringRef Name, 267 RecordLinkage Linkage) { 268 Name = copyString(Name); 269 ObjCIVarRecord *Record = Container->addObjCIVar(Name, Linkage); 270 updateLinkage(Record, Linkage); 271 return Record; 272 } 273 274 StringRef RecordsSlice::copyString(StringRef String) { 275 if (String.empty()) 276 return {}; 277 278 if (StringAllocator.identifyObject(String.data())) 279 return String; 280 281 void *Ptr = StringAllocator.Allocate(String.size(), 1); 282 memcpy(Ptr, String.data(), String.size()); 283 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 284 } 285 286 RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() { 287 if (!hasBinaryAttrs()) 288 BA = std::make_unique<BinaryAttrs>(); 289 return *BA; 290 } 291 292 void RecordsSlice::visit(RecordVisitor &V) const { 293 for (auto &G : Globals) 294 V.visitGlobal(*G.second); 295 for (auto &C : Classes) 296 V.visitObjCInterface(*C.second); 297 for (auto &Cat : Categories) 298 V.visitObjCCategory(*Cat.second); 299 } 300 301 static std::unique_ptr<InterfaceFile> 302 createInterfaceFile(const Records &Slices, StringRef InstallName) { 303 // Pickup symbols first. 304 auto Symbols = std::make_unique<SymbolSet>(); 305 for (auto &S : Slices) { 306 if (S->empty()) 307 continue; 308 auto &BA = S->getBinaryAttrs(); 309 if (BA.InstallName != InstallName) 310 continue; 311 312 SymbolConverter Converter(Symbols.get(), S->getTarget(), 313 !BA.TwoLevelNamespace); 314 S->visit(Converter); 315 } 316 317 auto File = std::make_unique<InterfaceFile>(std::move(Symbols)); 318 File->setInstallName(InstallName); 319 // Assign other attributes. 320 for (auto &S : Slices) { 321 if (S->empty()) 322 continue; 323 auto &BA = S->getBinaryAttrs(); 324 if (BA.InstallName != InstallName) 325 continue; 326 const Target &Targ = S->getTarget(); 327 File->addTarget(Targ); 328 if (File->getFileType() == FileType::Invalid) 329 File->setFileType(BA.File); 330 if (BA.AppExtensionSafe && !File->isApplicationExtensionSafe()) 331 File->setApplicationExtensionSafe(); 332 if (BA.TwoLevelNamespace && !File->isTwoLevelNamespace()) 333 File->setTwoLevelNamespace(); 334 if (BA.OSLibNotForSharedCache && !File->isOSLibNotForSharedCache()) 335 File->setOSLibNotForSharedCache(); 336 if (File->getCurrentVersion().empty()) 337 File->setCurrentVersion(BA.CurrentVersion); 338 if (File->getCompatibilityVersion().empty()) 339 File->setCompatibilityVersion(BA.CompatVersion); 340 if (File->getSwiftABIVersion() == 0) 341 File->setSwiftABIVersion(BA.SwiftABI); 342 if (File->getPath().empty()) 343 File->setPath(BA.Path); 344 if (!BA.ParentUmbrella.empty()) 345 File->addParentUmbrella(Targ, BA.ParentUmbrella); 346 for (const auto &Client : BA.AllowableClients) 347 File->addAllowableClient(Client, Targ); 348 for (const auto &Lib : BA.RexportedLibraries) 349 File->addReexportedLibrary(Lib, Targ); 350 } 351 352 return File; 353 } 354 355 std::unique_ptr<InterfaceFile> 356 llvm::MachO::convertToInterfaceFile(const Records &Slices) { 357 std::unique_ptr<InterfaceFile> File; 358 if (Slices.empty()) 359 return File; 360 361 SetVector<StringRef> InstallNames; 362 for (auto &S : Slices) { 363 auto Name = S->getBinaryAttrs().InstallName; 364 if (Name.empty()) 365 continue; 366 InstallNames.insert(Name); 367 } 368 369 File = createInterfaceFile(Slices, *InstallNames.begin()); 370 for (StringRef IN : llvm::drop_begin(InstallNames)) 371 File->addDocument(createInterfaceFile(Slices, IN)); 372 373 return File; 374 } 375