Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/TextStubV5.cpp
35262 views
1
//===- TextStubV5.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 Text Stub JSON mappings.
10
//
11
//===----------------------------------------------------------------------===//
12
#include "TextStubCommon.h"
13
#include "llvm/ADT/StringSwitch.h"
14
#include "llvm/Support/JSON.h"
15
#include <utility>
16
17
// clang-format off
18
/*
19
20
JSON Format specification.
21
22
All library level keys, accept target values and are defaulted if not specified.
23
24
{
25
"tapi_tbd_version": 5, # Required: TBD version for all documents in file
26
"main_library": { # Required: top level library
27
"target_info": [ # Required: target information
28
{
29
"target": "x86_64-macos",
30
"min_deployment": "10.14" # Optional: minOS defaults to 0
31
},
32
{
33
"target": "arm64-macos",
34
"min_deployment": "10.14"
35
},
36
{
37
"target": "arm64-maccatalyst",
38
"min_deployment": "12.1"
39
}],
40
"flags":[{"attributes": ["flat_namespace"]}], # Optional:
41
"install_names":[{"name":"/S/L/F/Foo.fwk/Foo"}], # Required: library install name
42
"current_versions":[{"version": "1.2"}], # Optional: defaults to 1
43
"compatibility_versions":[{ "version": "1.1"}], # Optional: defaults to 1
44
"rpaths": [ # Optional:
45
{
46
"targets": ["x86_64-macos"], # Optional: defaults to targets in `target-info`
47
"paths": ["@executable_path/.../Frameworks"]
48
}],
49
"parent_umbrellas": [{"umbrella": "System"}],
50
"allowable_clients": [{"clients": ["ClientA"]}],
51
"reexported_libraries": [{"names": ["/u/l/l/foo.dylib"]}],
52
"exported_symbols": [{ # List of export symbols section
53
"targets": ["x86_64-macos", "arm64-macos"], # Optional: defaults to targets in `target-info`
54
"text": { # List of Text segment symbols
55
"global": [ "_func" ],
56
"weak": [],
57
"thread_local": []
58
},
59
"data": { ... }, # List of Data segment symbols
60
}],
61
"reexported_symbols": [{ ... }], # List of reexported symbols section
62
"undefined_symbols": [{ ... }] # List of undefined symbols section
63
},
64
"libraries": [ # Optional: Array of inlined libraries
65
{...}, {...}, {...}
66
]
67
}
68
*/
69
// clang-format on
70
71
using namespace llvm;
72
using namespace llvm::json;
73
using namespace llvm::MachO;
74
75
namespace {
76
struct JSONSymbol {
77
EncodeKind Kind;
78
std::string Name;
79
SymbolFlags Flags;
80
};
81
82
using AttrToTargets = std::map<std::string, TargetList>;
83
using TargetsToSymbols =
84
SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>;
85
86
enum TBDKey : size_t {
87
TBDVersion = 0U,
88
MainLibrary,
89
Documents,
90
TargetInfo,
91
Targets,
92
Target,
93
Deployment,
94
Flags,
95
Attributes,
96
InstallName,
97
CurrentVersion,
98
CompatibilityVersion,
99
Version,
100
SwiftABI,
101
ABI,
102
ParentUmbrella,
103
Umbrella,
104
AllowableClients,
105
Clients,
106
ReexportLibs,
107
Names,
108
Name,
109
Exports,
110
Reexports,
111
Undefineds,
112
Data,
113
Text,
114
Weak,
115
ThreadLocal,
116
Globals,
117
ObjCClass,
118
ObjCEHType,
119
ObjCIvar,
120
RPath,
121
Paths,
122
};
123
124
std::array<StringRef, 64> Keys = {
125
"tapi_tbd_version",
126
"main_library",
127
"libraries",
128
"target_info",
129
"targets",
130
"target",
131
"min_deployment",
132
"flags",
133
"attributes",
134
"install_names",
135
"current_versions",
136
"compatibility_versions",
137
"version",
138
"swift_abi",
139
"abi",
140
"parent_umbrellas",
141
"umbrella",
142
"allowable_clients",
143
"clients",
144
"reexported_libraries",
145
"names",
146
"name",
147
"exported_symbols",
148
"reexported_symbols",
149
"undefined_symbols",
150
"data",
151
"text",
152
"weak",
153
"thread_local",
154
"global",
155
"objc_class",
156
"objc_eh_type",
157
"objc_ivar",
158
"rpaths",
159
"paths",
160
};
161
162
static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
163
return {"invalid ", Keys[Key], " section"};
164
}
165
166
static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
167
return {"missing ", Keys[Key], " information"};
168
}
169
170
class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
171
public:
172
JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
173
174
void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }
175
std::error_code convertToErrorCode() const override {
176
return llvm::inconvertibleErrorCode();
177
}
178
179
private:
180
std::string Message;
181
};
182
183
template <typename JsonT, typename StubT = JsonT>
184
Expected<StubT> getRequiredValue(
185
TBDKey Key, const Object *Obj,
186
std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
187
std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {
188
std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
189
if (!Val)
190
return make_error<JSONStubError>(getParseErrorMsg(Key));
191
192
if (Validate == nullptr)
193
return static_cast<StubT>(*Val);
194
195
std::optional<StubT> Result = Validate(*Val);
196
if (!Result.has_value())
197
return make_error<JSONStubError>(getParseErrorMsg(Key));
198
return Result.value();
199
}
200
201
template <typename JsonT, typename StubT = JsonT>
202
Expected<StubT> getRequiredValue(
203
TBDKey Key, const Object *Obj,
204
std::function<std::optional<JsonT>(const Object *, StringRef)> const
205
GetValue,
206
StubT DefaultValue, function_ref<std::optional<StubT>(JsonT)> Validate) {
207
std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
208
if (!Val)
209
return DefaultValue;
210
211
std::optional<StubT> Result;
212
Result = Validate(*Val);
213
if (!Result.has_value())
214
return make_error<JSONStubError>(getParseErrorMsg(Key));
215
return Result.value();
216
}
217
218
Error collectFromArray(TBDKey Key, const Object *Obj,
219
function_ref<void(StringRef)> Append,
220
bool IsRequired = false) {
221
const auto *Values = Obj->getArray(Keys[Key]);
222
if (!Values) {
223
if (IsRequired)
224
return make_error<JSONStubError>(getParseErrorMsg(Key));
225
return Error::success();
226
}
227
228
for (const Value &Val : *Values) {
229
auto ValStr = Val.getAsString();
230
if (!ValStr.has_value())
231
return make_error<JSONStubError>(getParseErrorMsg(Key));
232
Append(ValStr.value());
233
}
234
235
return Error::success();
236
}
237
238
namespace StubParser {
239
240
Expected<FileType> getVersion(const Object *File) {
241
auto VersionOrErr = getRequiredValue<int64_t, FileType>(
242
TBDKey::TBDVersion, File, &Object::getInteger,
243
[](int64_t Val) -> std::optional<FileType> {
244
unsigned Result = Val;
245
if (Result != 5)
246
return std::nullopt;
247
return FileType::TBD_V5;
248
});
249
250
if (!VersionOrErr)
251
return VersionOrErr.takeError();
252
return *VersionOrErr;
253
}
254
255
Expected<TargetList> getTargets(const Object *Section) {
256
const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
257
if (!Targets)
258
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
259
260
TargetList IFTargets;
261
for (const Value &JSONTarget : *Targets) {
262
auto TargetStr = JSONTarget.getAsString();
263
if (!TargetStr.has_value())
264
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
265
auto TargetOrErr = Target::create(TargetStr.value());
266
if (!TargetOrErr)
267
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
268
IFTargets.push_back(*TargetOrErr);
269
}
270
return std::move(IFTargets);
271
}
272
273
Expected<TargetList> getTargetsSection(const Object *Section) {
274
const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
275
if (!Targets)
276
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
277
278
TargetList IFTargets;
279
for (const Value &JSONTarget : *Targets) {
280
const auto *Obj = JSONTarget.getAsObject();
281
if (!Obj)
282
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
283
auto TargetStr =
284
getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
285
if (!TargetStr)
286
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
287
auto TargetOrErr = Target::create(*TargetStr);
288
if (!TargetOrErr)
289
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
290
291
auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
292
VersionTuple Version;
293
if (VersionStr && Version.tryParse(*VersionStr))
294
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
295
TargetOrErr->MinDeployment = Version;
296
297
// Convert to LLVM::Triple to accurately compute minOS + platform + arch
298
// pairing.
299
IFTargets.push_back(
300
MachO::Target(Triple(getTargetTripleName(*TargetOrErr))));
301
}
302
return std::move(IFTargets);
303
}
304
305
Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
306
SymbolFlags SectionFlag) {
307
auto Err = collectFromArray(
308
TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
309
JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), SectionFlag};
310
Result.back().second.emplace_back(Sym);
311
});
312
if (Err)
313
return Err;
314
315
Err = collectFromArray(
316
TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
317
JSONSymbol Sym = {EncodeKind::ObjectiveCClass, Name.str(), SectionFlag};
318
Result.back().second.emplace_back(Sym);
319
});
320
if (Err)
321
return Err;
322
323
Err = collectFromArray(TBDKey::ObjCEHType, Segment,
324
[&Result, &SectionFlag](StringRef Name) {
325
JSONSymbol Sym = {EncodeKind::ObjectiveCClassEHType,
326
Name.str(), SectionFlag};
327
Result.back().second.emplace_back(Sym);
328
});
329
if (Err)
330
return Err;
331
332
Err = collectFromArray(
333
TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
334
JSONSymbol Sym = {EncodeKind::ObjectiveCInstanceVariable, Name.str(),
335
SectionFlag};
336
Result.back().second.emplace_back(Sym);
337
});
338
if (Err)
339
return Err;
340
341
SymbolFlags WeakFlag =
342
SectionFlag |
343
(((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
344
? SymbolFlags::WeakReferenced
345
: SymbolFlags::WeakDefined);
346
Err = collectFromArray(
347
TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
348
JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), WeakFlag};
349
Result.back().second.emplace_back(Sym);
350
});
351
if (Err)
352
return Err;
353
354
Err = collectFromArray(
355
TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
356
JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(),
357
SymbolFlags::ThreadLocalValue | SectionFlag};
358
Result.back().second.emplace_back(Sym);
359
});
360
if (Err)
361
return Err;
362
363
return Error::success();
364
}
365
366
Expected<StringRef> getNameSection(const Object *File) {
367
const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
368
if (!Section)
369
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
370
371
assert(!Section->empty() && "unexpected missing install name");
372
// TODO: Just take first for now.
373
const auto *Obj = Section->front().getAsObject();
374
if (!Obj)
375
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
376
377
return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
378
}
379
380
Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
381
TargetList &Targets) {
382
383
const Array *Section = File->getArray(Keys[Key]);
384
if (!Section)
385
return TargetsToSymbols();
386
387
SymbolFlags SectionFlag;
388
switch (Key) {
389
case TBDKey::Reexports:
390
SectionFlag = SymbolFlags::Rexported;
391
break;
392
case TBDKey::Undefineds:
393
SectionFlag = SymbolFlags::Undefined;
394
break;
395
default:
396
SectionFlag = SymbolFlags::None;
397
break;
398
};
399
400
TargetsToSymbols Result;
401
TargetList MappedTargets;
402
for (auto Val : *Section) {
403
auto *Obj = Val.getAsObject();
404
if (!Obj)
405
continue;
406
407
auto TargetsOrErr = getTargets(Obj);
408
if (!TargetsOrErr) {
409
MappedTargets = Targets;
410
consumeError(TargetsOrErr.takeError());
411
} else {
412
MappedTargets = *TargetsOrErr;
413
}
414
Result.emplace_back(
415
std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
416
417
auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
418
auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
419
// There should be at least one valid section.
420
if (!DataSection && !TextSection)
421
return make_error<JSONStubError>(getParseErrorMsg(Key));
422
423
if (DataSection) {
424
auto Err = collectSymbolsFromSegment(DataSection, Result,
425
SectionFlag | SymbolFlags::Data);
426
if (Err)
427
return std::move(Err);
428
}
429
if (TextSection) {
430
auto Err = collectSymbolsFromSegment(TextSection, Result,
431
SectionFlag | SymbolFlags::Text);
432
if (Err)
433
return std::move(Err);
434
}
435
}
436
437
return std::move(Result);
438
}
439
440
Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
441
TBDKey SubKey,
442
const TargetList &Targets) {
443
auto *Section = File->getArray(Keys[Key]);
444
if (!Section)
445
return AttrToTargets();
446
447
AttrToTargets Result;
448
TargetList MappedTargets;
449
for (auto Val : *Section) {
450
auto *Obj = Val.getAsObject();
451
if (!Obj)
452
continue;
453
454
auto TargetsOrErr = getTargets(Obj);
455
if (!TargetsOrErr) {
456
MappedTargets = Targets;
457
consumeError(TargetsOrErr.takeError());
458
} else {
459
MappedTargets = *TargetsOrErr;
460
}
461
auto Err =
462
collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
463
Result[Key.str()] = MappedTargets;
464
});
465
if (Err)
466
return std::move(Err);
467
}
468
469
return std::move(Result);
470
}
471
472
Expected<AttrToTargets> getUmbrellaSection(const Object *File,
473
const TargetList &Targets) {
474
const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
475
if (!Umbrella)
476
return AttrToTargets();
477
478
AttrToTargets Result;
479
TargetList MappedTargets;
480
for (auto Val : *Umbrella) {
481
auto *Obj = Val.getAsObject();
482
if (!Obj)
483
return make_error<JSONStubError>(
484
getParseErrorMsg(TBDKey::ParentUmbrella));
485
486
// Get Targets section.
487
auto TargetsOrErr = getTargets(Obj);
488
if (!TargetsOrErr) {
489
MappedTargets = Targets;
490
consumeError(TargetsOrErr.takeError());
491
} else {
492
MappedTargets = *TargetsOrErr;
493
}
494
495
auto UmbrellaOrErr =
496
getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
497
if (!UmbrellaOrErr)
498
return UmbrellaOrErr.takeError();
499
Result[UmbrellaOrErr->str()] = Targets;
500
}
501
return std::move(Result);
502
}
503
504
Expected<uint8_t> getSwiftVersion(const Object *File) {
505
const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
506
if (!Versions)
507
return 0;
508
509
for (const auto &Val : *Versions) {
510
const auto *Obj = Val.getAsObject();
511
if (!Obj)
512
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
513
514
// TODO: Take first for now.
515
return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
516
&Object::getInteger);
517
}
518
519
return 0;
520
}
521
522
Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
523
const Array *Versions = File->getArray(Keys[Key]);
524
if (!Versions)
525
return PackedVersion(1, 0, 0);
526
527
for (const auto &Val : *Versions) {
528
const auto *Obj = Val.getAsObject();
529
if (!Obj)
530
return make_error<JSONStubError>(getParseErrorMsg(Key));
531
532
auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
533
PackedVersion PV;
534
auto [success, truncated] = PV.parse64(Version);
535
if (!success || truncated)
536
return std::nullopt;
537
return PV;
538
};
539
// TODO: Take first for now.
540
return getRequiredValue<StringRef, PackedVersion>(
541
TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
542
ValidatePV);
543
}
544
545
return PackedVersion(1, 0, 0);
546
}
547
548
Expected<TBDFlags> getFlags(const Object *File) {
549
TBDFlags Flags = TBDFlags::None;
550
const Array *Section = File->getArray(Keys[TBDKey::Flags]);
551
if (!Section || Section->empty())
552
return Flags;
553
554
for (auto &Val : *Section) {
555
// FIXME: Flags currently apply to all target triples.
556
const auto *Obj = Val.getAsObject();
557
if (!Obj)
558
return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
559
560
auto FlagsOrErr =
561
collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
562
TBDFlags TBDFlag =
563
StringSwitch<TBDFlags>(Flag)
564
.Case("flat_namespace", TBDFlags::FlatNamespace)
565
.Case("not_app_extension_safe",
566
TBDFlags::NotApplicationExtensionSafe)
567
.Case("sim_support", TBDFlags::SimulatorSupport)
568
.Case("not_for_dyld_shared_cache",
569
TBDFlags::OSLibNotForSharedCache)
570
.Default(TBDFlags::None);
571
Flags |= TBDFlag;
572
});
573
574
if (FlagsOrErr)
575
return std::move(FlagsOrErr);
576
577
return Flags;
578
}
579
580
return Flags;
581
}
582
583
using IFPtr = std::unique_ptr<InterfaceFile>;
584
Expected<IFPtr> parseToInterfaceFile(const Object *File) {
585
auto TargetsOrErr = getTargetsSection(File);
586
if (!TargetsOrErr)
587
return TargetsOrErr.takeError();
588
TargetList Targets = *TargetsOrErr;
589
590
auto NameOrErr = getNameSection(File);
591
if (!NameOrErr)
592
return NameOrErr.takeError();
593
StringRef Name = *NameOrErr;
594
595
auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
596
if (!CurrVersionOrErr)
597
return CurrVersionOrErr.takeError();
598
PackedVersion CurrVersion = *CurrVersionOrErr;
599
600
auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
601
if (!CompVersionOrErr)
602
return CompVersionOrErr.takeError();
603
PackedVersion CompVersion = *CompVersionOrErr;
604
605
auto SwiftABIOrErr = getSwiftVersion(File);
606
if (!SwiftABIOrErr)
607
return SwiftABIOrErr.takeError();
608
uint8_t SwiftABI = *SwiftABIOrErr;
609
610
auto FlagsOrErr = getFlags(File);
611
if (!FlagsOrErr)
612
return FlagsOrErr.takeError();
613
TBDFlags Flags = *FlagsOrErr;
614
615
auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
616
if (!UmbrellasOrErr)
617
return UmbrellasOrErr.takeError();
618
AttrToTargets Umbrellas = *UmbrellasOrErr;
619
620
auto ClientsOrErr =
621
getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
622
if (!ClientsOrErr)
623
return ClientsOrErr.takeError();
624
AttrToTargets Clients = *ClientsOrErr;
625
626
auto RLOrErr =
627
getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
628
if (!RLOrErr)
629
return RLOrErr.takeError();
630
AttrToTargets ReexportLibs = std::move(*RLOrErr);
631
632
auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
633
if (!RPathsOrErr)
634
return RPathsOrErr.takeError();
635
AttrToTargets RPaths = std::move(*RPathsOrErr);
636
637
auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
638
if (!ExportsOrErr)
639
return ExportsOrErr.takeError();
640
TargetsToSymbols Exports = std::move(*ExportsOrErr);
641
642
auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
643
if (!ReexportsOrErr)
644
return ReexportsOrErr.takeError();
645
TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
646
647
auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
648
if (!UndefinedsOrErr)
649
return UndefinedsOrErr.takeError();
650
TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
651
652
IFPtr F(new InterfaceFile);
653
F->setInstallName(Name);
654
F->setCurrentVersion(CurrVersion);
655
F->setCompatibilityVersion(CompVersion);
656
F->setSwiftABIVersion(SwiftABI);
657
F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
658
F->setApplicationExtensionSafe(
659
!(Flags & TBDFlags::NotApplicationExtensionSafe));
660
F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));
661
F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));
662
for (auto &T : Targets)
663
F->addTarget(T);
664
for (auto &[Lib, Targets] : Clients)
665
for (auto Target : Targets)
666
F->addAllowableClient(Lib, Target);
667
for (auto &[Lib, Targets] : ReexportLibs)
668
for (auto Target : Targets)
669
F->addReexportedLibrary(Lib, Target);
670
for (auto &[Lib, Targets] : Umbrellas)
671
for (auto Target : Targets)
672
F->addParentUmbrella(Target, Lib);
673
for (auto &[Path, Targets] : RPaths)
674
for (auto Target : Targets)
675
F->addRPath(Path, Target);
676
for (auto &[Targets, Symbols] : Exports)
677
for (auto &Sym : Symbols)
678
F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
679
for (auto &[Targets, Symbols] : Reexports)
680
for (auto &Sym : Symbols)
681
F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
682
for (auto &[Targets, Symbols] : Undefineds)
683
for (auto &Sym : Symbols)
684
F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
685
686
return std::move(F);
687
}
688
689
Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
690
std::vector<IFPtr> IFs;
691
const Array *Files = File->getArray(Keys[TBDKey::Documents]);
692
if (!Files)
693
return std::move(IFs);
694
695
for (auto Lib : *Files) {
696
auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
697
if (!IFOrErr)
698
return IFOrErr.takeError();
699
auto IF = std::move(*IFOrErr);
700
IFs.emplace_back(std::move(IF));
701
}
702
return std::move(IFs);
703
}
704
705
} // namespace StubParser
706
} // namespace
707
708
Expected<std::unique_ptr<InterfaceFile>>
709
MachO::getInterfaceFileFromJSON(StringRef JSON) {
710
auto ValOrErr = parse(JSON);
711
if (!ValOrErr)
712
return ValOrErr.takeError();
713
714
auto *Root = ValOrErr->getAsObject();
715
auto VersionOrErr = StubParser::getVersion(Root);
716
if (!VersionOrErr)
717
return VersionOrErr.takeError();
718
FileType Version = *VersionOrErr;
719
720
Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
721
auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
722
if (!IFOrErr)
723
return IFOrErr.takeError();
724
(*IFOrErr)->setFileType(Version);
725
std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
726
727
auto IFsOrErr = StubParser::getInlinedLibs(Root);
728
if (!IFsOrErr)
729
return IFsOrErr.takeError();
730
for (auto &File : *IFsOrErr) {
731
File->setFileType(Version);
732
IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
733
}
734
return std::move(IF);
735
}
736
737
namespace {
738
739
template <typename ContainerT = Array>
740
bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
741
if (Contents.empty())
742
return false;
743
Obj[Keys[Key]] = std::move(Contents);
744
return true;
745
}
746
747
std::string getFormattedStr(const MachO::Target &Targ) {
748
std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
749
? "maccatalyst"
750
: getOSAndEnvironmentName(Targ.Platform);
751
return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
752
}
753
754
template <typename AggregateT>
755
std::vector<std::string> serializeTargets(const AggregateT Targets,
756
const TargetList &ActiveTargets) {
757
std::vector<std::string> TargetsStr;
758
if (Targets.size() == ActiveTargets.size())
759
return TargetsStr;
760
761
for (const MachO::Target &Target : Targets)
762
TargetsStr.emplace_back(getFormattedStr(Target));
763
764
return TargetsStr;
765
}
766
767
Array serializeTargetInfo(const TargetList &ActiveTargets) {
768
Array Targets;
769
for (const auto Targ : ActiveTargets) {
770
Object TargetInfo;
771
if (!Targ.MinDeployment.empty())
772
TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
773
TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
774
Targets.emplace_back(std::move(TargetInfo));
775
}
776
return Targets;
777
}
778
779
template <typename ValueT, typename EntryT = ValueT>
780
Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
781
if (Value == Default)
782
return {};
783
Array Container;
784
Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
785
786
Container.emplace_back(std::move(ScalarObj));
787
return Container;
788
}
789
790
using TargetsToValuesMap =
791
std::map<std::vector<std::string>, std::vector<std::string>>;
792
793
template <typename AggregateT = TargetsToValuesMap>
794
Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
795
Array Container;
796
for (const auto &[Targets, Values] : Entries) {
797
Object Obj;
798
insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
799
Obj[Keys[Key]] = Values;
800
Container.emplace_back(std::move(Obj));
801
}
802
return Container;
803
}
804
805
template <typename ValueT = std::string,
806
typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
807
Array serializeField(TBDKey Key, const AggregateT &Values,
808
const TargetList &ActiveTargets, bool IsArray = true) {
809
std::map<ValueT, std::set<MachO::Target>> Entries;
810
for (const auto &[Target, Val] : Values)
811
Entries[Val].insert(Target);
812
813
if (!IsArray) {
814
std::map<std::vector<std::string>, std::string> FinalEntries;
815
for (const auto &[Val, Targets] : Entries)
816
FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
817
return serializeAttrToTargets(FinalEntries, Key);
818
}
819
820
TargetsToValuesMap FinalEntries;
821
for (const auto &[Val, Targets] : Entries)
822
FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
823
return serializeAttrToTargets(FinalEntries, Key);
824
}
825
826
Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
827
const TargetList &ActiveTargets) {
828
TargetsToValuesMap FinalEntries;
829
for (const auto &Ref : Values) {
830
TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
831
FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
832
Ref.getInstallName());
833
}
834
return serializeAttrToTargets(FinalEntries, Key);
835
}
836
837
struct SymbolFields {
838
struct SymbolTypes {
839
std::vector<StringRef> Weaks;
840
std::vector<StringRef> Globals;
841
std::vector<StringRef> TLV;
842
std::vector<StringRef> ObjCClasses;
843
std::vector<StringRef> IVars;
844
std::vector<StringRef> EHTypes;
845
846
bool empty() const {
847
return Weaks.empty() && Globals.empty() && TLV.empty() &&
848
ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
849
}
850
};
851
SymbolTypes Data;
852
SymbolTypes Text;
853
};
854
855
Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols,
856
const TargetList &ActiveTargets) {
857
auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
858
const Symbol *Sym) {
859
switch (Sym->getKind()) {
860
case EncodeKind::ObjectiveCClass:
861
Assignment.ObjCClasses.emplace_back(Sym->getName());
862
return;
863
case EncodeKind::ObjectiveCClassEHType:
864
Assignment.EHTypes.emplace_back(Sym->getName());
865
return;
866
case EncodeKind::ObjectiveCInstanceVariable:
867
Assignment.IVars.emplace_back(Sym->getName());
868
return;
869
case EncodeKind::GlobalSymbol: {
870
if (Sym->isWeakReferenced() || Sym->isWeakDefined())
871
Assignment.Weaks.emplace_back(Sym->getName());
872
else if (Sym->isThreadLocalValue())
873
Assignment.TLV.emplace_back(Sym->getName());
874
else
875
Assignment.Globals.emplace_back(Sym->getName());
876
return;
877
}
878
}
879
};
880
881
std::map<std::vector<std::string>, SymbolFields> Entries;
882
for (const auto *Sym : Symbols) {
883
std::set<MachO::Target> Targets{Sym->targets().begin(),
884
Sym->targets().end()};
885
auto JSONTargets = serializeTargets(Targets, ActiveTargets);
886
if (Sym->isData())
887
AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
888
else if (Sym->isText())
889
AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
890
else
891
llvm_unreachable("unexpected symbol type");
892
}
893
894
auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
895
SymbolFields::SymbolTypes &SymField) {
896
if (SymField.empty())
897
return;
898
Object Segment;
899
insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
900
insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
901
insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
902
insertNonEmptyValues(Segment, TBDKey::ObjCClass,
903
std::move(SymField.ObjCClasses));
904
insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
905
std::move(SymField.EHTypes));
906
insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
907
insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
908
};
909
910
Array SymbolSection;
911
for (auto &[Targets, Fields] : Entries) {
912
Object AllSyms;
913
insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
914
InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
915
InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
916
SymbolSection.emplace_back(std::move(AllSyms));
917
}
918
919
return SymbolSection;
920
}
921
922
Array serializeFlags(const InterfaceFile *File) {
923
// TODO: Give all Targets the same flags for now.
924
Array Flags;
925
if (!File->isTwoLevelNamespace())
926
Flags.emplace_back("flat_namespace");
927
if (!File->isApplicationExtensionSafe())
928
Flags.emplace_back("not_app_extension_safe");
929
if (File->hasSimulatorSupport())
930
Flags.emplace_back("sim_support");
931
if (File->isOSLibNotForSharedCache())
932
Flags.emplace_back("not_for_dyld_shared_cache");
933
return serializeScalar(TBDKey::Attributes, std::move(Flags));
934
}
935
936
Expected<Object> serializeIF(const InterfaceFile *File) {
937
Object Library;
938
939
// Handle required keys.
940
TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
941
if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
942
serializeTargetInfo(ActiveTargets)))
943
return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
944
945
Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
946
if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
947
return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
948
949
// Handle optional keys.
950
Array Flags = serializeFlags(File);
951
insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
952
953
Array CurrentV = serializeScalar<PackedVersion, std::string>(
954
TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
955
insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
956
957
Array CompatV = serializeScalar<PackedVersion, std::string>(
958
TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
959
insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
960
std::move(CompatV));
961
962
Array SwiftABI = serializeScalar<uint8_t, int64_t>(
963
TBDKey::ABI, File->getSwiftABIVersion(), 0u);
964
insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
965
966
Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
967
insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
968
969
Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
970
ActiveTargets, /*IsArray=*/false);
971
insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
972
973
Array Clients =
974
serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
975
insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
976
977
Array ReexportLibs =
978
serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
979
insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
980
981
// Handle symbols.
982
Array Exports = serializeSymbols(File->exports(), ActiveTargets);
983
insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
984
985
Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
986
insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
987
988
if (!File->isTwoLevelNamespace()) {
989
Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
990
insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
991
}
992
993
return std::move(Library);
994
}
995
996
Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
997
assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
998
Object Root;
999
1000
auto MainLibOrErr = serializeIF(File);
1001
if (!MainLibOrErr)
1002
return MainLibOrErr;
1003
Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
1004
Array Documents;
1005
for (const auto &Doc : File->documents()) {
1006
auto LibOrErr = serializeIF(Doc.get());
1007
if (!LibOrErr)
1008
return LibOrErr;
1009
Documents.emplace_back(std::move(*LibOrErr));
1010
}
1011
1012
Root[Keys[TBDKey::TBDVersion]] = 5;
1013
insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1014
return std::move(Root);
1015
}
1016
1017
} // namespace
1018
1019
Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS,
1020
const InterfaceFile &File,
1021
const FileType FileKind,
1022
bool Compact) {
1023
auto TextFile = getJSON(&File, FileKind);
1024
if (!TextFile)
1025
return TextFile.takeError();
1026
if (Compact)
1027
OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1028
else
1029
OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1030
return Error::success();
1031
}
1032
1033