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
addRecord(StringRef Name,SymbolFlags Flags,GlobalRecord::Kind GV,RecordLinkage Linkage)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
findContainer(bool IsIVar,StringRef Name) const55 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>
findRecord(K Key,const C & Container)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
findGlobal(StringRef Name,GlobalRecord::Kind GV) const74 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
getLinkageForSymbol(ObjCIFSymbolKind CurrType) const99 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
updateLinkageForSymbols(ObjCIFSymbolKind SymType,RecordLinkage Link)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
findObjCInterface(StringRef Name) const131 ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
132 return findRecord<ObjCInterfaceRecord>(Name, Classes);
133 }
134
findObjCCategory(StringRef ClassToExtend,StringRef Category) const135 ObjCCategoryRecord *RecordsSlice::findObjCCategory(StringRef ClassToExtend,
136 StringRef Category) const {
137 return findRecord<ObjCCategoryRecord>(std::make_pair(ClassToExtend, Category),
138 Categories);
139 }
140
findObjCIVar(StringRef IVar) const141 ObjCIVarRecord *ObjCContainerRecord::findObjCIVar(StringRef IVar) const {
142 return findRecord<ObjCIVarRecord>(IVar, IVars);
143 }
144
findObjCIVar(bool IsScopedName,StringRef Name) const145 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
addGlobal(StringRef Name,RecordLinkage Linkage,GlobalRecord::Kind GV,SymbolFlags Flags,bool Inlined)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
addObjCInterface(StringRef Name,RecordLinkage Linkage,ObjCIFSymbolKind SymType)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
mergeFlags(SymbolFlags Flags,RecordLinkage Linkage)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
addObjCCategory(ObjCCategoryRecord * Record)220 bool ObjCInterfaceRecord::addObjCCategory(ObjCCategoryRecord *Record) {
221 auto Result = Categories.insert({Name, Record});
222 return Result.second;
223 }
224
addObjCCategory(StringRef ClassToExtend,StringRef Category)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
getObjCIVars() const243 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 *>
getObjCCategories() const252 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
addObjCIVar(StringRef IVar,RecordLinkage Linkage)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
addObjCIVar(ObjCContainerRecord * Container,StringRef Name,RecordLinkage Linkage)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
copyString(StringRef String)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
getBinaryAttrs()289 RecordsSlice::BinaryAttrs &RecordsSlice::getBinaryAttrs() {
290 if (!hasBinaryAttrs())
291 BA = std::make_unique<BinaryAttrs>();
292 return *BA;
293 }
294
visit(RecordVisitor & V) const295 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>
createInterfaceFile(const Records & Slices,StringRef InstallName)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>
convertToInterfaceFile(const Records & Slices)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