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