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