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" # Required: minimum OS deployment version 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 VersionStr = getRequiredValue<StringRef>(TBDKey::Deployment, Obj, 287 &Object::getString); 288 if (!VersionStr) 289 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment)); 290 VersionTuple Version; 291 if (Version.tryParse(*VersionStr)) 292 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment)); 293 auto TargetOrErr = Target::create(*TargetStr); 294 if (!TargetOrErr) 295 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target)); 296 TargetOrErr->MinDeployment = Version; 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 = {SymbolKind::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 = {SymbolKind::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 = {SymbolKind::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 = {SymbolKind::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 = {SymbolKind::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 = {SymbolKind::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) 552 return Flags; 553 554 for (auto &Val : *Section) { 555 // TODO: Just take first for now. 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 .Default(TBDFlags::None); 568 Flags |= TBDFlag; 569 }); 570 571 if (FlagsOrErr) 572 return std::move(FlagsOrErr); 573 574 return Flags; 575 } 576 577 return Flags; 578 } 579 580 using IFPtr = std::unique_ptr<InterfaceFile>; 581 Expected<IFPtr> parseToInterfaceFile(const Object *File) { 582 auto TargetsOrErr = getTargetsSection(File); 583 if (!TargetsOrErr) 584 return TargetsOrErr.takeError(); 585 TargetList Targets = *TargetsOrErr; 586 587 auto NameOrErr = getNameSection(File); 588 if (!NameOrErr) 589 return NameOrErr.takeError(); 590 StringRef Name = *NameOrErr; 591 592 auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion); 593 if (!CurrVersionOrErr) 594 return CurrVersionOrErr.takeError(); 595 PackedVersion CurrVersion = *CurrVersionOrErr; 596 597 auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion); 598 if (!CompVersionOrErr) 599 return CompVersionOrErr.takeError(); 600 PackedVersion CompVersion = *CompVersionOrErr; 601 602 auto SwiftABIOrErr = getSwiftVersion(File); 603 if (!SwiftABIOrErr) 604 return SwiftABIOrErr.takeError(); 605 uint8_t SwiftABI = *SwiftABIOrErr; 606 607 auto FlagsOrErr = getFlags(File); 608 if (!FlagsOrErr) 609 return FlagsOrErr.takeError(); 610 TBDFlags Flags = *FlagsOrErr; 611 612 auto UmbrellasOrErr = getUmbrellaSection(File, Targets); 613 if (!UmbrellasOrErr) 614 return UmbrellasOrErr.takeError(); 615 AttrToTargets Umbrellas = *UmbrellasOrErr; 616 617 auto ClientsOrErr = 618 getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets); 619 if (!ClientsOrErr) 620 return ClientsOrErr.takeError(); 621 AttrToTargets Clients = *ClientsOrErr; 622 623 auto RLOrErr = 624 getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets); 625 if (!RLOrErr) 626 return RLOrErr.takeError(); 627 AttrToTargets ReexportLibs = std::move(*RLOrErr); 628 629 auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets); 630 if (!RPathsOrErr) 631 return RPathsOrErr.takeError(); 632 AttrToTargets RPaths = std::move(*RPathsOrErr); 633 634 auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets); 635 if (!ExportsOrErr) 636 return ExportsOrErr.takeError(); 637 TargetsToSymbols Exports = std::move(*ExportsOrErr); 638 639 auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets); 640 if (!ReexportsOrErr) 641 return ReexportsOrErr.takeError(); 642 TargetsToSymbols Reexports = std::move(*ReexportsOrErr); 643 644 auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets); 645 if (!UndefinedsOrErr) 646 return UndefinedsOrErr.takeError(); 647 TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr); 648 649 IFPtr F(new InterfaceFile); 650 F->setInstallName(Name); 651 F->setCurrentVersion(CurrVersion); 652 F->setCompatibilityVersion(CompVersion); 653 F->setSwiftABIVersion(SwiftABI); 654 F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 655 F->setApplicationExtensionSafe( 656 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 657 for (auto &T : Targets) 658 F->addTarget(T); 659 for (auto &[Lib, Targets] : Clients) 660 for (auto Target : Targets) 661 F->addAllowableClient(Lib, Target); 662 for (auto &[Lib, Targets] : ReexportLibs) 663 for (auto Target : Targets) 664 F->addReexportedLibrary(Lib, Target); 665 for (auto &[Lib, Targets] : Umbrellas) 666 for (auto Target : Targets) 667 F->addParentUmbrella(Target, Lib); 668 for (auto &[Path, Targets] : RPaths) 669 for (auto Target : Targets) 670 F->addRPath(Target, Path); 671 for (auto &[Targets, Symbols] : Exports) 672 for (auto &Sym : Symbols) 673 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags); 674 for (auto &[Targets, Symbols] : Reexports) 675 for (auto &Sym : Symbols) 676 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags); 677 for (auto &[Targets, Symbols] : Undefineds) 678 for (auto &Sym : Symbols) 679 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags); 680 681 return std::move(F); 682 } 683 684 Expected<std::vector<IFPtr>> getInlinedLibs(const Object *File) { 685 std::vector<IFPtr> IFs; 686 const Array *Files = File->getArray(Keys[TBDKey::Documents]); 687 if (!Files) 688 return std::move(IFs); 689 690 for (auto Lib : *Files) { 691 auto IFOrErr = parseToInterfaceFile(Lib.getAsObject()); 692 if (!IFOrErr) 693 return IFOrErr.takeError(); 694 auto IF = std::move(*IFOrErr); 695 IFs.emplace_back(std::move(IF)); 696 } 697 return std::move(IFs); 698 } 699 700 } // namespace StubParser 701 } // namespace 702 703 Expected<std::unique_ptr<InterfaceFile>> 704 MachO::getInterfaceFileFromJSON(StringRef JSON) { 705 auto ValOrErr = parse(JSON); 706 if (!ValOrErr) 707 return ValOrErr.takeError(); 708 709 auto *Root = ValOrErr->getAsObject(); 710 auto VersionOrErr = StubParser::getVersion(Root); 711 if (!VersionOrErr) 712 return VersionOrErr.takeError(); 713 FileType Version = *VersionOrErr; 714 715 Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]); 716 auto IFOrErr = StubParser::parseToInterfaceFile(MainLib); 717 if (!IFOrErr) 718 return IFOrErr.takeError(); 719 (*IFOrErr)->setFileType(Version); 720 std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr)); 721 722 auto IFsOrErr = StubParser::getInlinedLibs(Root); 723 if (!IFsOrErr) 724 return IFsOrErr.takeError(); 725 for (auto &File : *IFsOrErr) { 726 File->setFileType(Version); 727 IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File))); 728 } 729 return std::move(IF); 730 } 731 732 namespace { 733 734 template <typename ContainerT = Array> 735 bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) { 736 if (Contents.empty()) 737 return false; 738 Obj[Keys[Key]] = std::move(Contents); 739 return true; 740 } 741 742 std::string getFormattedStr(const MachO::Target &Targ) { 743 std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST 744 ? "maccatalyst" 745 : getOSAndEnvironmentName(Targ.Platform); 746 return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str(); 747 } 748 749 template <typename AggregateT> 750 std::vector<std::string> serializeTargets(const AggregateT Targets, 751 const TargetList &ActiveTargets) { 752 std::vector<std::string> TargetsStr; 753 if (Targets.size() == ActiveTargets.size()) 754 return TargetsStr; 755 756 llvm::for_each(Targets, [&TargetsStr](const MachO::Target &Target) { 757 TargetsStr.emplace_back(getFormattedStr(Target)); 758 }); 759 return TargetsStr; 760 } 761 762 Array serializeTargetInfo(const TargetList &ActiveTargets) { 763 Array Targets; 764 for (const auto Targ : ActiveTargets) { 765 Object TargetInfo; 766 TargetInfo[Keys[TBDKey::Deployment]] = Targ.MinDeployment.getAsString(); 767 TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ); 768 Targets.emplace_back(std::move(TargetInfo)); 769 } 770 return Targets; 771 } 772 773 template <typename ValueT, typename EntryT = ValueT> 774 Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) { 775 if (Value == Default) 776 return {}; 777 Array Container; 778 Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})}); 779 780 Container.emplace_back(std::move(ScalarObj)); 781 return Container; 782 } 783 784 using TargetsToValuesMap = 785 std::map<std::vector<std::string>, std::vector<std::string>>; 786 787 template <typename AggregateT = TargetsToValuesMap> 788 Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) { 789 Array Container; 790 for (const auto &[Targets, Values] : Entries) { 791 Object Obj; 792 insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets)); 793 Obj[Keys[Key]] = Values; 794 Container.emplace_back(std::move(Obj)); 795 } 796 return Container; 797 } 798 799 template <typename ValueT = std::string, 800 typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>> 801 Array serializeField(TBDKey Key, const AggregateT &Values, 802 const TargetList &ActiveTargets, bool IsArray = true) { 803 std::map<ValueT, std::set<MachO::Target>> Entries; 804 for (const auto &[Target, Val] : Values) 805 Entries[Val].insert(Target); 806 807 if (!IsArray) { 808 std::map<std::vector<std::string>, std::string> FinalEntries; 809 for (const auto &[Val, Targets] : Entries) 810 FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val; 811 return serializeAttrToTargets(FinalEntries, Key); 812 } 813 814 TargetsToValuesMap FinalEntries; 815 for (const auto &[Val, Targets] : Entries) 816 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val); 817 return serializeAttrToTargets(FinalEntries, Key); 818 } 819 820 Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values, 821 const TargetList &ActiveTargets) { 822 TargetsToValuesMap FinalEntries; 823 for (const auto &Ref : Values) { 824 TargetList Targets{Ref.targets().begin(), Ref.targets().end()}; 825 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back( 826 Ref.getInstallName()); 827 } 828 return serializeAttrToTargets(FinalEntries, Key); 829 } 830 831 struct SymbolFields { 832 struct SymbolTypes { 833 std::vector<StringRef> Weaks; 834 std::vector<StringRef> Globals; 835 std::vector<StringRef> TLV; 836 std::vector<StringRef> ObjCClasses; 837 std::vector<StringRef> IVars; 838 std::vector<StringRef> EHTypes; 839 840 bool empty() const { 841 return Weaks.empty() && Globals.empty() && TLV.empty() && 842 ObjCClasses.empty() && IVars.empty() && EHTypes.empty(); 843 } 844 }; 845 SymbolTypes Data; 846 SymbolTypes Text; 847 }; 848 849 Array serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols, 850 const TargetList &ActiveTargets) { 851 auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment, 852 const Symbol *Sym) { 853 switch (Sym->getKind()) { 854 case SymbolKind::ObjectiveCClass: 855 Assignment.ObjCClasses.emplace_back(Sym->getName()); 856 return; 857 case SymbolKind::ObjectiveCClassEHType: 858 Assignment.EHTypes.emplace_back(Sym->getName()); 859 return; 860 case SymbolKind::ObjectiveCInstanceVariable: 861 Assignment.IVars.emplace_back(Sym->getName()); 862 return; 863 case SymbolKind::GlobalSymbol: { 864 if (Sym->isWeakReferenced() || Sym->isWeakDefined()) 865 Assignment.Weaks.emplace_back(Sym->getName()); 866 else if (Sym->isThreadLocalValue()) 867 Assignment.TLV.emplace_back(Sym->getName()); 868 else 869 Assignment.Globals.emplace_back(Sym->getName()); 870 return; 871 } 872 } 873 }; 874 875 std::map<std::vector<std::string>, SymbolFields> Entries; 876 for (const auto *Sym : Symbols) { 877 std::set<MachO::Target> Targets{Sym->targets().begin(), 878 Sym->targets().end()}; 879 auto JSONTargets = serializeTargets(Targets, ActiveTargets); 880 if (Sym->isData()) 881 AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym); 882 else if (Sym->isText()) 883 AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym); 884 else 885 llvm_unreachable("unexpected symbol type"); 886 } 887 888 auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey, 889 SymbolFields::SymbolTypes &SymField) { 890 if (SymField.empty()) 891 return; 892 Object Segment; 893 insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals)); 894 insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV)); 895 insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks)); 896 insertNonEmptyValues(Segment, TBDKey::ObjCClass, 897 std::move(SymField.ObjCClasses)); 898 insertNonEmptyValues(Segment, TBDKey::ObjCEHType, 899 std::move(SymField.EHTypes)); 900 insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars)); 901 insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment)); 902 }; 903 904 Array SymbolSection; 905 for (auto &[Targets, Fields] : Entries) { 906 Object AllSyms; 907 insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets)); 908 InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data); 909 InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text); 910 SymbolSection.emplace_back(std::move(AllSyms)); 911 } 912 913 return SymbolSection; 914 } 915 916 Array serializeFlags(const InterfaceFile *File) { 917 // TODO: Give all Targets the same flags for now. 918 Array Flags; 919 if (!File->isTwoLevelNamespace()) 920 Flags.emplace_back("flat_namespace"); 921 if (!File->isApplicationExtensionSafe()) 922 Flags.emplace_back("not_app_extension_safe"); 923 return serializeScalar(TBDKey::Attributes, std::move(Flags)); 924 } 925 926 Expected<Object> serializeIF(const InterfaceFile *File) { 927 Object Library; 928 929 // Handle required keys. 930 TargetList ActiveTargets{File->targets().begin(), File->targets().end()}; 931 if (!insertNonEmptyValues(Library, TBDKey::TargetInfo, 932 serializeTargetInfo(ActiveTargets))) 933 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo)); 934 935 Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName()); 936 if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name))) 937 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName)); 938 939 // Handle optional keys. 940 Array Flags = serializeFlags(File); 941 insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags)); 942 943 Array CurrentV = serializeScalar<PackedVersion, std::string>( 944 TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0)); 945 insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV)); 946 947 Array CompatV = serializeScalar<PackedVersion, std::string>( 948 TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0)); 949 insertNonEmptyValues(Library, TBDKey::CompatibilityVersion, 950 std::move(CompatV)); 951 952 Array SwiftABI = serializeScalar<uint8_t, int64_t>( 953 TBDKey::ABI, File->getSwiftABIVersion(), 0u); 954 insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI)); 955 956 Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets); 957 insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths)); 958 959 Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(), 960 ActiveTargets, /*IsArray=*/false); 961 insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas)); 962 963 Array Clients = 964 serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets); 965 insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients)); 966 967 Array ReexportLibs = 968 serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets); 969 insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs)); 970 971 // Handle symbols. 972 Array Exports = serializeSymbols(File->exports(), ActiveTargets); 973 insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports)); 974 975 Array Reexports = serializeSymbols(File->reexports(), ActiveTargets); 976 insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports)); 977 978 if (!File->isTwoLevelNamespace()) { 979 Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets); 980 insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds)); 981 } 982 983 return std::move(Library); 984 } 985 986 Expected<Object> getJSON(const InterfaceFile *File) { 987 assert(File->getFileType() == FileType::TBD_V5 && 988 "unexpected json file format version"); 989 Object Root; 990 991 auto MainLibOrErr = serializeIF(File); 992 if (!MainLibOrErr) 993 return MainLibOrErr; 994 Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr); 995 Array Documents; 996 for (const auto &Doc : File->documents()) { 997 auto LibOrErr = serializeIF(Doc.get()); 998 if (!LibOrErr) 999 return LibOrErr; 1000 Documents.emplace_back(std::move(*LibOrErr)); 1001 } 1002 1003 Root[Keys[TBDKey::TBDVersion]] = 5; 1004 insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents)); 1005 return std::move(Root); 1006 } 1007 1008 } // namespace 1009 1010 Error MachO::serializeInterfaceFileToJSON(raw_ostream &OS, 1011 const InterfaceFile &File, 1012 bool Compact) { 1013 auto TextFile = getJSON(&File); 1014 if (!TextFile) 1015 return TextFile.takeError(); 1016 if (Compact) 1017 OS << formatv("{0}", Value(std::move(*TextFile))) << "\n"; 1018 else 1019 OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n"; 1020 return Error::success(); 1021 } 1022