LLVM 22.0.0git
TextStubV5.cpp
Go to the documentation of this file.
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"
14#include "llvm/Support/JSON.h"
15#include <utility>
16
17// clang-format off
18/*
19
20JSON Format specification.
21
22All 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
71using namespace llvm;
72using namespace llvm::json;
73using namespace llvm::MachO;
74
75namespace {
76struct JSONSymbol {
77 EncodeKind Kind;
78 std::string Name;
79 SymbolFlags Flags;
80};
81
82using AttrToTargets = std::map<std::string, TargetList>;
83using TargetsToSymbols =
85
86/// Wrapper over a vector for handling textstub attributes, mapped to target
87/// triples, that require insertion order to be intact in the resulting \c
88/// InterfaceFile.
89class InOrderAttrToTargets {
90 using EntryT = std::pair<std::string, TargetList>;
91
92public:
93 void insert(EntryT &&Entry) {
94 auto &Element = get(Entry.first);
95 Element.second = Entry.second;
96 }
97
98 const EntryT *begin() { return Container.begin(); }
99 const EntryT *end() { return Container.end(); }
100
101private:
102 EntryT &get(std::string &Key) {
103 auto *It = find_if(Container,
104 [&Key](EntryT &Input) { return Input.first == Key; });
105 if (It != Container.end())
106 return *It;
107 Container.push_back(EntryT(Key, {}));
108 return Container.back();
109 }
111};
112
113enum TBDKey : size_t {
114 TBDVersion = 0U,
115 MainLibrary,
116 Documents,
117 TargetInfo,
118 Targets,
119 Target,
120 Deployment,
121 Flags,
122 Attributes,
123 InstallName,
125 CompatibilityVersion,
126 Version,
127 SwiftABI,
128 ABI,
129 ParentUmbrella,
130 Umbrella,
131 AllowableClients,
132 Clients,
133 ReexportLibs,
134 Names,
135 Name,
136 Exports,
137 Reexports,
138 Undefineds,
139 Data,
140 Text,
141 Weak,
142 ThreadLocal,
143 Globals,
144 ObjCClass,
145 ObjCEHType,
146 ObjCIvar,
147 RPath,
148 Paths,
149};
150
151std::array<StringRef, 64> Keys = {
152 "tapi_tbd_version",
153 "main_library",
154 "libraries",
155 "target_info",
156 "targets",
157 "target",
158 "min_deployment",
159 "flags",
160 "attributes",
161 "install_names",
162 "current_versions",
163 "compatibility_versions",
164 "version",
165 "swift_abi",
166 "abi",
167 "parent_umbrellas",
168 "umbrella",
169 "allowable_clients",
170 "clients",
171 "reexported_libraries",
172 "names",
173 "name",
174 "exported_symbols",
175 "reexported_symbols",
176 "undefined_symbols",
177 "data",
178 "text",
179 "weak",
180 "thread_local",
181 "global",
182 "objc_class",
183 "objc_eh_type",
184 "objc_ivar",
185 "rpaths",
186 "paths",
187};
188
189static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
190 return {"invalid ", Keys[Key], " section"};
191}
192
193static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
194 return {"missing ", Keys[Key], " information"};
195}
196
197class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
198public:
199 JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
200
201 void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }
202 std::error_code convertToErrorCode() const override {
204 }
205
206private:
207 std::string Message;
208};
209
210template <typename JsonT, typename StubT = JsonT>
211Expected<StubT> getRequiredValue(
212 TBDKey Key, const Object *Obj,
213 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
214 std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {
215 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
216 if (!Val)
217 return make_error<JSONStubError>(getParseErrorMsg(Key));
218
219 if (Validate == nullptr)
220 return static_cast<StubT>(*Val);
221
222 std::optional<StubT> Result = Validate(*Val);
223 if (!Result.has_value())
224 return make_error<JSONStubError>(getParseErrorMsg(Key));
225 return Result.value();
226}
227
228template <typename JsonT, typename StubT = JsonT>
229Expected<StubT> getRequiredValue(
230 TBDKey Key, const Object *Obj,
231 std::function<std::optional<JsonT>(const Object *, StringRef)> const
232 GetValue,
233 StubT DefaultValue, function_ref<std::optional<StubT>(JsonT)> Validate) {
234 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
235 if (!Val)
236 return DefaultValue;
237
238 std::optional<StubT> Result;
239 Result = Validate(*Val);
240 if (!Result.has_value())
241 return make_error<JSONStubError>(getParseErrorMsg(Key));
242 return Result.value();
243}
244
245Error collectFromArray(TBDKey Key, const Object *Obj,
246 function_ref<void(StringRef)> Append,
247 bool IsRequired = false) {
248 const auto *Values = Obj->getArray(Keys[Key]);
249 if (!Values) {
250 if (IsRequired)
251 return make_error<JSONStubError>(getParseErrorMsg(Key));
252 return Error::success();
253 }
254
255 for (const Value &Val : *Values) {
256 auto ValStr = Val.getAsString();
257 if (!ValStr.has_value())
258 return make_error<JSONStubError>(getParseErrorMsg(Key));
259 Append(ValStr.value());
260 }
261
262 return Error::success();
263}
264
265namespace StubParser {
266
267Expected<FileType> getVersion(const Object *File) {
268 auto VersionOrErr = getRequiredValue<int64_t, FileType>(
269 TBDKey::TBDVersion, File, &Object::getInteger,
270 [](int64_t Val) -> std::optional<FileType> {
271 unsigned Result = Val;
272 if (Result != 5)
273 return std::nullopt;
274 return FileType::TBD_V5;
275 });
276
277 if (!VersionOrErr)
278 return VersionOrErr.takeError();
279 return *VersionOrErr;
280}
281
282Expected<TargetList> getTargets(const Object *Section) {
283 const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
284 if (!Targets)
285 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
286
287 TargetList IFTargets;
288 for (const Value &JSONTarget : *Targets) {
289 auto TargetStr = JSONTarget.getAsString();
290 if (!TargetStr.has_value())
291 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
292 auto TargetOrErr = Target::create(TargetStr.value());
293 if (!TargetOrErr)
294 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
295 IFTargets.push_back(*TargetOrErr);
296 }
297 return std::move(IFTargets);
298}
299
300Expected<TargetList> getTargetsSection(const Object *Section) {
301 const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
302 if (!Targets)
303 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
304
305 TargetList IFTargets;
306 for (const Value &JSONTarget : *Targets) {
307 const auto *Obj = JSONTarget.getAsObject();
308 if (!Obj)
309 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
310 auto TargetStr =
311 getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
312 if (!TargetStr)
313 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
314 auto TargetOrErr = Target::create(*TargetStr);
315 if (!TargetOrErr)
316 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
317
318 auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
319 VersionTuple Version;
320 if (VersionStr && Version.tryParse(*VersionStr))
321 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
322 TargetOrErr->MinDeployment = Version;
323
324 // Convert to LLVM::Triple to accurately compute minOS + platform + arch
325 // pairing.
326 IFTargets.push_back(
328 }
329 return std::move(IFTargets);
330}
331
332Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
333 SymbolFlags SectionFlag) {
334 auto Err = collectFromArray(
335 TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
336 JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), SectionFlag};
337 Result.back().second.emplace_back(Sym);
338 });
339 if (Err)
340 return Err;
341
342 Err = collectFromArray(
343 TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
344 JSONSymbol Sym = {EncodeKind::ObjectiveCClass, Name.str(), SectionFlag};
345 Result.back().second.emplace_back(Sym);
346 });
347 if (Err)
348 return Err;
349
350 Err = collectFromArray(TBDKey::ObjCEHType, Segment,
351 [&Result, &SectionFlag](StringRef Name) {
352 JSONSymbol Sym = {EncodeKind::ObjectiveCClassEHType,
353 Name.str(), SectionFlag};
354 Result.back().second.emplace_back(Sym);
355 });
356 if (Err)
357 return Err;
358
359 Err = collectFromArray(
360 TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
361 JSONSymbol Sym = {EncodeKind::ObjectiveCInstanceVariable, Name.str(),
362 SectionFlag};
363 Result.back().second.emplace_back(Sym);
364 });
365 if (Err)
366 return Err;
367
368 SymbolFlags WeakFlag =
369 SectionFlag |
373 Err = collectFromArray(
374 TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
375 JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(), WeakFlag};
376 Result.back().second.emplace_back(Sym);
377 });
378 if (Err)
379 return Err;
380
381 Err = collectFromArray(
382 TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
383 JSONSymbol Sym = {EncodeKind::GlobalSymbol, Name.str(),
384 SymbolFlags::ThreadLocalValue | SectionFlag};
385 Result.back().second.emplace_back(Sym);
386 });
387 if (Err)
388 return Err;
389
390 return Error::success();
391}
392
393Expected<StringRef> getNameSection(const Object *File) {
394 const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
395 if (!Section)
396 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
397
398 assert(!Section->empty() && "unexpected missing install name");
399 // TODO: Just take first for now.
400 const auto *Obj = Section->front().getAsObject();
401 if (!Obj)
402 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
403
404 return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
405}
406
407Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
408 TargetList &Targets) {
409
410 const Array *Section = File->getArray(Keys[Key]);
411 if (!Section)
412 return TargetsToSymbols();
413
414 SymbolFlags SectionFlag;
415 switch (Key) {
416 case TBDKey::Reexports:
417 SectionFlag = SymbolFlags::Rexported;
418 break;
419 case TBDKey::Undefineds:
420 SectionFlag = SymbolFlags::Undefined;
421 break;
422 default:
423 SectionFlag = SymbolFlags::None;
424 break;
425 };
426
427 TargetsToSymbols Result;
428 TargetList MappedTargets;
429 for (auto Val : *Section) {
430 auto *Obj = Val.getAsObject();
431 if (!Obj)
432 continue;
433
434 auto TargetsOrErr = getTargets(Obj);
435 if (!TargetsOrErr) {
436 MappedTargets = Targets;
437 consumeError(TargetsOrErr.takeError());
438 } else {
439 MappedTargets = *TargetsOrErr;
440 }
441 Result.emplace_back(
442 std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
443
444 auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
445 auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
446 // There should be at least one valid section.
447 if (!DataSection && !TextSection)
448 return make_error<JSONStubError>(getParseErrorMsg(Key));
449
450 if (DataSection) {
451 auto Err = collectSymbolsFromSegment(DataSection, Result,
452 SectionFlag | SymbolFlags::Data);
453 if (Err)
454 return std::move(Err);
455 }
456 if (TextSection) {
457 auto Err = collectSymbolsFromSegment(TextSection, Result,
458 SectionFlag | SymbolFlags::Text);
459 if (Err)
460 return std::move(Err);
461 }
462 }
463
464 return std::move(Result);
465}
466
467template <typename ReturnT = AttrToTargets>
468Expected<ReturnT> getLibSection(const Object *File, TBDKey Key, TBDKey SubKey,
469 const TargetList &Targets) {
470 auto *Section = File->getArray(Keys[Key]);
471 if (!Section)
472 return ReturnT();
473
474 ReturnT Result;
475 TargetList MappedTargets;
476 for (auto Val : *Section) {
477 auto *Obj = Val.getAsObject();
478 if (!Obj)
479 continue;
480
481 auto TargetsOrErr = getTargets(Obj);
482 if (!TargetsOrErr) {
483 MappedTargets = Targets;
484 consumeError(TargetsOrErr.takeError());
485 } else {
486 MappedTargets = *TargetsOrErr;
487 }
488 auto Err =
489 collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
490 Result.insert({Key.str(), MappedTargets});
491 });
492 if (Err)
493 return std::move(Err);
494 }
495
496 return std::move(Result);
497}
498
499Expected<AttrToTargets> getUmbrellaSection(const Object *File,
500 const TargetList &Targets) {
501 const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
502 if (!Umbrella)
503 return AttrToTargets();
504
505 AttrToTargets Result;
506 TargetList MappedTargets;
507 for (auto Val : *Umbrella) {
508 auto *Obj = Val.getAsObject();
509 if (!Obj)
511 getParseErrorMsg(TBDKey::ParentUmbrella));
512
513 // Get Targets section.
514 auto TargetsOrErr = getTargets(Obj);
515 if (!TargetsOrErr) {
516 MappedTargets = Targets;
517 consumeError(TargetsOrErr.takeError());
518 } else {
519 MappedTargets = *TargetsOrErr;
520 }
521
522 auto UmbrellaOrErr =
523 getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
524 if (!UmbrellaOrErr)
525 return UmbrellaOrErr.takeError();
526 Result[UmbrellaOrErr->str()] = Targets;
527 }
528 return std::move(Result);
529}
530
531Expected<uint8_t> getSwiftVersion(const Object *File) {
532 const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
533 if (!Versions)
534 return 0;
535
536 for (const auto &Val : *Versions) {
537 const auto *Obj = Val.getAsObject();
538 if (!Obj)
539 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
540
541 // TODO: Take first for now.
542 return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
544 }
545
546 return 0;
547}
548
549Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
550 const Array *Versions = File->getArray(Keys[Key]);
551 if (!Versions)
552 return PackedVersion(1, 0, 0);
553
554 for (const auto &Val : *Versions) {
555 const auto *Obj = Val.getAsObject();
556 if (!Obj)
557 return make_error<JSONStubError>(getParseErrorMsg(Key));
558
559 auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
560 PackedVersion PV;
561 auto [success, truncated] = PV.parse64(Version);
562 if (!success || truncated)
563 return std::nullopt;
564 return PV;
565 };
566 // TODO: Take first for now.
567 return getRequiredValue<StringRef, PackedVersion>(
568 TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
569 ValidatePV);
570 }
571
572 return PackedVersion(1, 0, 0);
573}
574
576 TBDFlags Flags = TBDFlags::None;
577 const Array *Section = File->getArray(Keys[TBDKey::Flags]);
578 if (!Section || Section->empty())
579 return Flags;
580
581 for (auto &Val : *Section) {
582 // FIXME: Flags currently apply to all target triples.
583 const auto *Obj = Val.getAsObject();
584 if (!Obj)
585 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
586
587 auto FlagsOrErr =
588 collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
589 TBDFlags TBDFlag =
591 .Case("flat_namespace", TBDFlags::FlatNamespace)
592 .Case("not_app_extension_safe",
594 .Case("sim_support", TBDFlags::SimulatorSupport)
595 .Case("not_for_dyld_shared_cache",
598 Flags |= TBDFlag;
599 });
600
601 if (FlagsOrErr)
602 return std::move(FlagsOrErr);
603
604 return Flags;
605 }
606
607 return Flags;
608}
609
610using IFPtr = std::unique_ptr<InterfaceFile>;
611Expected<IFPtr> parseToInterfaceFile(const Object *File) {
612 auto TargetsOrErr = getTargetsSection(File);
613 if (!TargetsOrErr)
614 return TargetsOrErr.takeError();
615 TargetList Targets = *TargetsOrErr;
616
617 auto NameOrErr = getNameSection(File);
618 if (!NameOrErr)
619 return NameOrErr.takeError();
620 StringRef Name = *NameOrErr;
621
622 auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
623 if (!CurrVersionOrErr)
624 return CurrVersionOrErr.takeError();
625 PackedVersion CurrVersion = *CurrVersionOrErr;
626
627 auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
628 if (!CompVersionOrErr)
629 return CompVersionOrErr.takeError();
630 PackedVersion CompVersion = *CompVersionOrErr;
631
632 auto SwiftABIOrErr = getSwiftVersion(File);
633 if (!SwiftABIOrErr)
634 return SwiftABIOrErr.takeError();
635 uint8_t SwiftABI = *SwiftABIOrErr;
636
637 auto FlagsOrErr = getFlags(File);
638 if (!FlagsOrErr)
639 return FlagsOrErr.takeError();
640 TBDFlags Flags = *FlagsOrErr;
641
642 auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
643 if (!UmbrellasOrErr)
644 return UmbrellasOrErr.takeError();
645 AttrToTargets Umbrellas = *UmbrellasOrErr;
646
647 auto ClientsOrErr =
648 getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
649 if (!ClientsOrErr)
650 return ClientsOrErr.takeError();
651 AttrToTargets Clients = *ClientsOrErr;
652
653 auto RLOrErr =
654 getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
655 if (!RLOrErr)
656 return RLOrErr.takeError();
657 AttrToTargets ReexportLibs = std::move(*RLOrErr);
658
659 auto RPathsOrErr = getLibSection<InOrderAttrToTargets>(
660 File, TBDKey::RPath, TBDKey::Paths, Targets);
661 if (!RPathsOrErr)
662 return RPathsOrErr.takeError();
663 InOrderAttrToTargets RPaths = std::move(*RPathsOrErr);
664
665 auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
666 if (!ExportsOrErr)
667 return ExportsOrErr.takeError();
668 TargetsToSymbols Exports = std::move(*ExportsOrErr);
669
670 auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
671 if (!ReexportsOrErr)
672 return ReexportsOrErr.takeError();
673 TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
674
675 auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
676 if (!UndefinedsOrErr)
677 return UndefinedsOrErr.takeError();
678 TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
679
680 IFPtr F(new InterfaceFile);
681 F->setInstallName(Name);
682 F->setCurrentVersion(CurrVersion);
683 F->setCompatibilityVersion(CompVersion);
684 F->setSwiftABIVersion(SwiftABI);
685 F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
686 F->setApplicationExtensionSafe(
688 F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));
689 F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));
690 for (auto &T : Targets)
691 F->addTarget(T);
692 for (auto &[Lib, Targets] : Clients)
693 for (auto Target : Targets)
694 F->addAllowableClient(Lib, Target);
695 for (auto &[Lib, Targets] : ReexportLibs)
696 for (auto Target : Targets)
697 F->addReexportedLibrary(Lib, Target);
698 for (auto &[Lib, Targets] : Umbrellas)
699 for (auto Target : Targets)
700 F->addParentUmbrella(Target, Lib);
701 for (auto &[Path, Targets] : RPaths)
702 for (auto Target : Targets)
703 F->addRPath(Path, Target);
704 for (auto &[Targets, Symbols] : Exports)
705 for (auto &Sym : Symbols)
706 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
707 for (auto &[Targets, Symbols] : Reexports)
708 for (auto &Sym : Symbols)
709 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
710 for (auto &[Targets, Symbols] : Undefineds)
711 for (auto &Sym : Symbols)
712 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
713
714 return std::move(F);
715}
716
717Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
718 std::vector<IFPtr> IFs;
719 const Array *Files = File->getArray(Keys[TBDKey::Documents]);
720 if (!Files)
721 return std::move(IFs);
722
723 for (auto Lib : *Files) {
724 auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
725 if (!IFOrErr)
726 return IFOrErr.takeError();
727 auto IF = std::move(*IFOrErr);
728 IFs.emplace_back(std::move(IF));
729 }
730 return std::move(IFs);
731}
732
733} // namespace StubParser
734} // namespace
735
738 auto ValOrErr = parse(JSON);
739 if (!ValOrErr)
740 return ValOrErr.takeError();
741
742 auto *Root = ValOrErr->getAsObject();
743 auto VersionOrErr = StubParser::getVersion(Root);
744 if (!VersionOrErr)
745 return VersionOrErr.takeError();
746 FileType Version = *VersionOrErr;
747
748 Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
749 auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
750 if (!IFOrErr)
751 return IFOrErr.takeError();
752 (*IFOrErr)->setFileType(Version);
753 std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
754
755 auto IFsOrErr = StubParser::getInlinedLibs(Root);
756 if (!IFsOrErr)
757 return IFsOrErr.takeError();
758 for (auto &File : *IFsOrErr) {
759 File->setFileType(Version);
760 IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
761 }
762 return std::move(IF);
763}
764
765namespace {
766
767template <typename ContainerT = Array>
768bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
769 if (Contents.empty())
770 return false;
771 Obj[Keys[Key]] = std::move(Contents);
772 return true;
773}
774
775std::string getFormattedStr(const MachO::Target &Targ) {
776 std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
777 ? "maccatalyst"
779 return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
780}
781
782template <typename AggregateT>
783std::vector<std::string> serializeTargets(const AggregateT Targets,
784 const TargetList &ActiveTargets) {
785 std::vector<std::string> TargetsStr;
786 if (Targets.size() == ActiveTargets.size())
787 return TargetsStr;
788
789 for (const MachO::Target &Target : Targets)
790 TargetsStr.emplace_back(getFormattedStr(Target));
791
792 return TargetsStr;
793}
794
795Array serializeTargetInfo(const TargetList &ActiveTargets) {
796 Array Targets;
797 for (const auto Targ : ActiveTargets) {
798 Object TargetInfo;
799 if (!Targ.MinDeployment.empty())
800 TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
801 TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
802 Targets.emplace_back(std::move(TargetInfo));
803 }
804 return Targets;
805}
806
807template <typename ValueT, typename EntryT = ValueT>
808Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
809 if (Value == Default)
810 return {};
811 Array Container;
812 Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
813
814 Container.emplace_back(std::move(ScalarObj));
815 return Container;
816}
817
818using TargetsToValuesMap =
819 std::map<std::vector<std::string>, std::vector<std::string>>;
820
821template <typename AggregateT = TargetsToValuesMap>
822Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
823 Array Container;
824 for (const auto &[Targets, Values] : Entries) {
825 Object Obj;
826 insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
827 Obj[Keys[Key]] = Values;
828 Container.emplace_back(std::move(Obj));
829 }
830 return Container;
831}
832
833/// When there is no significance in order, the common case, serialize all
834/// attributes in a stable order.
835template <typename ValueT = std::string,
836 typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
837Array serializeField(TBDKey Key, const AggregateT &Values,
838 const TargetList &ActiveTargets, bool IsArray = true) {
839 std::map<ValueT, std::set<MachO::Target>> Entries;
840 for (const auto &[Target, Val] : Values)
841 Entries[Val].insert(Target);
842
843 if (!IsArray) {
844 std::map<std::vector<std::string>, std::string> FinalEntries;
845 for (const auto &[Val, Targets] : Entries)
846 FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
847 return serializeAttrToTargets(FinalEntries, Key);
848 }
849
850 TargetsToValuesMap FinalEntries;
851 for (const auto &[Val, Targets] : Entries)
852 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
853 return serializeAttrToTargets(FinalEntries, Key);
854}
855
856Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
857 const TargetList &ActiveTargets) {
858 TargetsToValuesMap FinalEntries;
859 for (const auto &Ref : Values) {
860 TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
861 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
862 Ref.getInstallName());
863 }
864 return serializeAttrToTargets(FinalEntries, Key);
865}
866
867template <
868 typename AggregateT = std::vector<std::pair<MachO::Target, std::string>>>
869Array serializeFieldInInsertionOrder(TBDKey Key, const AggregateT &Values,
870 const TargetList &ActiveTargets) {
872 for (const auto &[Target, Val] : Values)
873 Entries[Val].insert(Target);
874
875 TargetsToValuesMap FinalEntries;
876 for (const auto &[Val, Targets] : Entries)
877 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
878 Val.str());
879 return serializeAttrToTargets(FinalEntries, Key);
880}
881
882struct SymbolFields {
883 struct SymbolTypes {
884 std::vector<StringRef> Weaks;
885 std::vector<StringRef> Globals;
886 std::vector<StringRef> TLV;
887 std::vector<StringRef> ObjCClasses;
888 std::vector<StringRef> IVars;
889 std::vector<StringRef> EHTypes;
890
891 bool empty() const {
892 return Weaks.empty() && Globals.empty() && TLV.empty() &&
893 ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
894 }
895 };
896 SymbolTypes Data;
897 SymbolTypes Text;
898};
899
901 const TargetList &ActiveTargets) {
902 auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
903 const Symbol *Sym) {
904 switch (Sym->getKind()) {
906 Assignment.ObjCClasses.emplace_back(Sym->getName());
907 return;
909 Assignment.EHTypes.emplace_back(Sym->getName());
910 return;
912 Assignment.IVars.emplace_back(Sym->getName());
913 return;
915 if (Sym->isWeakReferenced() || Sym->isWeakDefined())
916 Assignment.Weaks.emplace_back(Sym->getName());
917 else if (Sym->isThreadLocalValue())
918 Assignment.TLV.emplace_back(Sym->getName());
919 else
920 Assignment.Globals.emplace_back(Sym->getName());
921 return;
922 }
923 }
924 };
925
926 std::map<std::vector<std::string>, SymbolFields> Entries;
927 for (const auto *Sym : Symbols) {
928 std::set<MachO::Target> Targets{Sym->targets().begin(),
929 Sym->targets().end()};
930 auto JSONTargets = serializeTargets(Targets, ActiveTargets);
931 if (Sym->isData())
932 AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
933 else if (Sym->isText())
934 AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
935 else
936 llvm_unreachable("unexpected symbol type");
937 }
938
939 auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
940 SymbolFields::SymbolTypes &SymField) {
941 if (SymField.empty())
942 return;
943 llvm::sort(SymField.Globals);
944 llvm::sort(SymField.TLV);
945 llvm::sort(SymField.Weaks);
946 llvm::sort(SymField.ObjCClasses);
947 llvm::sort(SymField.EHTypes);
948 llvm::sort(SymField.IVars);
949 Object Segment;
950 insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
951 insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
952 insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
953 insertNonEmptyValues(Segment, TBDKey::ObjCClass,
954 std::move(SymField.ObjCClasses));
955 insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
956 std::move(SymField.EHTypes));
957 insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
958 insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
959 };
960
961 Array SymbolSection;
962 for (auto &[Targets, Fields] : Entries) {
963 Object AllSyms;
964 insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
965 InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
966 InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
967 SymbolSection.emplace_back(std::move(AllSyms));
968 }
969
970 return SymbolSection;
971}
972
973Array serializeFlags(const InterfaceFile *File) {
974 // TODO: Give all Targets the same flags for now.
975 Array Flags;
976 if (!File->isTwoLevelNamespace())
977 Flags.emplace_back("flat_namespace");
978 if (!File->isApplicationExtensionSafe())
979 Flags.emplace_back("not_app_extension_safe");
980 if (File->hasSimulatorSupport())
981 Flags.emplace_back("sim_support");
982 if (File->isOSLibNotForSharedCache())
983 Flags.emplace_back("not_for_dyld_shared_cache");
984 return serializeScalar(TBDKey::Attributes, std::move(Flags));
985}
986
987Expected<Object> serializeIF(const InterfaceFile *File) {
988 Object Library;
989
990 // Handle required keys.
991 TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
992 if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
993 serializeTargetInfo(ActiveTargets)))
994 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
995
996 Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
997 if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
998 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
999
1000 // Handle optional keys.
1001 Array Flags = serializeFlags(File);
1002 insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
1003
1004 Array CurrentV = serializeScalar<PackedVersion, std::string>(
1005 TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
1006 insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
1007
1008 Array CompatV = serializeScalar<PackedVersion, std::string>(
1009 TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
1010 insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
1011 std::move(CompatV));
1012
1013 Array SwiftABI = serializeScalar<uint8_t, int64_t>(
1014 TBDKey::ABI, File->getSwiftABIVersion(), 0u);
1015 insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
1016
1017 Array RPaths = serializeFieldInInsertionOrder(TBDKey::Paths, File->rpaths(),
1018 ActiveTargets);
1019 insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
1020
1021 Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
1022 ActiveTargets, /*IsArray=*/false);
1023 insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
1024
1025 Array Clients =
1026 serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
1027 insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
1028
1029 Array ReexportLibs =
1030 serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
1031 insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
1032
1033 // Handle symbols.
1034 Array Exports = serializeSymbols(File->exports(), ActiveTargets);
1035 insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
1036
1037 Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
1038 insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
1039
1040 if (!File->isTwoLevelNamespace()) {
1041 Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
1042 insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
1043 }
1044
1045 return std::move(Library);
1046}
1047
1048Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
1049 assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
1050 Object Root;
1051
1052 auto MainLibOrErr = serializeIF(File);
1053 if (!MainLibOrErr)
1054 return MainLibOrErr;
1055 Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
1056 Array Documents;
1057 for (const auto &Doc : File->documents()) {
1058 auto LibOrErr = serializeIF(Doc.get());
1059 if (!LibOrErr)
1060 return LibOrErr;
1061 Documents.emplace_back(std::move(*LibOrErr));
1062 }
1063
1064 Root[Keys[TBDKey::TBDVersion]] = 5;
1065 insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1066 return std::move(Root);
1067}
1068
1069} // namespace
1070
1072 const InterfaceFile &File,
1073 const FileType FileKind,
1074 bool Compact) {
1075 auto TextFile = getJSON(&File, FileKind);
1076 if (!TextFile)
1077 return TextFile.takeError();
1078 if (Compact)
1079 OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1080 else
1081 OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1082 return Error::success();
1083}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
@ Default
This file supports working with JSON data.
#define F(x, y, z)
Definition MD5.cpp:55
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
static uint32_t getFlags(const Symbol *Sym)
Definition TapiFile.cpp:26
@ NotApplicationExtensionSafe
@ SimulatorSupport
@ FlatNamespace
@ None
@ OSLibNotForSharedCache
Base class for user error types.
Definition Error.h:354
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
Defines the interface file.
SymbolSet::const_filtered_symbol_range const_filtered_symbol_range
LLVM_ABI std::pair< bool, bool > parse64(StringRef Str)
PlatformType Platform
Definition Target.h:44
static LLVM_ABI llvm::Expected< Target > create(StringRef Target)
Definition Target.cpp:17
Architecture Arch
Definition Target.h:43
VersionTuple MinDeployment
Definition Target.h:45
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:36
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition MapVector.h:115
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:47
LLVM Value Representation.
Definition Value.h:75
Represents a version number in the form major[.minor[.subminor[.build]]].
LLVM_ABI std::string getAsString() const
Retrieve a string representation of the version number.
bool empty() const
Determine whether this version information is empty (e.g., all version components are zero).
An efficient, type-erasing, non-owning reference to a callable.
An Array is a JSON array, which contains heterogeneous JSON values.
Definition JSON.h:166
void emplace_back(Args &&...A)
Definition JSON.h:564
iterator insert(const_iterator P, const Value &E)
Definition JSON.h:568
An Object is a JSON object, which maps strings to heterogenous JSON values.
Definition JSON.h:98
LLVM_ABI const json::Object * getObject(StringRef K) const
Definition JSON.cpp:67
LLVM_ABI std::optional< llvm::StringRef > getString(StringRef K) const
Definition JSON.cpp:62
LLVM_ABI std::optional< int64_t > getInteger(StringRef K) const
Definition JSON.cpp:57
LLVM_ABI const json::Array * getArray(StringRef K) const
Definition JSON.cpp:77
A "cursor" marking a position within a Value.
Definition JSON.h:666
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ Entry
Definition COFF.h:862
LLVM_ABI std::string getTargetTripleName(const Target &Targ)
Definition Target.cpp:76
FileType
Defines the file type TextAPI files can represent.
Definition FileTypes.h:15
@ TBD_V5
Text-based stub file (.tbd) version 5.0.
Definition FileTypes.h:41
LLVM_ABI StringRef getArchitectureName(Architecture Arch)
Convert an architecture slice to a string.
LLVM_ABI std::string getOSAndEnvironmentName(PlatformType Platform, std::string Version="")
Definition Platform.cpp:90
Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File, const FileType FileKind, bool Compact)
Expected< std::unique_ptr< InterfaceFile > > getInterfaceFileFromJSON(StringRef JSON)
EncodeKind
Mapping of entry types in TextStubs.
Definition Symbol.h:56
SymbolFlags
Symbol flags.
Definition Symbol.h:25
@ ThreadLocalValue
Thread-local value symbol.
Definition Symbol.h:30
@ Rexported
Rexported.
Definition Symbol.h:42
@ WeakReferenced
Weak referenced symbol.
Definition Symbol.h:36
@ WeakDefined
Weak defined symbol.
Definition Symbol.h:33
@ Text
Text Segment.
Definition Symbol.h:48
@ Undefined
Undefined.
Definition Symbol.h:39
@ Data
Data Segment.
Definition Symbol.h:45
SmallVector< Target, 5 > TargetList
Definition Symbol.h:82
LLVM_ABI llvm::Expected< Value > parse(llvm::StringRef JSON)
Parses the provided JSON source, or returns a ParseError.
Definition JSON.cpp:675
bool empty() const
Definition BasicBlock.h:101
iterator end() const
Definition BasicBlock.h:89
LLVM_ABI iterator begin() const
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
FunctionAddr VTableAddr uintptr_t uintptr_t Version
Definition InstrProf.h:302
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1632
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
@ Ref
The access may reference the value stored in memory.
Definition ModRef.h:32
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:189
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1740
LogicalResult success(bool IsSuccess=true)
Utility function to generate a LogicalResult.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1083