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 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)> 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 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 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 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 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 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 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 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 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 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 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 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 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>; 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 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>> 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> 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 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> 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 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> 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> 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>>> 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 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 846 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 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 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 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 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 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