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 SymbolKind Kind; 78 std::string Name; 79 SymbolFlags Flags; 80 }; 81 82 using AttrToTargets = std::map<std::string, TargetList>; 83 using TargetsToSymbols = 84 SmallVector<std::pair<TargetList, std::vector<JSONSymbol>>>; 85 86 enum TBDKey : size_t { 87 TBDVersion = 0U, 88 MainLibrary, 89 Documents, 90 TargetInfo, 91 Targets, 92 Target, 93 Deployment, 94 Flags, 95 Attributes, 96 InstallName, 97 CurrentVersion, 98 CompatibilityVersion, 99 Version, 100 SwiftABI, 101 ABI, 102 ParentUmbrella, 103 Umbrella, 104 AllowableClients, 105 Clients, 106 ReexportLibs, 107 Names, 108 Name, 109 Exports, 110 Reexports, 111 Undefineds, 112 Data, 113 Text, 114 Weak, 115 ThreadLocal, 116 Globals, 117 ObjCClass, 118 ObjCEHType, 119 ObjCIvar, 120 RPath, 121 Paths, 122 }; 123 124 std::array<StringRef, 64> Keys = { 125 "tapi_tbd_version", 126 "main_library", 127 "libraries", 128 "target_info", 129 "targets", 130 "target", 131 "min_deployment", 132 "flags", 133 "attributes", 134 "install_names", 135 "current_versions", 136 "compatibility_versions", 137 "version", 138 "swift_abi", 139 "abi", 140 "parent_umbrellas", 141 "umbrella", 142 "allowable_clients", 143 "clients", 144 "reexported_libraries", 145 "names", 146 "name", 147 "exported_symbols", 148 "reexported_symbols", 149 "undefined_symbols", 150 "data", 151 "text", 152 "weak", 153 "thread_local", 154 "global", 155 "objc_class", 156 "objc_eh_type", 157 "objc_ivar", 158 "rpaths", 159 "paths", 160 }; 161 162 static llvm::SmallString<128> getParseErrorMsg(TBDKey Key) { 163 return {"invalid ", Keys[Key], " section"}; 164 } 165 166 static llvm::SmallString<128> getSerializeErrorMsg(TBDKey Key) { 167 return {"missing ", Keys[Key], " information"}; 168 } 169 170 class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> { 171 public: 172 JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {} 173 174 void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; } 175 std::error_code convertToErrorCode() const override { 176 return llvm::inconvertibleErrorCode(); 177 } 178 179 private: 180 std::string Message; 181 }; 182 183 template <typename JsonT, typename StubT = JsonT> 184 Expected<StubT> getRequiredValue( 185 TBDKey Key, const Object *Obj, 186 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue, 187 std::function<std::optional<StubT>(JsonT)> Validate = nullptr) { 188 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]); 189 if (!Val) 190 return make_error<JSONStubError>(getParseErrorMsg(Key)); 191 192 if (Validate == nullptr) 193 return static_cast<StubT>(*Val); 194 195 std::optional<StubT> Result = Validate(*Val); 196 if (!Result.has_value()) 197 return make_error<JSONStubError>(getParseErrorMsg(Key)); 198 return Result.value(); 199 } 200 201 template <typename JsonT, typename StubT = JsonT> 202 Expected<StubT> getRequiredValue( 203 TBDKey Key, const Object *Obj, 204 std::function<std::optional<JsonT>(const Object *, StringRef)> 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 217 Error 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 237 namespace StubParser { 238 239 Expected<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 254 Expected<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 272 Expected<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( 299 MachO::Target(Triple(getTargetTripleName(*TargetOrErr)))); 300 } 301 return std::move(IFTargets); 302 } 303 304 Error 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 365 Expected<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 379 Expected<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 439 Expected<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 471 Expected<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 503 Expected<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, 515 &Object::getInteger); 516 } 517 518 return 0; 519 } 520 521 Expected<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 547 Expected<TBDFlags> getFlags(const Object *File) { 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 = 562 StringSwitch<TBDFlags>(Flag) 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 582 using IFPtr = std::unique_ptr<InterfaceFile>; 583 Expected<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 688 Expected<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 707 Expected<std::unique_ptr<InterfaceFile>> 708 MachO::getInterfaceFileFromJSON(StringRef JSON) { 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 736 namespace { 737 738 template <typename ContainerT = Array> 739 bool 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 746 std::string getFormattedStr(const MachO::Target &Targ) { 747 std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST 748 ? "maccatalyst" 749 : getOSAndEnvironmentName(Targ.Platform); 750 return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str(); 751 } 752 753 template <typename AggregateT> 754 std::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 766 Array 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 778 template <typename ValueT, typename EntryT = ValueT> 779 Array 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 789 using TargetsToValuesMap = 790 std::map<std::vector<std::string>, std::vector<std::string>>; 791 792 template <typename AggregateT = TargetsToValuesMap> 793 Array 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 804 template <typename ValueT = std::string, 805 typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>> 806 Array 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 825 Array 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 836 struct 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 854 Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols, 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: { 869 if (Sym->isWeakReferenced() || Sym->isWeakDefined()) 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 921 Array 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 935 Expected<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 995 Expected<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 1018 Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS, 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 } 1031