LLVM 18.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 {
78 std::string Name;
80};
81
82using AttrToTargets = std::map<std::string, TargetList>;
83using TargetsToSymbols =
85
86enum TBDKey : size_t {
87 TBDVersion = 0U,
88 MainLibrary,
89 Documents,
90 TargetInfo,
91 Targets,
92 Target,
93 Deployment,
94 Flags,
96 InstallName,
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
124std::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
162static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) {
163 return {"invalid ", Keys[Key], " section"};
164}
165
166static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) {
167 return {"missing ", Keys[Key], " information"};
168}
169
170class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
171public:
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 {
177 }
178
179private:
180 std::string Message;
181};
182
183template <typename JsonT, typename StubT = JsonT>
184Expected<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
201template <typename JsonT, typename StubT = JsonT>
202Expected<StubT> getRequiredValue(
203 TBDKey Key, const Object *Obj,
204 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
205 StubT DefaultValue, std::function<std::optional<StubT>(JsonT)> Validate) {
206 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
207 if (!Val)
208 return DefaultValue;
209
210 std::optional<StubT> Result;
211 Result = Validate(*Val);
212 if (!Result.has_value())
213 return make_error<JSONStubError>(getParseErrorMsg(Key));
214 return Result.value();
215}
216
217Error collectFromArray(TBDKey Key, const Object *Obj,
218 std::function<void(StringRef)> Append,
219 bool IsRequired = false) {
220 const auto *Values = Obj->getArray(Keys[Key]);
221 if (!Values) {
222 if (IsRequired)
223 return make_error<JSONStubError>(getParseErrorMsg(Key));
224 return Error::success();
225 }
226
227 for (const Value &Val : *Values) {
228 auto ValStr = Val.getAsString();
229 if (!ValStr.has_value())
230 return make_error<JSONStubError>(getParseErrorMsg(Key));
231 Append(ValStr.value());
232 }
233
234 return Error::success();
235}
236
237namespace StubParser {
238
239Expected<FileType> getVersion(const Object *File) {
240 auto VersionOrErr = getRequiredValue<int64_t, FileType>(
241 TBDKey::TBDVersion, File, &Object::getInteger,
242 [](int64_t Val) -> std::optional<FileType> {
243 unsigned Result = Val;
244 if (Result != 5)
245 return std::nullopt;
246 return FileType::TBD_V5;
247 });
248
249 if (!VersionOrErr)
250 return VersionOrErr.takeError();
251 return *VersionOrErr;
252}
253
254Expected<TargetList> getTargets(const Object *Section) {
255 const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
256 if (!Targets)
257 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
258
259 TargetList IFTargets;
260 for (const Value &JSONTarget : *Targets) {
261 auto TargetStr = JSONTarget.getAsString();
262 if (!TargetStr.has_value())
263 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
264 auto TargetOrErr = Target::create(TargetStr.value());
265 if (!TargetOrErr)
266 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
267 IFTargets.push_back(*TargetOrErr);
268 }
269 return std::move(IFTargets);
270}
271
272Expected<TargetList> getTargetsSection(const Object *Section) {
273 const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
274 if (!Targets)
275 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
276
277 TargetList IFTargets;
278 for (const Value &JSONTarget : *Targets) {
279 const auto *Obj = JSONTarget.getAsObject();
280 if (!Obj)
281 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
282 auto TargetStr =
283 getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
284 if (!TargetStr)
285 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
286 auto TargetOrErr = Target::create(*TargetStr);
287 if (!TargetOrErr)
288 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
289
290 auto VersionStr = Obj->getString(Keys[TBDKey::Deployment]);
291 VersionTuple Version;
292 if (VersionStr && Version.tryParse(*VersionStr))
293 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
294 TargetOrErr->MinDeployment = Version;
295
296 // Convert to LLVM::Triple to accurately compute minOS + platform + arch
297 // pairing.
298 IFTargets.push_back(
300 }
301 return std::move(IFTargets);
302}
303
304Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result,
305 SymbolFlags SectionFlag) {
306 auto Err = collectFromArray(
307 TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
308 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), SectionFlag};
309 Result.back().second.emplace_back(Sym);
310 });
311 if (Err)
312 return Err;
313
314 Err = collectFromArray(
315 TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
316 JSONSymbol Sym = {SymbolKind::ObjectiveCClass, Name.str(), SectionFlag};
317 Result.back().second.emplace_back(Sym);
318 });
319 if (Err)
320 return Err;
321
322 Err = collectFromArray(TBDKey::ObjCEHType, Segment,
323 [&Result, &SectionFlag](StringRef Name) {
324 JSONSymbol Sym = {SymbolKind::ObjectiveCClassEHType,
325 Name.str(), SectionFlag};
326 Result.back().second.emplace_back(Sym);
327 });
328 if (Err)
329 return Err;
330
331 Err = collectFromArray(
332 TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
333 JSONSymbol Sym = {SymbolKind::ObjectiveCInstanceVariable, Name.str(),
334 SectionFlag};
335 Result.back().second.emplace_back(Sym);
336 });
337 if (Err)
338 return Err;
339
340 SymbolFlags WeakFlag =
341 SectionFlag |
342 (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
343 ? SymbolFlags::WeakReferenced
344 : SymbolFlags::WeakDefined);
345 Err = collectFromArray(
346 TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
347 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), WeakFlag};
348 Result.back().second.emplace_back(Sym);
349 });
350 if (Err)
351 return Err;
352
353 Err = collectFromArray(
354 TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
355 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(),
356 SymbolFlags::ThreadLocalValue | SectionFlag};
357 Result.back().second.emplace_back(Sym);
358 });
359 if (Err)
360 return Err;
361
362 return Error::success();
363}
364
365Expected<StringRef> getNameSection(const Object *File) {
366 const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
367 if (!Section)
368 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
369
370 assert(!Section->empty() && "unexpected missing install name");
371 // TODO: Just take first for now.
372 const auto *Obj = Section->front().getAsObject();
373 if (!Obj)
374 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
375
376 return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
377}
378
379Expected<TargetsToSymbols> getSymbolSection(const Object *File, TBDKey Key,
380 TargetList &Targets) {
381
382 const Array *Section = File->getArray(Keys[Key]);
383 if (!Section)
384 return TargetsToSymbols();
385
386 SymbolFlags SectionFlag;
387 switch (Key) {
388 case TBDKey::Reexports:
389 SectionFlag = SymbolFlags::Rexported;
390 break;
391 case TBDKey::Undefineds:
392 SectionFlag = SymbolFlags::Undefined;
393 break;
394 default:
395 SectionFlag = SymbolFlags::None;
396 break;
397 };
398
399 TargetsToSymbols Result;
400 TargetList MappedTargets;
401 for (auto Val : *Section) {
402 auto *Obj = Val.getAsObject();
403 if (!Obj)
404 continue;
405
406 auto TargetsOrErr = getTargets(Obj);
407 if (!TargetsOrErr) {
408 MappedTargets = Targets;
409 consumeError(TargetsOrErr.takeError());
410 } else {
411 MappedTargets = *TargetsOrErr;
412 }
413 Result.emplace_back(
414 std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
415
416 auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
417 auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
418 // There should be at least one valid section.
419 if (!DataSection && !TextSection)
420 return make_error<JSONStubError>(getParseErrorMsg(Key));
421
422 if (DataSection) {
423 auto Err = collectSymbolsFromSegment(DataSection, Result,
424 SectionFlag | SymbolFlags::Data);
425 if (Err)
426 return std::move(Err);
427 }
428 if (TextSection) {
429 auto Err = collectSymbolsFromSegment(TextSection, Result,
430 SectionFlag | SymbolFlags::Text);
431 if (Err)
432 return std::move(Err);
433 }
434 }
435
436 return std::move(Result);
437}
438
439Expected<AttrToTargets> getLibSection(const Object *File, TBDKey Key,
440 TBDKey SubKey,
441 const TargetList &Targets) {
442 auto *Section = File->getArray(Keys[Key]);
443 if (!Section)
444 return AttrToTargets();
445
446 AttrToTargets Result;
447 TargetList MappedTargets;
448 for (auto Val : *Section) {
449 auto *Obj = Val.getAsObject();
450 if (!Obj)
451 continue;
452
453 auto TargetsOrErr = getTargets(Obj);
454 if (!TargetsOrErr) {
455 MappedTargets = Targets;
456 consumeError(TargetsOrErr.takeError());
457 } else {
458 MappedTargets = *TargetsOrErr;
459 }
460 auto Err =
461 collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
462 Result[Key.str()] = MappedTargets;
463 });
464 if (Err)
465 return std::move(Err);
466 }
467
468 return std::move(Result);
469}
470
471Expected<AttrToTargets> getUmbrellaSection(const Object *File,
472 const TargetList &Targets) {
473 const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
474 if (!Umbrella)
475 return AttrToTargets();
476
477 AttrToTargets Result;
478 TargetList MappedTargets;
479 for (auto Val : *Umbrella) {
480 auto *Obj = Val.getAsObject();
481 if (!Obj)
482 return make_error<JSONStubError>(
483 getParseErrorMsg(TBDKey::ParentUmbrella));
484
485 // Get Targets section.
486 auto TargetsOrErr = getTargets(Obj);
487 if (!TargetsOrErr) {
488 MappedTargets = Targets;
489 consumeError(TargetsOrErr.takeError());
490 } else {
491 MappedTargets = *TargetsOrErr;
492 }
493
494 auto UmbrellaOrErr =
495 getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
496 if (!UmbrellaOrErr)
497 return UmbrellaOrErr.takeError();
498 Result[UmbrellaOrErr->str()] = Targets;
499 }
500 return std::move(Result);
501}
502
503Expected<uint8_t> getSwiftVersion(const Object *File) {
504 const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
505 if (!Versions)
506 return 0;
507
508 for (const auto &Val : *Versions) {
509 const auto *Obj = Val.getAsObject();
510 if (!Obj)
511 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
512
513 // TODO: Take first for now.
514 return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
516 }
517
518 return 0;
519}
520
521Expected<PackedVersion> getPackedVersion(const Object *File, TBDKey Key) {
522 const Array *Versions = File->getArray(Keys[Key]);
523 if (!Versions)
524 return PackedVersion(1, 0, 0);
525
526 for (const auto &Val : *Versions) {
527 const auto *Obj = Val.getAsObject();
528 if (!Obj)
529 return make_error<JSONStubError>(getParseErrorMsg(Key));
530
531 auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
532 PackedVersion PV;
533 auto [success, truncated] = PV.parse64(Version);
534 if (!success || truncated)
535 return std::nullopt;
536 return PV;
537 };
538 // TODO: Take first for now.
539 return getRequiredValue<StringRef, PackedVersion>(
540 TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
541 ValidatePV);
542 }
543
544 return PackedVersion(1, 0, 0);
545}
546
548 TBDFlags Flags = TBDFlags::None;
549 const Array *Section = File->getArray(Keys[TBDKey::Flags]);
550 if (!Section || Section->empty())
551 return Flags;
552
553 for (auto &Val : *Section) {
554 // FIXME: Flags currently apply to all target triples.
555 const auto *Obj = Val.getAsObject();
556 if (!Obj)
557 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
558
559 auto FlagsOrErr =
560 collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
561 TBDFlags TBDFlag =
563 .Case("flat_namespace", TBDFlags::FlatNamespace)
564 .Case("not_app_extension_safe",
565 TBDFlags::NotApplicationExtensionSafe)
566 .Case("sim_support", TBDFlags::SimulatorSupport)
567 .Case("not_for_dyld_shared_cache",
568 TBDFlags::OSLibNotForSharedCache)
569 .Default(TBDFlags::None);
570 Flags |= TBDFlag;
571 });
572
573 if (FlagsOrErr)
574 return std::move(FlagsOrErr);
575
576 return Flags;
577 }
578
579 return Flags;
580}
581
582using IFPtr = std::unique_ptr<InterfaceFile>;
583Expected<IFPtr> parseToInterfaceFile(const Object *File) {
584 auto TargetsOrErr = getTargetsSection(File);
585 if (!TargetsOrErr)
586 return TargetsOrErr.takeError();
587 TargetList Targets = *TargetsOrErr;
588
589 auto NameOrErr = getNameSection(File);
590 if (!NameOrErr)
591 return NameOrErr.takeError();
592 StringRef Name = *NameOrErr;
593
594 auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
595 if (!CurrVersionOrErr)
596 return CurrVersionOrErr.takeError();
597 PackedVersion CurrVersion = *CurrVersionOrErr;
598
599 auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
600 if (!CompVersionOrErr)
601 return CompVersionOrErr.takeError();
602 PackedVersion CompVersion = *CompVersionOrErr;
603
604 auto SwiftABIOrErr = getSwiftVersion(File);
605 if (!SwiftABIOrErr)
606 return SwiftABIOrErr.takeError();
607 uint8_t SwiftABI = *SwiftABIOrErr;
608
609 auto FlagsOrErr = getFlags(File);
610 if (!FlagsOrErr)
611 return FlagsOrErr.takeError();
612 TBDFlags Flags = *FlagsOrErr;
613
614 auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
615 if (!UmbrellasOrErr)
616 return UmbrellasOrErr.takeError();
617 AttrToTargets Umbrellas = *UmbrellasOrErr;
618
619 auto ClientsOrErr =
620 getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
621 if (!ClientsOrErr)
622 return ClientsOrErr.takeError();
623 AttrToTargets Clients = *ClientsOrErr;
624
625 auto RLOrErr =
626 getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
627 if (!RLOrErr)
628 return RLOrErr.takeError();
629 AttrToTargets ReexportLibs = std::move(*RLOrErr);
630
631 auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
632 if (!RPathsOrErr)
633 return RPathsOrErr.takeError();
634 AttrToTargets RPaths = std::move(*RPathsOrErr);
635
636 auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
637 if (!ExportsOrErr)
638 return ExportsOrErr.takeError();
639 TargetsToSymbols Exports = std::move(*ExportsOrErr);
640
641 auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
642 if (!ReexportsOrErr)
643 return ReexportsOrErr.takeError();
644 TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
645
646 auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
647 if (!UndefinedsOrErr)
648 return UndefinedsOrErr.takeError();
649 TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
650
651 IFPtr F(new InterfaceFile);
652 F->setInstallName(Name);
653 F->setCurrentVersion(CurrVersion);
654 F->setCompatibilityVersion(CompVersion);
655 F->setSwiftABIVersion(SwiftABI);
656 F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
657 F->setApplicationExtensionSafe(
658 !(Flags & TBDFlags::NotApplicationExtensionSafe));
659 F->setSimulatorSupport((Flags & TBDFlags::SimulatorSupport));
660 F->setOSLibNotForSharedCache((Flags & TBDFlags::OSLibNotForSharedCache));
661 for (auto &T : Targets)
662 F->addTarget(T);
663 for (auto &[Lib, Targets] : Clients)
664 for (auto Target : Targets)
665 F->addAllowableClient(Lib, Target);
666 for (auto &[Lib, Targets] : ReexportLibs)
667 for (auto Target : Targets)
668 F->addReexportedLibrary(Lib, Target);
669 for (auto &[Lib, Targets] : Umbrellas)
670 for (auto Target : Targets)
671 F->addParentUmbrella(Target, Lib);
672 for (auto &[Path, Targets] : RPaths)
673 for (auto Target : Targets)
674 F->addRPath(Target, Path);
675 for (auto &[Targets, Symbols] : Exports)
676 for (auto &Sym : Symbols)
677 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
678 for (auto &[Targets, Symbols] : Reexports)
679 for (auto &Sym : Symbols)
680 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
681 for (auto &[Targets, Symbols] : Undefineds)
682 for (auto &Sym : Symbols)
683 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
684
685 return std::move(F);
686}
687
688Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) {
689 std::vector<IFPtr> IFs;
690 const Array *Files = File->getArray(Keys[TBDKey::Documents]);
691 if (!Files)
692 return std::move(IFs);
693
694 for (auto Lib : *Files) {
695 auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
696 if (!IFOrErr)
697 return IFOrErr.takeError();
698 auto IF = std::move(*IFOrErr);
699 IFs.emplace_back(std::move(IF));
700 }
701 return std::move(IFs);
702}
703
704} // namespace StubParser
705} // namespace
706
709 auto ValOrErr = parse(JSON);
710 if (!ValOrErr)
711 return ValOrErr.takeError();
712
713 auto *Root = ValOrErr->getAsObject();
714 auto VersionOrErr = StubParser::getVersion(Root);
715 if (!VersionOrErr)
716 return VersionOrErr.takeError();
717 FileType Version = *VersionOrErr;
718
719 Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
720 auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
721 if (!IFOrErr)
722 return IFOrErr.takeError();
723 (*IFOrErr)->setFileType(Version);
724 std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
725
726 auto IFsOrErr = StubParser::getInlinedLibs(Root);
727 if (!IFsOrErr)
728 return IFsOrErr.takeError();
729 for (auto &File : *IFsOrErr) {
730 File->setFileType(Version);
731 IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
732 }
733 return std::move(IF);
734}
735
736namespace {
737
738template <typename ContainerT = Array>
739bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
740 if (Contents.empty())
741 return false;
742 Obj[Keys[Key]] = std::move(Contents);
743 return true;
744}
745
746std::string getFormattedStr(const MachO::Target &Targ) {
747 std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
748 ? "maccatalyst"
750 return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
751}
752
753template <typename AggregateT>
754std::vector<std::string> serializeTargets(const AggregateT Targets,
755 const TargetList &ActiveTargets) {
756 std::vector<std::string> TargetsStr;
757 if (Targets.size() == ActiveTargets.size())
758 return TargetsStr;
759
760 for (const MachO::Target &Target : Targets)
761 TargetsStr.emplace_back(getFormattedStr(Target));
762
763 return TargetsStr;
764}
765
766Array serializeTargetInfo(const TargetList &ActiveTargets) {
767 Array Targets;
768 for (const auto Targ : ActiveTargets) {
769 Object TargetInfo;
770 if (!Targ.MinDeployment.empty())
771 TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString();
772 TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
773 Targets.emplace_back(std::move(TargetInfo));
774 }
775 return Targets;
776}
777
778template <typename ValueT, typename EntryT = ValueT>
779Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
780 if (Value == Default)
781 return {};
782 Array Container;
783 Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
784
785 Container.emplace_back(std::move(ScalarObj));
786 return Container;
787}
788
789using TargetsToValuesMap =
790 std::map<std::vector<std::string>, std::vector<std::string>>;
791
792template <typename AggregateT = TargetsToValuesMap>
793Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
794 Array Container;
795 for (const auto &[Targets, Values] : Entries) {
796 Object Obj;
797 insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
798 Obj[Keys[Key]] = Values;
799 Container.emplace_back(std::move(Obj));
800 }
801 return Container;
802}
803
804template <typename ValueT = std::string,
805 typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
806Array serializeField(TBDKey Key, const AggregateT &Values,
807 const TargetList &ActiveTargets, bool IsArray = true) {
808 std::map<ValueT, std::set<MachO::Target>> Entries;
809 for (const auto &[Target, Val] : Values)
810 Entries[Val].insert(Target);
811
812 if (!IsArray) {
813 std::map<std::vector<std::string>, std::string> FinalEntries;
814 for (const auto &[Val, Targets] : Entries)
815 FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
816 return serializeAttrToTargets(FinalEntries, Key);
817 }
818
819 TargetsToValuesMap FinalEntries;
820 for (const auto &[Val, Targets] : Entries)
821 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
822 return serializeAttrToTargets(FinalEntries, Key);
823}
824
825Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
826 const TargetList &ActiveTargets) {
827 TargetsToValuesMap FinalEntries;
828 for (const auto &Ref : Values) {
829 TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
830 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
831 Ref.getInstallName());
832 }
833 return serializeAttrToTargets(FinalEntries, Key);
834}
835
836struct SymbolFields {
837 struct SymbolTypes {
838 std::vector<StringRef> Weaks;
839 std::vector<StringRef> Globals;
840 std::vector<StringRef> TLV;
841 std::vector<StringRef> ObjCClasses;
842 std::vector<StringRef> IVars;
843 std::vector<StringRef> EHTypes;
844
845 bool empty() const {
846 return Weaks.empty() && Globals.empty() && TLV.empty() &&
847 ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
848 }
849 };
850 SymbolTypes Data;
851 SymbolTypes Text;
852};
853
855 const TargetList &ActiveTargets) {
856 auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
857 const Symbol *Sym) {
858 switch (Sym->getKind()) {
859 case SymbolKind::ObjectiveCClass:
860 Assignment.ObjCClasses.emplace_back(Sym->getName());
861 return;
862 case SymbolKind::ObjectiveCClassEHType:
863 Assignment.EHTypes.emplace_back(Sym->getName());
864 return;
865 case SymbolKind::ObjectiveCInstanceVariable:
866 Assignment.IVars.emplace_back(Sym->getName());
867 return;
868 case SymbolKind::GlobalSymbol: {
870 Assignment.Weaks.emplace_back(Sym->getName());
871 else if (Sym->isThreadLocalValue())
872 Assignment.TLV.emplace_back(Sym->getName());
873 else
874 Assignment.Globals.emplace_back(Sym->getName());
875 return;
876 }
877 }
878 };
879
880 std::map<std::vector<std::string>, SymbolFields> Entries;
881 for (const auto *Sym : Symbols) {
882 std::set<MachO::Target> Targets{Sym->targets().begin(),
883 Sym->targets().end()};
884 auto JSONTargets = serializeTargets(Targets, ActiveTargets);
885 if (Sym->isData())
886 AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
887 else if (Sym->isText())
888 AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
889 else
890 llvm_unreachable("unexpected symbol type");
891 }
892
893 auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
894 SymbolFields::SymbolTypes &SymField) {
895 if (SymField.empty())
896 return;
897 Object Segment;
898 insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
899 insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
900 insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
901 insertNonEmptyValues(Segment, TBDKey::ObjCClass,
902 std::move(SymField.ObjCClasses));
903 insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
904 std::move(SymField.EHTypes));
905 insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
906 insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
907 };
908
909 Array SymbolSection;
910 for (auto &[Targets, Fields] : Entries) {
911 Object AllSyms;
912 insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
913 InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
914 InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
915 SymbolSection.emplace_back(std::move(AllSyms));
916 }
917
918 return SymbolSection;
919}
920
921Array serializeFlags(const InterfaceFile *File) {
922 // TODO: Give all Targets the same flags for now.
923 Array Flags;
924 if (!File->isTwoLevelNamespace())
925 Flags.emplace_back("flat_namespace");
926 if (!File->isApplicationExtensionSafe())
927 Flags.emplace_back("not_app_extension_safe");
928 if (File->hasSimulatorSupport())
929 Flags.emplace_back("sim_support");
930 if (File->isOSLibNotForSharedCache())
931 Flags.emplace_back("not_for_dyld_shared_cache");
932 return serializeScalar(TBDKey::Attributes, std::move(Flags));
933}
934
935Expected<Object> serializeIF(const InterfaceFile *File) {
936 Object Library;
937
938 // Handle required keys.
939 TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
940 if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
941 serializeTargetInfo(ActiveTargets)))
942 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
943
944 Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
945 if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
946 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
947
948 // Handle optional keys.
949 Array Flags = serializeFlags(File);
950 insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
951
952 Array CurrentV = serializeScalar<PackedVersion, std::string>(
953 TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
954 insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
955
956 Array CompatV = serializeScalar<PackedVersion, std::string>(
957 TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
958 insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
959 std::move(CompatV));
960
961 Array SwiftABI = serializeScalar<uint8_t, int64_t>(
962 TBDKey::ABI, File->getSwiftABIVersion(), 0u);
963 insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
964
965 Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
966 insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
967
968 Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
969 ActiveTargets, /*IsArray=*/false);
970 insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
971
972 Array Clients =
973 serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
974 insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
975
976 Array ReexportLibs =
977 serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
978 insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
979
980 // Handle symbols.
981 Array Exports = serializeSymbols(File->exports(), ActiveTargets);
982 insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
983
984 Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
985 insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
986
987 if (!File->isTwoLevelNamespace()) {
988 Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
989 insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
990 }
991
992 return std::move(Library);
993}
994
995Expected<Object> getJSON(const InterfaceFile *File, const FileType FileKind) {
996 assert(FileKind == FileType::TBD_V5 && "unexpected json file format version");
997 Object Root;
998
999 auto MainLibOrErr = serializeIF(File);
1000 if (!MainLibOrErr)
1001 return MainLibOrErr;
1002 Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
1003 Array Documents;
1004 for (const auto &Doc : File->documents()) {
1005 auto LibOrErr = serializeIF(Doc.get());
1006 if (!LibOrErr)
1007 return LibOrErr;
1008 Documents.emplace_back(std::move(*LibOrErr));
1009 }
1010
1011 Root[Keys[TBDKey::TBDVersion]] = 5;
1012 insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1013 return std::move(Root);
1014}
1015
1016} // namespace
1017
1019 const InterfaceFile &File,
1020 const FileType FileKind,
1021 bool Compact) {
1022 auto TextFile = getJSON(&File, FileKind);
1023 if (!TextFile)
1024 return TextFile.takeError();
1025 if (Compact)
1026 OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1027 else
1028 OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1029 return Error::success();
1030}
AMDGPU Kernel Attributes
@ Default
Definition: DwarfDebug.cpp:87
std::string Name
Symbol * Sym
Definition: ELF_riscv.cpp:477
This file supports working with JSON data.
#define F(x, y, z)
Definition: MD5.cpp:55
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
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:27
TBDFlags
virtual std::error_code convertToErrorCode() const =0
Convert this error to a std::error_code.
virtual void log(raw_ostream &OS) const =0
Print an error message to an output stream.
Base class for user error types.
Definition: Error.h:352
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
Error takeError()
Take ownership of the stored error.
Definition: Error.h:601
Defines the interface file.
std::pair< bool, bool > parse64(StringRef Str)
bool isData() const
Definition: Symbol.h:116
bool isWeakDefined() const
Definition: Symbol.h:95
const_target_range targets() const
Definition: Symbol.h:134
bool isThreadLocalValue() const
Definition: Symbol.h:103
SymbolKind getKind() const
Definition: Symbol.h:88
StringRef getName() const
Definition: Symbol.h:89
bool isText() const
Definition: Symbol.h:120
bool isWeakReferenced() const
Definition: Symbol.h:99
PlatformType Platform
Definition: Target.h:43
static llvm::Expected< Target > create(StringRef Target)
Definition: Target.cpp:17
Architecture Arch
Definition: Target.h:42
VersionTuple MinDeployment
Definition: Target.h:44
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
size_t size() const
Definition: SmallVector.h:91
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
R Default(T Value)
Definition: StringSwitch.h:182
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
LLVM Value Representation.
Definition: Value.h:74
Represents a version number in the form major[.minor[.subminor[.build]]].
Definition: VersionTuple.h:29
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).
Definition: VersionTuple.h:66
A range adaptor for a pair of iterators.
IteratorT end() const
IteratorT begin() const
An Array is a JSON array, which contains heterogeneous JSON values.
Definition: JSON.h:163
void emplace_back(Args &&...A)
Definition: JSON.h:541
An Object is a JSON object, which maps strings to heterogenous JSON values.
Definition: JSON.h:97
const json::Object * getObject(StringRef K) const
Definition: JSON.cpp:67
std::optional< llvm::StringRef > getString(StringRef K) const
Definition: JSON.cpp:62
std::optional< int64_t > getInteger(StringRef K) const
Definition: JSON.cpp:57
const json::Array * getArray(StringRef K) const
Definition: JSON.cpp:77
A "cursor" marking a position within a Value.
Definition: JSON.h:640
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Key
PAL metadata keys.
const uint64_t Version
Definition: InstrProf.h:1027
std::string getTargetTripleName(const Target &Targ)
Definition: Target.cpp:76
FileType
Defines the file type this file represents.
Definition: InterfaceFile.h:53
StringRef getArchitectureName(Architecture Arch)
Convert an architecture slice to a string.
std::string getOSAndEnvironmentName(PlatformType Platform, std::string Version="")
Definition: Platform.cpp:84
Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File, const FileType FileKind, bool Compact)
Expected< std::unique_ptr< InterfaceFile > > getInterfaceFileFromJSON(StringRef JSON)
Definition: TextStubV5.cpp:708
SymbolFlags
Symbol flags.
Definition: Symbol.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:90
@ Ref
The access may reference the value stored in memory.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
Definition: regcomp.c:192