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