1164 lines · cpp
1//===- TextStub.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-exception6//7//===----------------------------------------------------------------------===//8//9// Implements the text stub file reader/writer.10//11//===----------------------------------------------------------------------===//12 13#include "TextAPIContext.h"14#include "TextStubCommon.h"15#include "llvm/ADT/BitmaskEnum.h"16#include "llvm/ADT/SmallString.h"17#include "llvm/ADT/StringRef.h"18#include "llvm/Support/Allocator.h"19#include "llvm/Support/SourceMgr.h"20#include "llvm/Support/YAMLTraits.h"21#include "llvm/Support/raw_ostream.h"22#include "llvm/TextAPI/Architecture.h"23#include "llvm/TextAPI/ArchitectureSet.h"24#include "llvm/TextAPI/InterfaceFile.h"25#include "llvm/TextAPI/PackedVersion.h"26#include "llvm/TextAPI/TextAPIReader.h"27#include "llvm/TextAPI/TextAPIWriter.h"28#include <set>29 30// clang-format off31/*32 33 YAML Format specification.34 35 The TBD v1 format only support two level address libraries and is per36 definition application extension safe.37 38--- # the tag !tapi-tbd-v1 is optional and39 # shouldn't be emitted to support older linker.40archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are41 # supported by this file.42platform: ios # Specifies the platform (macosx, ios, etc)43install-name: /u/l/libfoo.dylib #44current-version: 1.2.3 # Optional: defaults to 1.045compatibility-version: 1.0 # Optional: defaults to 1.046swift-version: 0 # Optional: defaults to 047objc-constraint: none # Optional: defaults to none48exports: # List of export sections49...50 51Each export section is defined as following:52 53 - archs: [ arm64 ] # the list of architecture slices54 allowed-clients: [ client ] # Optional: List of clients55 re-exports: [ ] # Optional: List of re-exports56 symbols: [ _sym ] # Optional: List of symbols57 objc-classes: [] # Optional: List of Objective-C classes58 objc-ivars: [] # Optional: List of Objective C Instance59 # Variables60 weak-def-symbols: [] # Optional: List of weak defined symbols61 thread-local-symbols: [] # Optional: List of thread local symbols62*/63 64/*65 66 YAML Format specification.67 68--- !tapi-tbd-v269archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are70 # supported by this file.71uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.72platform: ios # Specifies the platform (macosx, ios, etc)73flags: [] # Optional:74install-name: /u/l/libfoo.dylib #75current-version: 1.2.3 # Optional: defaults to 1.076compatibility-version: 1.0 # Optional: defaults to 1.077swift-version: 0 # Optional: defaults to 078objc-constraint: retain_release # Optional: defaults to retain_release79parent-umbrella: # Optional:80exports: # List of export sections81...82undefineds: # List of undefineds sections83...84 85Each export section is defined as following:86 87- archs: [ arm64 ] # the list of architecture slices88 allowed-clients: [ client ] # Optional: List of clients89 re-exports: [ ] # Optional: List of re-exports90 symbols: [ _sym ] # Optional: List of symbols91 objc-classes: [] # Optional: List of Objective-C classes92 objc-ivars: [] # Optional: List of Objective C Instance93 # Variables94 weak-def-symbols: [] # Optional: List of weak defined symbols95 thread-local-symbols: [] # Optional: List of thread local symbols96 97Each undefineds section is defined as following:98- archs: [ arm64 ] # the list of architecture slices99 symbols: [ _sym ] # Optional: List of symbols100 objc-classes: [] # Optional: List of Objective-C classes101 objc-ivars: [] # Optional: List of Objective C Instance Variables102 weak-ref-symbols: [] # Optional: List of weak defined symbols103*/104 105/*106 107 YAML Format specification.108 109--- !tapi-tbd-v3110archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are111 # supported by this file.112uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.113platform: ios # Specifies the platform (macosx, ios, etc)114flags: [] # Optional:115install-name: /u/l/libfoo.dylib #116current-version: 1.2.3 # Optional: defaults to 1.0117compatibility-version: 1.0 # Optional: defaults to 1.0118swift-abi-version: 0 # Optional: defaults to 0119objc-constraint: retain_release # Optional: defaults to retain_release120parent-umbrella: # Optional:121exports: # List of export sections122...123undefineds: # List of undefineds sections124...125 126Each export section is defined as following:127 128- archs: [ arm64 ] # the list of architecture slices129 allowed-clients: [ client ] # Optional: List of clients130 re-exports: [ ] # Optional: List of re-exports131 symbols: [ _sym ] # Optional: List of symbols132 objc-classes: [] # Optional: List of Objective-C classes133 objc-eh-types: [] # Optional: List of Objective-C classes134 # with EH135 objc-ivars: [] # Optional: List of Objective C Instance136 # Variables137 weak-def-symbols: [] # Optional: List of weak defined symbols138 thread-local-symbols: [] # Optional: List of thread local symbols139 140Each undefineds section is defined as following:141- archs: [ arm64 ] # the list of architecture slices142 symbols: [ _sym ] # Optional: List of symbols143 objc-classes: [] # Optional: List of Objective-C classes144 objc-eh-types: [] # Optional: List of Objective-C classes145 # with EH146 objc-ivars: [] # Optional: List of Objective C Instance Variables147 weak-ref-symbols: [] # Optional: List of weak defined symbols148*/149 150/*151 152 YAML Format specification.153 154--- !tapi-tbd155tbd-version: 4 # The tbd version for format156targets: [ armv7-ios, x86_64-maccatalyst ] # The list of applicable tapi supported target triples157uuids: # Optional: List of target and UUID pairs.158 - target: armv7-ios159 value: ...160 - target: x86_64-maccatalyst161 value: ...162flags: [] # Optional:163install-name: /u/l/libfoo.dylib #164current-version: 1.2.3 # Optional: defaults to 1.0165compatibility-version: 1.0 # Optional: defaults to 1.0166swift-abi-version: 0 # Optional: defaults to 0167parent-umbrella: # Optional:168allowable-clients:169 - targets: [ armv7-ios ] # Optional:170 clients: [ clientA ]171exports: # List of export sections172...173re-exports: # List of reexport sections174...175undefineds: # List of undefineds sections176...177 178Each export and reexport section is defined as following:179 180- targets: [ arm64-macos ] # The list of target triples associated with symbols181 symbols: [ _symA ] # Optional: List of symbols182 objc-classes: [] # Optional: List of Objective-C classes183 objc-eh-types: [] # Optional: List of Objective-C classes184 # with EH185 objc-ivars: [] # Optional: List of Objective C Instance186 # Variables187 weak-symbols: [] # Optional: List of weak defined symbols188 thread-local-symbols: [] # Optional: List of thread local symbols189- targets: [ arm64-macos, x86_64-maccatalyst ] # Optional: Targets for applicable additional symbols190 symbols: [ _symB ] # Optional: List of symbols191 192Each undefineds section is defined as following:193- targets: [ arm64-macos ] # The list of target triples associated with symbols194 symbols: [ _symC ] # Optional: List of symbols195 objc-classes: [] # Optional: List of Objective-C classes196 objc-eh-types: [] # Optional: List of Objective-C classes197 # with EH198 objc-ivars: [] # Optional: List of Objective C Instance Variables199 weak-symbols: [] # Optional: List of weak defined symbols200*/201// clang-format on202 203using namespace llvm;204using namespace llvm::yaml;205using namespace llvm::MachO;206 207namespace {208struct ExportSection {209 std::vector<Architecture> Architectures;210 std::vector<FlowStringRef> AllowableClients;211 std::vector<FlowStringRef> ReexportedLibraries;212 std::vector<FlowStringRef> Symbols;213 std::vector<FlowStringRef> Classes;214 std::vector<FlowStringRef> ClassEHs;215 std::vector<FlowStringRef> IVars;216 std::vector<FlowStringRef> WeakDefSymbols;217 std::vector<FlowStringRef> TLVSymbols;218};219 220struct UndefinedSection {221 std::vector<Architecture> Architectures;222 std::vector<FlowStringRef> Symbols;223 std::vector<FlowStringRef> Classes;224 std::vector<FlowStringRef> ClassEHs;225 std::vector<FlowStringRef> IVars;226 std::vector<FlowStringRef> WeakRefSymbols;227};228 229// Sections for direct target mapping in TBDv4230struct SymbolSection {231 TargetList Targets;232 std::vector<FlowStringRef> Symbols;233 std::vector<FlowStringRef> Classes;234 std::vector<FlowStringRef> ClassEHs;235 std::vector<FlowStringRef> Ivars;236 std::vector<FlowStringRef> WeakSymbols;237 std::vector<FlowStringRef> TlvSymbols;238};239 240struct MetadataSection {241 enum Option { Clients, Libraries };242 std::vector<Target> Targets;243 std::vector<FlowStringRef> Values;244};245 246struct UmbrellaSection {247 std::vector<Target> Targets;248 std::string Umbrella;249};250 251// UUID's for TBDv4 are mapped to target not arch252struct UUIDv4 {253 Target TargetID;254 std::string Value;255 256 UUIDv4() = default;257 UUIDv4(const Target &TargetID, const std::string &Value)258 : TargetID(TargetID), Value(Value) {}259};260} // end anonymous namespace.261 262LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)263LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)264LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)265// Specific to TBDv4266LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection)267LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection)268LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection)269LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target)270LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4)271 272namespace llvm {273namespace yaml {274 275template <> struct MappingTraits<ExportSection> {276 static void mapping(IO &IO, ExportSection &Section) {277 const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());278 assert((!Ctx || Ctx->FileKind != FileType::Invalid) &&279 "File type is not set in YAML context");280 281 IO.mapRequired("archs", Section.Architectures);282 if (Ctx->FileKind == FileType::TBD_V1)283 IO.mapOptional("allowed-clients", Section.AllowableClients);284 else285 IO.mapOptional("allowable-clients", Section.AllowableClients);286 IO.mapOptional("re-exports", Section.ReexportedLibraries);287 IO.mapOptional("symbols", Section.Symbols);288 IO.mapOptional("objc-classes", Section.Classes);289 if (Ctx->FileKind == FileType::TBD_V3)290 IO.mapOptional("objc-eh-types", Section.ClassEHs);291 IO.mapOptional("objc-ivars", Section.IVars);292 IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols);293 IO.mapOptional("thread-local-symbols", Section.TLVSymbols);294 }295};296 297template <> struct MappingTraits<UndefinedSection> {298 static void mapping(IO &IO, UndefinedSection &Section) {299 const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());300 assert((!Ctx || Ctx->FileKind != FileType::Invalid) &&301 "File type is not set in YAML context");302 303 IO.mapRequired("archs", Section.Architectures);304 IO.mapOptional("symbols", Section.Symbols);305 IO.mapOptional("objc-classes", Section.Classes);306 if (Ctx->FileKind == FileType::TBD_V3)307 IO.mapOptional("objc-eh-types", Section.ClassEHs);308 IO.mapOptional("objc-ivars", Section.IVars);309 IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols);310 }311};312 313template <> struct MappingTraits<SymbolSection> {314 static void mapping(IO &IO, SymbolSection &Section) {315 IO.mapRequired("targets", Section.Targets);316 IO.mapOptional("symbols", Section.Symbols);317 IO.mapOptional("objc-classes", Section.Classes);318 IO.mapOptional("objc-eh-types", Section.ClassEHs);319 IO.mapOptional("objc-ivars", Section.Ivars);320 IO.mapOptional("weak-symbols", Section.WeakSymbols);321 IO.mapOptional("thread-local-symbols", Section.TlvSymbols);322 }323};324 325template <> struct MappingTraits<UmbrellaSection> {326 static void mapping(IO &IO, UmbrellaSection &Section) {327 IO.mapRequired("targets", Section.Targets);328 IO.mapRequired("umbrella", Section.Umbrella);329 }330};331 332template <> struct MappingTraits<UUIDv4> {333 static void mapping(IO &IO, UUIDv4 &UUID) {334 IO.mapRequired("target", UUID.TargetID);335 IO.mapRequired("value", UUID.Value);336 }337};338 339template <>340struct MappingContextTraits<MetadataSection, MetadataSection::Option> {341 static void mapping(IO &IO, MetadataSection &Section,342 MetadataSection::Option &OptionKind) {343 IO.mapRequired("targets", Section.Targets);344 switch (OptionKind) {345 case MetadataSection::Option::Clients:346 IO.mapRequired("clients", Section.Values);347 return;348 case MetadataSection::Option::Libraries:349 IO.mapRequired("libraries", Section.Values);350 return;351 }352 llvm_unreachable("unexpected option for metadata");353 }354};355 356template <> struct ScalarBitSetTraits<TBDFlags> {357 static void bitset(IO &IO, TBDFlags &Flags) {358 IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace);359 IO.bitSetCase(Flags, "not_app_extension_safe",360 TBDFlags::NotApplicationExtensionSafe);361 IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI);362 IO.bitSetCase(Flags, "not_for_dyld_shared_cache",363 TBDFlags::OSLibNotForSharedCache);364 }365};366 367template <> struct ScalarTraits<Target> {368 static void output(const Target &Value, void *, raw_ostream &OS) {369 OS << Value.Arch << "-";370 switch (Value.Platform) {371#define PLATFORM(platform, id, name, build_name, target, tapi_target, \372 marketing) \373 case PLATFORM_##platform: \374 OS << #tapi_target; \375 break;376#include "llvm/BinaryFormat/MachO.def"377 }378 }379 380 static StringRef input(StringRef Scalar, void *, Target &Value) {381 auto Result = Target::create(Scalar);382 if (!Result) {383 consumeError(Result.takeError());384 return "unparsable target";385 }386 387 Value = *Result;388 if (Value.Arch == AK_unknown)389 return "unknown architecture";390 if (Value.Platform == PLATFORM_UNKNOWN)391 return "unknown platform";392 393 return {};394 }395 396 static QuotingType mustQuote(StringRef) { return QuotingType::None; }397};398 399template <> struct MappingTraits<const InterfaceFile *> {400 struct NormalizedTBD {401 explicit NormalizedTBD(IO &IO) {}402 NormalizedTBD(IO &IO, const InterfaceFile *&File) {403 Architectures = File->getArchitectures();404 Platforms = File->getPlatforms();405 InstallName = File->getInstallName();406 CurrentVersion = PackedVersion(File->getCurrentVersion());407 CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());408 SwiftABIVersion = File->getSwiftABIVersion();409 ObjCConstraint = File->getObjCConstraint();410 411 Flags = TBDFlags::None;412 if (!File->isApplicationExtensionSafe())413 Flags |= TBDFlags::NotApplicationExtensionSafe;414 415 if (!File->isTwoLevelNamespace())416 Flags |= TBDFlags::FlatNamespace;417 418 if (!File->umbrellas().empty())419 ParentUmbrella = File->umbrellas().begin()->second;420 421 std::set<ArchitectureSet> ArchSet;422 for (const auto &Library : File->allowableClients())423 ArchSet.insert(Library.getArchitectures());424 425 for (const auto &Library : File->reexportedLibraries())426 ArchSet.insert(Library.getArchitectures());427 428 std::map<const Symbol *, ArchitectureSet> SymbolToArchSet;429 for (const auto *Symbol : File->symbols()) {430 auto Architectures = Symbol->getArchitectures();431 SymbolToArchSet[Symbol] = Architectures;432 ArchSet.insert(Architectures);433 }434 435 for (auto Architectures : ArchSet) {436 ExportSection Section;437 Section.Architectures = Architectures;438 439 for (const auto &Library : File->allowableClients())440 if (Library.getArchitectures() == Architectures)441 Section.AllowableClients.emplace_back(Library.getInstallName());442 443 for (const auto &Library : File->reexportedLibraries())444 if (Library.getArchitectures() == Architectures)445 Section.ReexportedLibraries.emplace_back(Library.getInstallName());446 447 for (const auto &SymArch : SymbolToArchSet) {448 if (SymArch.second != Architectures)449 continue;450 451 const auto *Symbol = SymArch.first;452 switch (Symbol->getKind()) {453 case EncodeKind::GlobalSymbol:454 if (Symbol->isWeakDefined())455 Section.WeakDefSymbols.emplace_back(Symbol->getName());456 else if (Symbol->isThreadLocalValue())457 Section.TLVSymbols.emplace_back(Symbol->getName());458 else459 Section.Symbols.emplace_back(Symbol->getName());460 break;461 case EncodeKind::ObjectiveCClass:462 if (File->getFileType() != FileType::TBD_V3)463 Section.Classes.emplace_back(464 copyString("_" + Symbol->getName().str()));465 else466 Section.Classes.emplace_back(Symbol->getName());467 break;468 case EncodeKind::ObjectiveCClassEHType:469 if (File->getFileType() != FileType::TBD_V3)470 Section.Symbols.emplace_back(471 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));472 else473 Section.ClassEHs.emplace_back(Symbol->getName());474 break;475 case EncodeKind::ObjectiveCInstanceVariable:476 if (File->getFileType() != FileType::TBD_V3)477 Section.IVars.emplace_back(478 copyString("_" + Symbol->getName().str()));479 else480 Section.IVars.emplace_back(Symbol->getName());481 break;482 }483 }484 llvm::sort(Section.Symbols);485 llvm::sort(Section.Classes);486 llvm::sort(Section.ClassEHs);487 llvm::sort(Section.IVars);488 llvm::sort(Section.WeakDefSymbols);489 llvm::sort(Section.TLVSymbols);490 Exports.emplace_back(std::move(Section));491 }492 493 ArchSet.clear();494 SymbolToArchSet.clear();495 496 for (const auto *Symbol : File->undefineds()) {497 auto Architectures = Symbol->getArchitectures();498 SymbolToArchSet[Symbol] = Architectures;499 ArchSet.insert(Architectures);500 }501 502 for (auto Architectures : ArchSet) {503 UndefinedSection Section;504 Section.Architectures = Architectures;505 506 for (const auto &SymArch : SymbolToArchSet) {507 if (SymArch.second != Architectures)508 continue;509 510 const auto *Symbol = SymArch.first;511 switch (Symbol->getKind()) {512 case EncodeKind::GlobalSymbol:513 if (Symbol->isWeakReferenced())514 Section.WeakRefSymbols.emplace_back(Symbol->getName());515 else516 Section.Symbols.emplace_back(Symbol->getName());517 break;518 case EncodeKind::ObjectiveCClass:519 if (File->getFileType() != FileType::TBD_V3)520 Section.Classes.emplace_back(521 copyString("_" + Symbol->getName().str()));522 else523 Section.Classes.emplace_back(Symbol->getName());524 break;525 case EncodeKind::ObjectiveCClassEHType:526 if (File->getFileType() != FileType::TBD_V3)527 Section.Symbols.emplace_back(528 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));529 else530 Section.ClassEHs.emplace_back(Symbol->getName());531 break;532 case EncodeKind::ObjectiveCInstanceVariable:533 if (File->getFileType() != FileType::TBD_V3)534 Section.IVars.emplace_back(535 copyString("_" + Symbol->getName().str()));536 else537 Section.IVars.emplace_back(Symbol->getName());538 break;539 }540 }541 llvm::sort(Section.Symbols);542 llvm::sort(Section.Classes);543 llvm::sort(Section.ClassEHs);544 llvm::sort(Section.IVars);545 llvm::sort(Section.WeakRefSymbols);546 Undefineds.emplace_back(std::move(Section));547 }548 }549 550 // TBD v1 - TBD v3 files only support one platform and several551 // architectures. It is possible to have more than one platform for TBD v3552 // files, but the architectures don't apply to all553 // platforms, specifically to filter out the i386 slice from554 // platform macCatalyst.555 TargetList synthesizeTargets(ArchitectureSet Architectures,556 const PlatformSet &Platforms) {557 TargetList Targets;558 559 for (auto Platform : Platforms) {560 Platform = mapToPlatformType(Platform, Architectures.hasX86());561 562 for (const auto &&Architecture : Architectures) {563 if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))564 continue;565 566 Targets.emplace_back(Architecture, Platform);567 }568 }569 return Targets;570 }571 572 const InterfaceFile *denormalize(IO &IO) {573 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());574 assert(Ctx);575 576 auto *File = new InterfaceFile;577 File->setPath(Ctx->Path);578 File->setFileType(Ctx->FileKind);579 File->addTargets(synthesizeTargets(Architectures, Platforms));580 File->setInstallName(InstallName);581 File->setCurrentVersion(CurrentVersion);582 File->setCompatibilityVersion(CompatibilityVersion);583 File->setSwiftABIVersion(SwiftABIVersion);584 File->setObjCConstraint(ObjCConstraint);585 for (const auto &Target : File->targets())586 File->addParentUmbrella(Target, ParentUmbrella);587 588 if (Ctx->FileKind == FileType::TBD_V1) {589 File->setTwoLevelNamespace();590 File->setApplicationExtensionSafe();591 } else {592 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));593 File->setApplicationExtensionSafe(594 !(Flags & TBDFlags::NotApplicationExtensionSafe));595 }596 597 // For older file formats, the segment where the symbol598 // comes from is unknown, treat all symbols as Data599 // in these cases.600 const auto Flags = SymbolFlags::Data;601 602 for (const auto &Section : Exports) {603 const auto Targets =604 synthesizeTargets(Section.Architectures, Platforms);605 606 for (const auto &Lib : Section.AllowableClients)607 for (const auto &Target : Targets)608 File->addAllowableClient(Lib, Target);609 610 for (const auto &Lib : Section.ReexportedLibraries)611 for (const auto &Target : Targets)612 File->addReexportedLibrary(Lib, Target);613 614 for (const auto &Symbol : Section.Symbols) {615 if (Ctx->FileKind != FileType::TBD_V3 &&616 Symbol.value.starts_with(ObjC2EHTypePrefix))617 File->addSymbol(EncodeKind::ObjectiveCClassEHType,618 Symbol.value.drop_front(15), Targets, Flags);619 else620 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, Flags);621 }622 for (auto &Symbol : Section.Classes) {623 auto Name = Symbol.value;624 if (Ctx->FileKind != FileType::TBD_V3)625 Name = Name.drop_front();626 File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets, Flags);627 }628 for (auto &Symbol : Section.ClassEHs)629 File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets,630 Flags);631 for (auto &Symbol : Section.IVars) {632 auto Name = Symbol.value;633 if (Ctx->FileKind != FileType::TBD_V3)634 Name = Name.drop_front();635 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets,636 Flags);637 }638 for (auto &Symbol : Section.WeakDefSymbols)639 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,640 SymbolFlags::WeakDefined | Flags);641 for (auto &Symbol : Section.TLVSymbols)642 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,643 SymbolFlags::ThreadLocalValue | Flags);644 }645 646 for (const auto &Section : Undefineds) {647 const auto Targets =648 synthesizeTargets(Section.Architectures, Platforms);649 for (auto &Symbol : Section.Symbols) {650 if (Ctx->FileKind != FileType::TBD_V3 &&651 Symbol.value.starts_with(ObjC2EHTypePrefix))652 File->addSymbol(EncodeKind::ObjectiveCClassEHType,653 Symbol.value.drop_front(15), Targets,654 SymbolFlags::Undefined | Flags);655 else656 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,657 SymbolFlags::Undefined | Flags);658 }659 for (auto &Symbol : Section.Classes) {660 auto Name = Symbol.value;661 if (Ctx->FileKind != FileType::TBD_V3)662 Name = Name.drop_front();663 File->addSymbol(EncodeKind::ObjectiveCClass, Name, Targets,664 SymbolFlags::Undefined | Flags);665 }666 for (auto &Symbol : Section.ClassEHs)667 File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets,668 SymbolFlags::Undefined | Flags);669 for (auto &Symbol : Section.IVars) {670 auto Name = Symbol.value;671 if (Ctx->FileKind != FileType::TBD_V3)672 Name = Name.drop_front();673 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, Name, Targets,674 SymbolFlags::Undefined | Flags);675 }676 for (auto &Symbol : Section.WeakRefSymbols)677 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets,678 SymbolFlags::Undefined | SymbolFlags::WeakReferenced |679 Flags);680 }681 682 return File;683 }684 685 llvm::BumpPtrAllocator Allocator;686 StringRef copyString(StringRef String) {687 if (String.empty())688 return {};689 690 void *Ptr = Allocator.Allocate(String.size(), 1);691 memcpy(Ptr, String.data(), String.size());692 return StringRef(reinterpret_cast<const char *>(Ptr), String.size());693 }694 695 std::vector<Architecture> Architectures;696 std::vector<UUID> UUIDs;697 PlatformSet Platforms;698 StringRef InstallName;699 PackedVersion CurrentVersion;700 PackedVersion CompatibilityVersion;701 SwiftVersion SwiftABIVersion{0};702 ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};703 TBDFlags Flags{TBDFlags::None};704 StringRef ParentUmbrella;705 std::vector<ExportSection> Exports;706 std::vector<UndefinedSection> Undefineds;707 };708 709 static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) {710 if (IO.mapTag("!tapi-tbd", false))711 Ctx->FileKind = FileType::TBD_V4;712 else if (IO.mapTag("!tapi-tbd-v3", false))713 Ctx->FileKind = FileType::TBD_V3;714 else if (IO.mapTag("!tapi-tbd-v2", false))715 Ctx->FileKind = FileType::TBD_V2;716 else if (IO.mapTag("!tapi-tbd-v1", false) ||717 IO.mapTag("tag:yaml.org,2002:map", false))718 Ctx->FileKind = FileType::TBD_V1;719 else {720 Ctx->FileKind = FileType::Invalid;721 return;722 }723 }724 725 static void mapping(IO &IO, const InterfaceFile *&File) {726 auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());727 assert((!Ctx || !IO.outputting() ||728 (Ctx && Ctx->FileKind != FileType::Invalid)) &&729 "File type is not set in YAML context");730 731 if (!IO.outputting()) {732 setFileTypeForInput(Ctx, IO);733 switch (Ctx->FileKind) {734 default:735 break;736 case FileType::TBD_V4:737 mapKeysToValuesV4(IO, File);738 return;739 case FileType::Invalid:740 IO.setError("unsupported file type");741 return;742 }743 } else {744 // Set file type when writing.745 switch (Ctx->FileKind) {746 default:747 llvm_unreachable("unexpected file type");748 case FileType::TBD_V4:749 mapKeysToValuesV4(IO, File);750 return;751 case FileType::TBD_V3:752 IO.mapTag("!tapi-tbd-v3", true);753 break;754 case FileType::TBD_V2:755 IO.mapTag("!tapi-tbd-v2", true);756 break;757 case FileType::TBD_V1:758 // Don't write the tag into the .tbd file for TBD v1759 break;760 }761 }762 mapKeysToValues(Ctx->FileKind, IO, File);763 }764 765 using SectionList = std::vector<SymbolSection>;766 struct NormalizedTBD_V4 {767 explicit NormalizedTBD_V4(IO &IO) {}768 NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) {769 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());770 assert(Ctx);771 TBDVersion = Ctx->FileKind >> 4;772 Targets.insert(Targets.begin(), File->targets().begin(),773 File->targets().end());774 InstallName = File->getInstallName();775 CurrentVersion = File->getCurrentVersion();776 CompatibilityVersion = File->getCompatibilityVersion();777 SwiftABIVersion = File->getSwiftABIVersion();778 779 Flags = TBDFlags::None;780 if (!File->isApplicationExtensionSafe())781 Flags |= TBDFlags::NotApplicationExtensionSafe;782 783 if (!File->isTwoLevelNamespace())784 Flags |= TBDFlags::FlatNamespace;785 786 if (File->isOSLibNotForSharedCache())787 Flags |= TBDFlags::OSLibNotForSharedCache;788 789 {790 std::map<std::string, TargetList> valueToTargetList;791 for (const auto &it : File->umbrellas())792 valueToTargetList[it.second].emplace_back(it.first);793 794 for (const auto &it : valueToTargetList) {795 UmbrellaSection CurrentSection;796 CurrentSection.Targets.insert(CurrentSection.Targets.begin(),797 it.second.begin(), it.second.end());798 CurrentSection.Umbrella = it.first;799 ParentUmbrellas.emplace_back(std::move(CurrentSection));800 }801 }802 803 assignTargetsToLibrary(File->allowableClients(), AllowableClients);804 assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries);805 806 auto handleSymbols =807 [](SectionList &CurrentSections,808 InterfaceFile::const_filtered_symbol_range Symbols) {809 std::set<TargetList> TargetSet;810 std::map<const Symbol *, TargetList> SymbolToTargetList;811 for (const auto *Symbol : Symbols) {812 TargetList Targets(Symbol->targets());813 SymbolToTargetList[Symbol] = Targets;814 TargetSet.emplace(std::move(Targets));815 }816 for (const auto &TargetIDs : TargetSet) {817 SymbolSection CurrentSection;818 CurrentSection.Targets.insert(CurrentSection.Targets.begin(),819 TargetIDs.begin(), TargetIDs.end());820 821 for (const auto &IT : SymbolToTargetList) {822 if (IT.second != TargetIDs)823 continue;824 825 const auto *Symbol = IT.first;826 switch (Symbol->getKind()) {827 case EncodeKind::GlobalSymbol:828 if (Symbol->isWeakDefined())829 CurrentSection.WeakSymbols.emplace_back(Symbol->getName());830 else if (Symbol->isThreadLocalValue())831 CurrentSection.TlvSymbols.emplace_back(Symbol->getName());832 else833 CurrentSection.Symbols.emplace_back(Symbol->getName());834 break;835 case EncodeKind::ObjectiveCClass:836 CurrentSection.Classes.emplace_back(Symbol->getName());837 break;838 case EncodeKind::ObjectiveCClassEHType:839 CurrentSection.ClassEHs.emplace_back(Symbol->getName());840 break;841 case EncodeKind::ObjectiveCInstanceVariable:842 CurrentSection.Ivars.emplace_back(Symbol->getName());843 break;844 }845 }846 sort(CurrentSection.Symbols);847 sort(CurrentSection.Classes);848 sort(CurrentSection.ClassEHs);849 sort(CurrentSection.Ivars);850 sort(CurrentSection.WeakSymbols);851 sort(CurrentSection.TlvSymbols);852 CurrentSections.emplace_back(std::move(CurrentSection));853 }854 };855 856 handleSymbols(Exports, File->exports());857 handleSymbols(Reexports, File->reexports());858 handleSymbols(Undefineds, File->undefineds());859 }860 861 const InterfaceFile *denormalize(IO &IO) {862 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());863 assert(Ctx);864 865 auto *File = new InterfaceFile;866 File->setPath(Ctx->Path);867 File->setFileType(Ctx->FileKind);868 File->addTargets(Targets);869 File->setInstallName(InstallName);870 File->setCurrentVersion(CurrentVersion);871 File->setCompatibilityVersion(CompatibilityVersion);872 File->setSwiftABIVersion(SwiftABIVersion);873 for (const auto &CurrentSection : ParentUmbrellas)874 for (const auto &target : CurrentSection.Targets)875 File->addParentUmbrella(target, CurrentSection.Umbrella);876 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));877 File->setApplicationExtensionSafe(878 !(Flags & TBDFlags::NotApplicationExtensionSafe));879 File->setOSLibNotForSharedCache(880 (Flags & TBDFlags::OSLibNotForSharedCache));881 882 for (const auto &CurrentSection : AllowableClients) {883 for (const auto &lib : CurrentSection.Values)884 for (const auto &Target : CurrentSection.Targets)885 File->addAllowableClient(lib, Target);886 }887 888 for (const auto &CurrentSection : ReexportedLibraries) {889 for (const auto &Lib : CurrentSection.Values)890 for (const auto &Target : CurrentSection.Targets)891 File->addReexportedLibrary(Lib, Target);892 }893 894 auto handleSymbols = [File](const SectionList &CurrentSections,895 SymbolFlags InputFlag = SymbolFlags::None) {896 // For older file formats, the segment where the symbol897 // comes from is unknown, treat all symbols as Data898 // in these cases.899 const SymbolFlags Flag = InputFlag | SymbolFlags::Data;900 901 for (const auto &CurrentSection : CurrentSections) {902 for (auto &sym : CurrentSection.Symbols)903 File->addSymbol(EncodeKind::GlobalSymbol, sym,904 CurrentSection.Targets, Flag);905 906 for (auto &sym : CurrentSection.Classes)907 File->addSymbol(EncodeKind::ObjectiveCClass, sym,908 CurrentSection.Targets, Flag);909 910 for (auto &sym : CurrentSection.ClassEHs)911 File->addSymbol(EncodeKind::ObjectiveCClassEHType, sym,912 CurrentSection.Targets, Flag);913 914 for (auto &sym : CurrentSection.Ivars)915 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, sym,916 CurrentSection.Targets, Flag);917 918 SymbolFlags SymFlag =919 ((Flag & SymbolFlags::Undefined) == SymbolFlags::Undefined)920 ? SymbolFlags::WeakReferenced921 : SymbolFlags::WeakDefined;922 for (auto &sym : CurrentSection.WeakSymbols) {923 File->addSymbol(EncodeKind::GlobalSymbol, sym,924 CurrentSection.Targets, Flag | SymFlag);925 }926 927 for (auto &sym : CurrentSection.TlvSymbols)928 File->addSymbol(EncodeKind::GlobalSymbol, sym,929 CurrentSection.Targets,930 Flag | SymbolFlags::ThreadLocalValue);931 }932 };933 934 handleSymbols(Exports);935 handleSymbols(Reexports, SymbolFlags::Rexported);936 handleSymbols(Undefineds, SymbolFlags::Undefined);937 938 return File;939 }940 941 unsigned TBDVersion;942 std::vector<UUIDv4> UUIDs;943 TargetList Targets;944 StringRef InstallName;945 PackedVersion CurrentVersion;946 PackedVersion CompatibilityVersion;947 SwiftVersion SwiftABIVersion{0};948 std::vector<MetadataSection> AllowableClients;949 std::vector<MetadataSection> ReexportedLibraries;950 TBDFlags Flags{TBDFlags::None};951 std::vector<UmbrellaSection> ParentUmbrellas;952 SectionList Exports;953 SectionList Reexports;954 SectionList Undefineds;955 956 private:957 void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries,958 std::vector<MetadataSection> &Section) {959 std::set<TargetList> targetSet;960 std::map<const InterfaceFileRef *, TargetList> valueToTargetList;961 for (const auto &library : Libraries) {962 TargetList targets(library.targets());963 valueToTargetList[&library] = targets;964 targetSet.emplace(std::move(targets));965 }966 967 for (const auto &targets : targetSet) {968 MetadataSection CurrentSection;969 CurrentSection.Targets.insert(CurrentSection.Targets.begin(),970 targets.begin(), targets.end());971 972 for (const auto &it : valueToTargetList) {973 if (it.second != targets)974 continue;975 976 CurrentSection.Values.emplace_back(it.first->getInstallName());977 }978 llvm::sort(CurrentSection.Values);979 Section.emplace_back(std::move(CurrentSection));980 }981 }982 };983 984 static void mapKeysToValues(FileType FileKind, IO &IO,985 const InterfaceFile *&File) {986 MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);987 std::vector<UUID> EmptyUUID;988 IO.mapRequired("archs", Keys->Architectures);989 if (FileKind != FileType::TBD_V1)990 IO.mapOptional("uuids", EmptyUUID);991 IO.mapRequired("platform", Keys->Platforms);992 if (FileKind != FileType::TBD_V1)993 IO.mapOptional("flags", Keys->Flags, TBDFlags::None);994 IO.mapRequired("install-name", Keys->InstallName);995 IO.mapOptional("current-version", Keys->CurrentVersion,996 PackedVersion(1, 0, 0));997 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,998 PackedVersion(1, 0, 0));999 if (FileKind != FileType::TBD_V3)1000 IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));1001 else1002 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,1003 SwiftVersion(0));1004 IO.mapOptional("objc-constraint", Keys->ObjCConstraint,1005 (FileKind == FileType::TBD_V1)1006 ? ObjCConstraintType::None1007 : ObjCConstraintType::Retain_Release);1008 if (FileKind != FileType::TBD_V1)1009 IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());1010 IO.mapOptional("exports", Keys->Exports);1011 if (FileKind != FileType::TBD_V1)1012 IO.mapOptional("undefineds", Keys->Undefineds);1013 }1014 1015 static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) {1016 MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO,1017 File);1018 std::vector<UUIDv4> EmptyUUID;1019 IO.mapTag("!tapi-tbd", true);1020 IO.mapRequired("tbd-version", Keys->TBDVersion);1021 IO.mapRequired("targets", Keys->Targets);1022 IO.mapOptional("uuids", EmptyUUID);1023 IO.mapOptional("flags", Keys->Flags, TBDFlags::None);1024 IO.mapRequired("install-name", Keys->InstallName);1025 IO.mapOptional("current-version", Keys->CurrentVersion,1026 PackedVersion(1, 0, 0));1027 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,1028 PackedVersion(1, 0, 0));1029 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0));1030 IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas);1031 auto OptionKind = MetadataSection::Option::Clients;1032 IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients,1033 OptionKind);1034 OptionKind = MetadataSection::Option::Libraries;1035 IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries,1036 OptionKind);1037 IO.mapOptional("exports", Keys->Exports);1038 IO.mapOptional("reexports", Keys->Reexports);1039 IO.mapOptional("undefineds", Keys->Undefineds);1040 }1041};1042 1043template <>1044struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {1045 static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {1046 return Seq.size();1047 }1048 static const InterfaceFile *&1049 element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {1050 if (Index >= Seq.size())1051 Seq.resize(Index + 1);1052 return Seq[Index];1053 }1054};1055 1056} // end namespace yaml.1057} // namespace llvm1058 1059static void DiagHandler(const SMDiagnostic &Diag, void *Context) {1060 auto *File = static_cast<TextAPIContext *>(Context);1061 SmallString<1024> Message;1062 raw_svector_ostream S(Message);1063 1064 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,1065 Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),1066 Diag.getMessage(), Diag.getLineContents(),1067 Diag.getRanges(), Diag.getFixIts());1068 1069 NewDiag.print(nullptr, S);1070 File->ErrorMessage = ("malformed file\n" + Message).str();1071}1072 1073Expected<FileType> TextAPIReader::canRead(MemoryBufferRef InputBuffer) {1074 auto TAPIFile = InputBuffer.getBuffer().trim();1075 if (TAPIFile.starts_with("{") && TAPIFile.ends_with("}"))1076 return FileType::TBD_V5;1077 1078 if (!TAPIFile.ends_with("..."))1079 return createStringError(std::errc::not_supported, "unsupported file type");1080 1081 if (TAPIFile.starts_with("--- !tapi-tbd"))1082 return FileType::TBD_V4;1083 1084 if (TAPIFile.starts_with("--- !tapi-tbd-v3"))1085 return FileType::TBD_V3;1086 1087 if (TAPIFile.starts_with("--- !tapi-tbd-v2"))1088 return FileType::TBD_V2;1089 1090 if (TAPIFile.starts_with("--- !tapi-tbd-v1") ||1091 TAPIFile.starts_with("---\narchs:"))1092 return FileType::TBD_V1;1093 1094 return createStringError(std::errc::not_supported, "unsupported file type");1095}1096 1097Expected<std::unique_ptr<InterfaceFile>>1098TextAPIReader::get(MemoryBufferRef InputBuffer) {1099 TextAPIContext Ctx;1100 Ctx.Path = std::string(InputBuffer.getBufferIdentifier());1101 if (auto FTOrErr = canRead(InputBuffer))1102 Ctx.FileKind = *FTOrErr;1103 else1104 return FTOrErr.takeError();1105 1106 // Handle JSON Format.1107 if (Ctx.FileKind >= FileType::TBD_V5) {1108 auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer());1109 if (!FileOrErr)1110 return FileOrErr.takeError();1111 1112 (*FileOrErr)->setPath(Ctx.Path);1113 return std::move(*FileOrErr);1114 }1115 yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx);1116 1117 // Fill vector with interface file objects created by parsing the YAML file.1118 std::vector<const InterfaceFile *> Files;1119 YAMLIn >> Files;1120 1121 // YAMLIn dynamically allocates for Interface file and in case of error,1122 // memory leak will occur unless wrapped around unique_ptr1123 auto File = std::unique_ptr<InterfaceFile>(1124 const_cast<InterfaceFile *>(Files.front()));1125 1126 for (const InterfaceFile *FI : llvm::drop_begin(Files))1127 File->addDocument(1128 std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI)));1129 1130 if (YAMLIn.error())1131 return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());1132 1133 return std::move(File);1134}1135 1136Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File,1137 const FileType FileKind, bool Compact) {1138 TextAPIContext Ctx;1139 Ctx.Path = std::string(File.getPath());1140 1141 // Prefer parameter for format if passed, otherwise fallback to the File1142 // FileType.1143 Ctx.FileKind =1144 (FileKind == FileType::Invalid) ? File.getFileType() : FileKind;1145 1146 // Write out in JSON format.1147 if (Ctx.FileKind >= FileType::TBD_V5) {1148 return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact);1149 }1150 1151 llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);1152 1153 std::vector<const InterfaceFile *> Files;1154 Files.emplace_back(&File);1155 1156 for (const auto &Document : File.documents())1157 Files.emplace_back(Document.get());1158 1159 // Stream out yaml.1160 YAMLOut << Files;1161 1162 return Error::success();1163}1164