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