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