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