diff options
Diffstat (limited to 'llvm/lib/TextAPI/MachO')
| -rw-r--r-- | llvm/lib/TextAPI/MachO/Architecture.cpp | 81 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/ArchitectureSet.cpp | 69 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/InterfaceFile.cpp | 123 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/PackedVersion.cpp | 113 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/Platform.cpp | 91 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/Symbol.cpp | 58 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/Target.cpp | 75 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/TextAPIContext.h | 33 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/TextStub.cpp | 1144 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/TextStubCommon.cpp | 225 | ||||
| -rw-r--r-- | llvm/lib/TextAPI/MachO/TextStubCommon.h | 81 | 
11 files changed, 2093 insertions, 0 deletions
| diff --git a/llvm/lib/TextAPI/MachO/Architecture.cpp b/llvm/lib/TextAPI/MachO/Architecture.cpp new file mode 100644 index 000000000000..699fb5f4587a --- /dev/null +++ b/llvm/lib/TextAPI/MachO/Architecture.cpp @@ -0,0 +1,81 @@ +//===- Architecture.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements the architecture helper functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/MachO.h" + +namespace llvm { +namespace MachO { + +Architecture getArchitectureFromCpuType(uint32_t CPUType, uint32_t CPUSubType) { +#define ARCHINFO(Arch, Type, Subtype)                                          \ +  if (CPUType == (Type) &&                                                     \ +      (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) == (Subtype))                    \ +    return AK_##Arch; +#include "llvm/TextAPI/MachO/Architecture.def" +#undef ARCHINFO + +  return AK_unknown; +} + +Architecture getArchitectureFromName(StringRef Name) { +  return StringSwitch<Architecture>(Name) +#define ARCHINFO(Arch, Type, Subtype) .Case(#Arch, AK_##Arch) +#include "llvm/TextAPI/MachO/Architecture.def" +#undef ARCHINFO +      .Default(AK_unknown); +} + +StringRef getArchitectureName(Architecture Arch) { +  switch (Arch) { +#define ARCHINFO(Arch, Type, Subtype)                                          \ +  case AK_##Arch:                                                              \ +    return #Arch; +#include "llvm/TextAPI/MachO/Architecture.def" +#undef ARCHINFO +  case AK_unknown: +    return "unknown"; +  } + +  // Appease some compilers that cannot figure out that this is a fully covered +  // switch statement. +  return "unknown"; +} + +std::pair<uint32_t, uint32_t> getCPUTypeFromArchitecture(Architecture Arch) { +  switch (Arch) { +#define ARCHINFO(Arch, Type, Subtype)                                          \ +  case AK_##Arch:                                                              \ +    return std::make_pair(Type, Subtype); +#include "llvm/TextAPI/MachO/Architecture.def" +#undef ARCHINFO +  case AK_unknown: +    return std::make_pair(0, 0); +  } + +  // Appease some compilers that cannot figure out that this is a fully covered +  // switch statement. +  return std::make_pair(0, 0); +} + +Architecture mapToArchitecture(const Triple &Target) { +  return getArchitectureFromName(Target.getArchName()); +} + +raw_ostream &operator<<(raw_ostream &OS, Architecture Arch) { +  OS << getArchitectureName(Arch); +  return OS; +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/ArchitectureSet.cpp b/llvm/lib/TextAPI/MachO/ArchitectureSet.cpp new file mode 100644 index 000000000000..c589671199b7 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/ArchitectureSet.cpp @@ -0,0 +1,69 @@ +//===- ArchitectureSet.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements the architecture set. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/MachO/ArchitectureSet.h" + +namespace llvm { +namespace MachO { + +ArchitectureSet::ArchitectureSet(const std::vector<Architecture> &Archs) +    : ArchitectureSet() { +  for (auto Arch : Archs) { +    if (Arch == AK_unknown) +      continue; +    set(Arch); +  } +} + +size_t ArchitectureSet::count() const { +  // popcnt +  size_t Cnt = 0; +  for (unsigned i = 0; i < sizeof(ArchSetType) * 8; ++i) +    if (ArchSet & (1U << i)) +      ++Cnt; +  return Cnt; +} + +ArchitectureSet::operator std::string() const { +  if (empty()) +    return "[(empty)]"; + +  std::string result; +  auto size = count(); +  for (auto arch : *this) { +    result.append(getArchitectureName(arch)); +    size -= 1; +    if (size) +      result.append(" "); +  } +  return result; +} + +ArchitectureSet::operator std::vector<Architecture>() const { +  std::vector<Architecture> archs; +  for (auto arch : *this) { +    if (arch == AK_unknown) +      continue; +    archs.emplace_back(arch); +  } +  return archs; +} + +void ArchitectureSet::print(raw_ostream &os) const { os << std::string(*this); } + +raw_ostream &operator<<(raw_ostream &os, ArchitectureSet set) { +  set.print(os); +  return os; +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/InterfaceFile.cpp b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp new file mode 100644 index 000000000000..c40a952a6a8b --- /dev/null +++ b/llvm/lib/TextAPI/MachO/InterfaceFile.cpp @@ -0,0 +1,123 @@ +//===- InterfaceFile.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements the Interface File. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/MachO/InterfaceFile.h" +#include <iomanip> +#include <sstream> + +namespace llvm { +namespace MachO { +namespace detail { +template <typename C> +typename C::iterator addEntry(C &Container, StringRef InstallName) { +  auto I = partition_point(Container, [=](const InterfaceFileRef &O) { +    return O.getInstallName() < InstallName; +  }); +  if (I != Container.end() && I->getInstallName() == InstallName) +    return I; + +  return Container.emplace(I, InstallName); +} + +template <typename C> +typename C::iterator addEntry(C &Container, const Target &Target_) { +  auto Iter = +      lower_bound(Container, Target_, [](const Target &LHS, const Target &RHS) { +        return LHS < RHS; +      }); +  if ((Iter != std::end(Container)) && !(Target_ < *Iter)) +    return Iter; + +  return Container.insert(Iter, Target_); +} +} // end namespace detail. + +void InterfaceFileRef::addTarget(const Target &Target) { +  detail::addEntry(Targets, Target); +} + +void InterfaceFile::addAllowableClient(StringRef InstallName, +                                       const Target &Target) { +  auto Client = detail::addEntry(AllowableClients, InstallName); +  Client->addTarget(Target); +} + +void InterfaceFile::addReexportedLibrary(StringRef InstallName, +                                         const Target &Target) { +  auto Lib = detail::addEntry(ReexportedLibraries, InstallName); +  Lib->addTarget(Target); +} + +void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) { +  auto Iter = lower_bound(ParentUmbrellas, Target_, +                          [](const std::pair<Target, std::string> &LHS, +                             Target RHS) { return LHS.first < RHS; }); + +  if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) { +    Iter->second = Parent; +    return; +  } + +  ParentUmbrellas.emplace(Iter, Target_, Parent); +  return; +} + +void InterfaceFile::addUUID(const Target &Target_, StringRef UUID) { +  auto Iter = lower_bound(UUIDs, Target_, +                          [](const std::pair<Target, std::string> &LHS, +                             Target RHS) { return LHS.first < RHS; }); + +  if ((Iter != UUIDs.end()) && !(Target_ < Iter->first)) { +    Iter->second = UUID; +    return; +  } + +  UUIDs.emplace(Iter, Target_, UUID); +  return; +} + +void InterfaceFile::addUUID(const Target &Target, uint8_t UUID[16]) { +  std::stringstream Stream; +  for (unsigned i = 0; i < 16; ++i) { +    if (i == 4 || i == 6 || i == 8 || i == 10) +      Stream << '-'; +    Stream << std::setfill('0') << std::setw(2) << std::uppercase << std::hex +           << static_cast<int>(UUID[i]); +  } +  addUUID(Target, Stream.str()); +} + +void InterfaceFile::addTarget(const Target &Target) { +  detail::addEntry(Targets, Target); +} + +InterfaceFile::const_filtered_target_range +InterfaceFile::targets(ArchitectureSet Archs) const { +  std::function<bool(const Target &)> fn = [Archs](const Target &Target_) { +    return Archs.has(Target_.Arch); +  }; +  return make_filter_range(Targets, fn); +} + +void InterfaceFile::addSymbol(SymbolKind Kind, StringRef Name, +                              const TargetList &Targets, SymbolFlags Flags) { +  Name = copyString(Name); +  auto result = Symbols.try_emplace(SymbolsMapKey{Kind, Name}, nullptr); +  if (result.second) +    result.first->second = new (Allocator) Symbol{Kind, Name, Targets, Flags}; +  else +    for (const auto &Target : Targets) +      result.first->second->addTarget(Target); +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/PackedVersion.cpp b/llvm/lib/TextAPI/MachO/PackedVersion.cpp new file mode 100644 index 000000000000..8405aba90ed6 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/PackedVersion.cpp @@ -0,0 +1,113 @@ +//===- PackedVersion.cpp --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements the Mach-O packed version. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/MachO/PackedVersion.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace MachO { + +bool PackedVersion::parse32(StringRef Str) { +  Version = 0; + +  if (Str.empty()) +    return false; + +  SmallVector<StringRef, 3> Parts; +  SplitString(Str, Parts, "."); + +  if (Parts.size() > 3) +    return false; + +  unsigned long long Num; +  if (getAsUnsignedInteger(Parts[0], 10, Num)) +    return false; + +  if (Num > UINT16_MAX) +    return false; + +  Version = Num << 16; + +  for (unsigned i = 1, ShiftNum = 8; i < Parts.size(); ++i, ShiftNum -= 8) { +    if (getAsUnsignedInteger(Parts[i], 10, Num)) +      return false; + +    if (Num > UINT8_MAX) +      return false; + +    Version |= (Num << ShiftNum); +  } + +  return true; +} + +std::pair<bool, bool> PackedVersion::parse64(StringRef Str) { +  bool Truncated = false; +  Version = 0; + +  if (Str.empty()) +    return std::make_pair(false, Truncated); + +  SmallVector<StringRef, 5> Parts; +  SplitString(Str, Parts, "."); + +  if (Parts.size() > 5) +    return std::make_pair(false, Truncated); + +  unsigned long long Num; +  if (getAsUnsignedInteger(Parts[0], 10, Num)) +    return std::make_pair(false, Truncated); + +  if (Num > 0xFFFFFFULL) +    return std::make_pair(false, Truncated); + +  if (Num > 0xFFFFULL) { +    Num = 0xFFFFULL; +    Truncated = true; +  } +  Version = Num << 16; + +  for (unsigned i = 1, ShiftNum = 8; i < Parts.size() && i < 3; +       ++i, ShiftNum -= 8) { +    if (getAsUnsignedInteger(Parts[i], 10, Num)) +      return std::make_pair(false, Truncated); + +    if (Num > 0x3FFULL) +      return std::make_pair(false, Truncated); + +    if (Num > 0xFFULL) { +      Num = 0xFFULL; +      Truncated = true; +    } +    Version |= (Num << ShiftNum); +  } + +  if (Parts.size() > 3) +    Truncated = true; + +  return std::make_pair(true, Truncated); +} + +void PackedVersion::print(raw_ostream &OS) const { +  OS << format("%d", getMajor()); +  if (getMinor() || getSubminor()) +    OS << format(".%d", getMinor()); +  if (getSubminor()) +    OS << format(".%d", getSubminor()); +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/Platform.cpp b/llvm/lib/TextAPI/MachO/Platform.cpp new file mode 100644 index 000000000000..588ec9a4d83b --- /dev/null +++ b/llvm/lib/TextAPI/MachO/Platform.cpp @@ -0,0 +1,91 @@ +//===- llvm/TextAPI/MachO/Platform.cpp - Platform ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implementations of Platform Helper functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/TextAPI/MachO/Platform.h" + +namespace llvm { +namespace MachO { + +PlatformKind mapToPlatformKind(PlatformKind Platform, bool WantSim) { +  switch (Platform) { +  default: +    return Platform; +  case PlatformKind::iOS: +    return WantSim ? PlatformKind::iOSSimulator : PlatformKind::iOS; +  case PlatformKind::tvOS: +    return WantSim ? PlatformKind::tvOSSimulator : PlatformKind::tvOS; +  case PlatformKind::watchOS: +    return WantSim ? PlatformKind::watchOSSimulator : PlatformKind::watchOS; +  } +  llvm_unreachable("Unknown llvm.MachO.PlatformKind enum"); +} + +PlatformKind mapToPlatformKind(const Triple &Target) { +  switch (Target.getOS()) { +  default: +    return PlatformKind::unknown; +  case Triple::MacOSX: +    return PlatformKind::macOS; +  case Triple::IOS: +    if (Target.isSimulatorEnvironment()) +      return PlatformKind::iOSSimulator; +    if (Target.getEnvironment() == Triple::MacABI) +      return PlatformKind::macCatalyst; +    return PlatformKind::iOS; +  case Triple::TvOS: +    return Target.isSimulatorEnvironment() ? PlatformKind::tvOSSimulator +                                           : PlatformKind::tvOS; +  case Triple::WatchOS: +    return Target.isSimulatorEnvironment() ? PlatformKind::watchOSSimulator +                                           : PlatformKind::watchOS; +    // TODO: add bridgeOS once in llvm::Triple +  } +  llvm_unreachable("Unknown Target Triple"); +} + +PlatformSet mapToPlatformSet(ArrayRef<Triple> Targets) { +  PlatformSet Result; +  for (const auto &Target : Targets) +    Result.insert(mapToPlatformKind(Target)); +  return Result; +} + +StringRef getPlatformName(PlatformKind Platform) { +  switch (Platform) { +  case PlatformKind::unknown: +    return "unknown"; +  case PlatformKind::macOS: +    return "macOS"; +  case PlatformKind::iOS: +    return "iOS"; +  case PlatformKind::tvOS: +    return "tvOS"; +  case PlatformKind::watchOS: +    return "watchOS"; +  case PlatformKind::bridgeOS: +    return "bridgeOS"; +  case PlatformKind::macCatalyst: +    return "macCatalyst"; +  case PlatformKind::iOSSimulator: +    return "iOS Simulator"; +  case PlatformKind::tvOSSimulator: +    return "tvOS Simulator"; +  case PlatformKind::watchOSSimulator: +    return "watchOS Simulator"; +  } +  llvm_unreachable("Unknown llvm.MachO.PlatformKind enum"); +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/Symbol.cpp b/llvm/lib/TextAPI/MachO/Symbol.cpp new file mode 100644 index 000000000000..9f2d8172beed --- /dev/null +++ b/llvm/lib/TextAPI/MachO/Symbol.cpp @@ -0,0 +1,58 @@ +//===- Symbol.cpp ---------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements the Symbol. +// +//===----------------------------------------------------------------------===// + +#include "llvm/TextAPI/MachO/Symbol.h" +#include <string> + +namespace llvm { +namespace MachO { + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void Symbol::dump(raw_ostream &OS) const { +  std::string Result; +  if (isUndefined()) +    Result += "(undef) "; +  if (isWeakDefined()) +    Result += "(weak-def) "; +  if (isWeakReferenced()) +    Result += "(weak-ref) "; +  if (isThreadLocalValue()) +    Result += "(tlv) "; +  switch (Kind) { +  case SymbolKind::GlobalSymbol: +    Result += Name.str(); +    break; +  case SymbolKind::ObjectiveCClass: +    Result += "(ObjC Class) " + Name.str(); +    break; +  case SymbolKind::ObjectiveCClassEHType: +    Result += "(ObjC Class EH) " + Name.str(); +    break; +  case SymbolKind::ObjectiveCInstanceVariable: +    Result += "(ObjC IVar) " + Name.str(); +    break; +  } +  OS << Result; +} +#endif + +Symbol::const_filtered_target_range +Symbol::targets(ArchitectureSet Architectures) const { +  std::function<bool(const Target &)> FN = +      [Architectures](const Target &Target) { +        return Architectures.has(Target.Arch); +      }; +  return make_filter_range(Targets, FN); +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/Target.cpp b/llvm/lib/TextAPI/MachO/Target.cpp new file mode 100644 index 000000000000..aee8ef421425 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/Target.cpp @@ -0,0 +1,75 @@ +//===- tapi/Core/Target.cpp - Target ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TextAPI/MachO/Target.h" + +namespace llvm { +namespace MachO { + +Expected<Target> Target::create(StringRef TargetValue) { +  auto Result = TargetValue.split('-'); +  auto ArchitectureStr = Result.first; +  auto Architecture = getArchitectureFromName(ArchitectureStr); +  auto PlatformStr = Result.second; +  PlatformKind Platform; +  Platform = StringSwitch<PlatformKind>(PlatformStr) +                 .Case("macos", PlatformKind::macOS) +                 .Case("ios", PlatformKind::iOS) +                 .Case("tvos", PlatformKind::tvOS) +                 .Case("watchos", PlatformKind::watchOS) +                 .Case("bridgeos", PlatformKind::bridgeOS) +                 .Case("maccatalyst", PlatformKind::macCatalyst) +                 .Case("ios-simulator", PlatformKind::iOSSimulator) +                 .Case("tvos-simulator", PlatformKind::tvOSSimulator) +                 .Case("watchos-simulator", PlatformKind::watchOSSimulator) +                 .Default(PlatformKind::unknown); + +  if (Platform == PlatformKind::unknown) { +    if (PlatformStr.startswith("<") && PlatformStr.endswith(">")) { +      PlatformStr = PlatformStr.drop_front().drop_back(); +      unsigned long long RawValue; +      if (!PlatformStr.getAsInteger(10, RawValue)) +        Platform = (PlatformKind)RawValue; +    } +  } + +  return Target{Architecture, Platform}; +} + +Target::operator std::string() const { +  return (getArchitectureName(Arch) + " (" + getPlatformName(Platform) + ")") +      .str(); +} + +raw_ostream &operator<<(raw_ostream &OS, const Target &Target) { +  OS << std::string(Target); +  return OS; +} + +PlatformSet mapToPlatformSet(ArrayRef<Target> Targets) { +  PlatformSet Result; +  for (const auto &Target : Targets) +    Result.insert(Target.Platform); +  return Result; +} + +ArchitectureSet mapToArchitectureSet(ArrayRef<Target> Targets) { +  ArchitectureSet Result; +  for (const auto &Target : Targets) +    Result.set(Target.Arch); +  return Result; +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/TextAPIContext.h b/llvm/lib/TextAPI/MachO/TextAPIContext.h new file mode 100644 index 000000000000..3df40f09f7f7 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/TextAPIContext.h @@ -0,0 +1,33 @@ +//===- TextAPIContext.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines the YAML Context for the TextAPI Reader/Writer. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TEXTAPI_MACHO_CONTEXT_H +#define LLVM_TEXTAPI_MACHO_CONTEXT_H + +#include "llvm/Support/MemoryBuffer.h" +#include <string> + +namespace llvm { +namespace MachO { + +enum FileType : unsigned; + +struct TextAPIContext { +  std::string ErrorMessage; +  std::string Path; +  FileType FileKind; +}; + +} // end namespace MachO. +} // end namespace llvm. + +#endif // LLVM_TEXTAPI_MACHO_CONTEXT_H diff --git a/llvm/lib/TextAPI/MachO/TextStub.cpp b/llvm/lib/TextAPI/MachO/TextStub.cpp new file mode 100644 index 000000000000..0584e43d5893 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/TextStub.cpp @@ -0,0 +1,1144 @@ +//===- TextStub.cpp -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implements the text stub file reader/writer. +// +//===----------------------------------------------------------------------===// + +#include "TextAPIContext.h" +#include "TextStubCommon.h" +#include "llvm/ADT/BitmaskEnum.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/TextAPI/MachO/ArchitectureSet.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" +#include "llvm/TextAPI/MachO/PackedVersion.h" +#include "llvm/TextAPI/MachO/TextAPIReader.h" +#include "llvm/TextAPI/MachO/TextAPIWriter.h" +#include <algorithm> +#include <set> + +// clang-format off +/* + + YAML Format specification. + + The TBD v1 format only support two level address libraries and is per + definition application extension safe. + +---                              # the tag !tapi-tbd-v1 is optional and +                                 # shouldn't be emitted to support older linker. +archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are +                                 # supported by this file. +platform: ios                    # Specifies the platform (macosx, ios, etc) +install-name: /u/l/libfoo.dylib  # +current-version: 1.2.3           # Optional: defaults to 1.0 +compatibility-version: 1.0       # Optional: defaults to 1.0 +swift-version: 0                 # Optional: defaults to 0 +objc-constraint: none            # Optional: defaults to none +exports:                         # List of export sections +... + +Each export section is defined as following: + + - archs: [ arm64 ]                   # the list of architecture slices +   allowed-clients: [ client ]        # Optional: List of clients +   re-exports: [ ]                    # Optional: List of re-exports +   symbols: [ _sym ]                  # Optional: List of symbols +   objc-classes: []                   # Optional: List of Objective-C classes +   objc-ivars: []                     # Optional: List of Objective C Instance +                                      #           Variables +   weak-def-symbols: []               # Optional: List of weak defined symbols +   thread-local-symbols: []           # Optional: List of thread local symbols +*/ + +/* + + YAML Format specification. + +--- !tapi-tbd-v2 +archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are +                                 # supported by this file. +uuids: [ armv7:... ]             # Optional: List of architecture and UUID pairs. +platform: ios                    # Specifies the platform (macosx, ios, etc) +flags: []                        # Optional: +install-name: /u/l/libfoo.dylib  # +current-version: 1.2.3           # Optional: defaults to 1.0 +compatibility-version: 1.0       # Optional: defaults to 1.0 +swift-version: 0                 # Optional: defaults to 0 +objc-constraint: retain_release  # Optional: defaults to retain_release +parent-umbrella:                 # Optional: +exports:                         # List of export sections +... +undefineds:                      # List of undefineds sections +... + +Each export section is defined as following: + +- archs: [ arm64 ]                   # the list of architecture slices +  allowed-clients: [ client ]        # Optional: List of clients +  re-exports: [ ]                    # Optional: List of re-exports +  symbols: [ _sym ]                  # Optional: List of symbols +  objc-classes: []                   # Optional: List of Objective-C classes +  objc-ivars: []                     # Optional: List of Objective C Instance +                                     #           Variables +  weak-def-symbols: []               # Optional: List of weak defined symbols +  thread-local-symbols: []           # Optional: List of thread local symbols + +Each undefineds section is defined as following: +- archs: [ arm64 ]     # the list of architecture slices +  symbols: [ _sym ]    # Optional: List of symbols +  objc-classes: []     # Optional: List of Objective-C classes +  objc-ivars: []       # Optional: List of Objective C Instance Variables +  weak-ref-symbols: [] # Optional: List of weak defined symbols +*/ + +/* + + YAML Format specification. + +--- !tapi-tbd-v3 +archs: [ armv7, armv7s, arm64 ]  # the list of architecture slices that are +                                 # supported by this file. +uuids: [ armv7:... ]             # Optional: List of architecture and UUID pairs. +platform: ios                    # Specifies the platform (macosx, ios, etc) +flags: []                        # Optional: +install-name: /u/l/libfoo.dylib  # +current-version: 1.2.3           # Optional: defaults to 1.0 +compatibility-version: 1.0       # Optional: defaults to 1.0 +swift-abi-version: 0             # Optional: defaults to 0 +objc-constraint: retain_release  # Optional: defaults to retain_release +parent-umbrella:                 # Optional: +exports:                         # List of export sections +... +undefineds:                      # List of undefineds sections +... + +Each export section is defined as following: + +- archs: [ arm64 ]                   # the list of architecture slices +  allowed-clients: [ client ]        # Optional: List of clients +  re-exports: [ ]                    # Optional: List of re-exports +  symbols: [ _sym ]                  # Optional: List of symbols +  objc-classes: []                   # Optional: List of Objective-C classes +  objc-eh-types: []                  # Optional: List of Objective-C classes +                                     #           with EH +  objc-ivars: []                     # Optional: List of Objective C Instance +                                     #           Variables +  weak-def-symbols: []               # Optional: List of weak defined symbols +  thread-local-symbols: []           # Optional: List of thread local symbols + +Each undefineds section is defined as following: +- archs: [ arm64 ]     # the list of architecture slices +  symbols: [ _sym ]    # Optional: List of symbols +  objc-classes: []     # Optional: List of Objective-C classes +  objc-eh-types: []                  # Optional: List of Objective-C classes +                                     #           with EH +  objc-ivars: []       # Optional: List of Objective C Instance Variables +  weak-ref-symbols: [] # Optional: List of weak defined symbols +*/ + +/* + + YAML Format specification. + +--- !tapi-tbd +tbd-version: 4                              # The tbd version for format +targets: [ armv7-ios, x86_64-maccatalyst ]  # The list of applicable tapi supported target triples +uuids:                                      # Optional: List of target and UUID pairs. +  - target: armv7-ios +    value: ... +  - target: x86_64-maccatalyst +    value: ... +flags: []                        # Optional: +install-name: /u/l/libfoo.dylib  # +current-version: 1.2.3           # Optional: defaults to 1.0 +compatibility-version: 1.0       # Optional: defaults to 1.0 +swift-abi-version: 0             # Optional: defaults to 0 +parent-umbrella:                 # Optional: +allowable-clients: +  - targets: [ armv7-ios ]       # Optional: +    clients: [ clientA ] +exports:                         # List of export sections +... +re-exports:                      # List of reexport sections +... +undefineds:                      # List of undefineds sections +... + +Each export and reexport  section is defined as following: + +- targets: [ arm64-macos ]                        # The list of target triples associated with symbols +  symbols: [ _symA ]                              # Optional: List of symbols +  objc-classes: []                                # Optional: List of Objective-C classes +  objc-eh-types: []                               # Optional: List of Objective-C classes +                                                  #           with EH +  objc-ivars: []                                  # Optional: List of Objective C Instance +                                                  #           Variables +  weak-symbols: []                                # Optional: List of weak defined symbols +  thread-local-symbols: []                        # Optional: List of thread local symbols +- targets: [ arm64-macos, x86_64-maccatalyst ]    # Optional: Targets for applicable additional symbols +  symbols: [ _symB ]                              # Optional: List of symbols + +Each undefineds section is defined as following: +- targets: [ arm64-macos ]    # The list of target triples associated with symbols +  symbols: [ _symC ]          # Optional: List of symbols +  objc-classes: []            # Optional: List of Objective-C classes +  objc-eh-types: []           # Optional: List of Objective-C classes +                              #           with EH +  objc-ivars: []              # Optional: List of Objective C Instance Variables +  weak-symbols: []            # Optional: List of weak defined symbols +*/ +// clang-format on + +using namespace llvm; +using namespace llvm::yaml; +using namespace llvm::MachO; + +namespace { +struct ExportSection { +  std::vector<Architecture> Architectures; +  std::vector<FlowStringRef> AllowableClients; +  std::vector<FlowStringRef> ReexportedLibraries; +  std::vector<FlowStringRef> Symbols; +  std::vector<FlowStringRef> Classes; +  std::vector<FlowStringRef> ClassEHs; +  std::vector<FlowStringRef> IVars; +  std::vector<FlowStringRef> WeakDefSymbols; +  std::vector<FlowStringRef> TLVSymbols; +}; + +struct UndefinedSection { +  std::vector<Architecture> Architectures; +  std::vector<FlowStringRef> Symbols; +  std::vector<FlowStringRef> Classes; +  std::vector<FlowStringRef> ClassEHs; +  std::vector<FlowStringRef> IVars; +  std::vector<FlowStringRef> WeakRefSymbols; +}; + +// Sections for direct target mapping in TBDv4 +struct SymbolSection { +  TargetList Targets; +  std::vector<FlowStringRef> Symbols; +  std::vector<FlowStringRef> Classes; +  std::vector<FlowStringRef> ClassEHs; +  std::vector<FlowStringRef> Ivars; +  std::vector<FlowStringRef> WeakSymbols; +  std::vector<FlowStringRef> TlvSymbols; +}; + +struct MetadataSection { +  enum Option { Clients, Libraries }; +  std::vector<Target> Targets; +  std::vector<FlowStringRef> Values; +}; + +struct UmbrellaSection { +  std::vector<Target> Targets; +  std::string Umbrella; +}; + +// UUID's for TBDv4 are mapped to target not arch +struct UUIDv4 { +  Target TargetID; +  std::string Value; + +  UUIDv4() = default; +  UUIDv4(const Target &TargetID, const std::string &Value) +      : TargetID(TargetID), Value(Value) {} +}; + +// clang-format off +enum TBDFlags : unsigned { +  None                         = 0U, +  FlatNamespace                = 1U << 0, +  NotApplicationExtensionSafe  = 1U << 1, +  InstallAPI                   = 1U << 2, +  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI), +}; +// clang-format on +} // end anonymous namespace. + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture) +LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection) +LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection) +// Specific to TBDv4 +LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection) +LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection) +LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target) +LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits<ExportSection> { +  static void mapping(IO &IO, ExportSection &Section) { +    const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); +    assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) && +           "File type is not set in YAML context"); + +    IO.mapRequired("archs", Section.Architectures); +    if (Ctx->FileKind == FileType::TBD_V1) +      IO.mapOptional("allowed-clients", Section.AllowableClients); +    else +      IO.mapOptional("allowable-clients", Section.AllowableClients); +    IO.mapOptional("re-exports", Section.ReexportedLibraries); +    IO.mapOptional("symbols", Section.Symbols); +    IO.mapOptional("objc-classes", Section.Classes); +    if (Ctx->FileKind == FileType::TBD_V3) +      IO.mapOptional("objc-eh-types", Section.ClassEHs); +    IO.mapOptional("objc-ivars", Section.IVars); +    IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols); +    IO.mapOptional("thread-local-symbols", Section.TLVSymbols); +  } +}; + +template <> struct MappingTraits<UndefinedSection> { +  static void mapping(IO &IO, UndefinedSection &Section) { +    const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); +    assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) && +           "File type is not set in YAML context"); + +    IO.mapRequired("archs", Section.Architectures); +    IO.mapOptional("symbols", Section.Symbols); +    IO.mapOptional("objc-classes", Section.Classes); +    if (Ctx->FileKind == FileType::TBD_V3) +      IO.mapOptional("objc-eh-types", Section.ClassEHs); +    IO.mapOptional("objc-ivars", Section.IVars); +    IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols); +  } +}; + +template <> struct MappingTraits<SymbolSection> { +  static void mapping(IO &IO, SymbolSection &Section) { +    IO.mapRequired("targets", Section.Targets); +    IO.mapOptional("symbols", Section.Symbols); +    IO.mapOptional("objc-classes", Section.Classes); +    IO.mapOptional("objc-eh-types", Section.ClassEHs); +    IO.mapOptional("objc-ivars", Section.Ivars); +    IO.mapOptional("weak-symbols", Section.WeakSymbols); +    IO.mapOptional("thread-local-symbols", Section.TlvSymbols); +  } +}; + +template <> struct MappingTraits<UmbrellaSection> { +  static void mapping(IO &IO, UmbrellaSection &Section) { +    IO.mapRequired("targets", Section.Targets); +    IO.mapRequired("umbrella", Section.Umbrella); +  } +}; + +template <> struct MappingTraits<UUIDv4> { +  static void mapping(IO &IO, UUIDv4 &UUID) { +    IO.mapRequired("target", UUID.TargetID); +    IO.mapRequired("value", UUID.Value); +  } +}; + +template <> +struct MappingContextTraits<MetadataSection, MetadataSection::Option> { +  static void mapping(IO &IO, MetadataSection &Section, +                      MetadataSection::Option &OptionKind) { +    IO.mapRequired("targets", Section.Targets); +    switch (OptionKind) { +    case MetadataSection::Option::Clients: +      IO.mapRequired("clients", Section.Values); +      return; +    case MetadataSection::Option::Libraries: +      IO.mapRequired("libraries", Section.Values); +      return; +    } +    llvm_unreachable("unexpected option for metadata"); +  } +}; + +template <> struct ScalarBitSetTraits<TBDFlags> { +  static void bitset(IO &IO, TBDFlags &Flags) { +    IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace); +    IO.bitSetCase(Flags, "not_app_extension_safe", +                  TBDFlags::NotApplicationExtensionSafe); +    IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI); +  } +}; + +template <> struct ScalarTraits<Target> { +  static void output(const Target &Value, void *, raw_ostream &OS) { +    OS << Value.Arch << "-"; +    switch (Value.Platform) { +    default: +      OS << "unknown"; +      break; +    case PlatformKind::macOS: +      OS << "macos"; +      break; +    case PlatformKind::iOS: +      OS << "ios"; +      break; +    case PlatformKind::tvOS: +      OS << "tvos"; +      break; +    case PlatformKind::watchOS: +      OS << "watchos"; +      break; +    case PlatformKind::bridgeOS: +      OS << "bridgeos"; +      break; +    case PlatformKind::macCatalyst: +      OS << "maccatalyst"; +      break; +    case PlatformKind::iOSSimulator: +      OS << "ios-simulator"; +      break; +    case PlatformKind::tvOSSimulator: +      OS << "tvos-simulator"; +      break; +    case PlatformKind::watchOSSimulator: +      OS << "watchos-simulator"; +      break; +    } +  } + +  static StringRef input(StringRef Scalar, void *, Target &Value) { +    auto Result = Target::create(Scalar); +    if (!Result) +      return toString(Result.takeError()); + +    Value = *Result; +    if (Value.Arch == AK_unknown) +      return "unknown architecture"; +    if (Value.Platform == PlatformKind::unknown) +      return "unknown platform"; + +    return {}; +  } + +  static QuotingType mustQuote(StringRef) { return QuotingType::None; } +}; + +template <> struct MappingTraits<const InterfaceFile *> { +  struct NormalizedTBD { +    explicit NormalizedTBD(IO &IO) {} +    NormalizedTBD(IO &IO, const InterfaceFile *&File) { +      Architectures = File->getArchitectures(); +      UUIDs = File->uuids(); +      Platforms = File->getPlatforms(); +      InstallName = File->getInstallName(); +      CurrentVersion = PackedVersion(File->getCurrentVersion()); +      CompatibilityVersion = PackedVersion(File->getCompatibilityVersion()); +      SwiftABIVersion = File->getSwiftABIVersion(); +      ObjCConstraint = File->getObjCConstraint(); + +      Flags = TBDFlags::None; +      if (!File->isApplicationExtensionSafe()) +        Flags |= TBDFlags::NotApplicationExtensionSafe; + +      if (!File->isTwoLevelNamespace()) +        Flags |= TBDFlags::FlatNamespace; + +      if (File->isInstallAPI()) +        Flags |= TBDFlags::InstallAPI; + +      for (const auto &Iter : File->umbrellas()) { +        ParentUmbrella = Iter.second; +        break; +      } + +      std::set<ArchitectureSet> ArchSet; +      for (const auto &Library : File->allowableClients()) +        ArchSet.insert(Library.getArchitectures()); + +      for (const auto &Library : File->reexportedLibraries()) +        ArchSet.insert(Library.getArchitectures()); + +      std::map<const Symbol *, ArchitectureSet> SymbolToArchSet; +      for (const auto *Symbol : File->exports()) { +        auto Architectures = Symbol->getArchitectures(); +        SymbolToArchSet[Symbol] = Architectures; +        ArchSet.insert(Architectures); +      } + +      for (auto Architectures : ArchSet) { +        ExportSection Section; +        Section.Architectures = Architectures; + +        for (const auto &Library : File->allowableClients()) +          if (Library.getArchitectures() == Architectures) +            Section.AllowableClients.emplace_back(Library.getInstallName()); + +        for (const auto &Library : File->reexportedLibraries()) +          if (Library.getArchitectures() == Architectures) +            Section.ReexportedLibraries.emplace_back(Library.getInstallName()); + +        for (const auto &SymArch : SymbolToArchSet) { +          if (SymArch.second != Architectures) +            continue; + +          const auto *Symbol = SymArch.first; +          switch (Symbol->getKind()) { +          case SymbolKind::GlobalSymbol: +            if (Symbol->isWeakDefined()) +              Section.WeakDefSymbols.emplace_back(Symbol->getName()); +            else if (Symbol->isThreadLocalValue()) +              Section.TLVSymbols.emplace_back(Symbol->getName()); +            else +              Section.Symbols.emplace_back(Symbol->getName()); +            break; +          case SymbolKind::ObjectiveCClass: +            if (File->getFileType() != FileType::TBD_V3) +              Section.Classes.emplace_back( +                  copyString("_" + Symbol->getName().str())); +            else +              Section.Classes.emplace_back(Symbol->getName()); +            break; +          case SymbolKind::ObjectiveCClassEHType: +            if (File->getFileType() != FileType::TBD_V3) +              Section.Symbols.emplace_back( +                  copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); +            else +              Section.ClassEHs.emplace_back(Symbol->getName()); +            break; +          case SymbolKind::ObjectiveCInstanceVariable: +            if (File->getFileType() != FileType::TBD_V3) +              Section.IVars.emplace_back( +                  copyString("_" + Symbol->getName().str())); +            else +              Section.IVars.emplace_back(Symbol->getName()); +            break; +          } +        } +        llvm::sort(Section.Symbols.begin(), Section.Symbols.end()); +        llvm::sort(Section.Classes.begin(), Section.Classes.end()); +        llvm::sort(Section.ClassEHs.begin(), Section.ClassEHs.end()); +        llvm::sort(Section.IVars.begin(), Section.IVars.end()); +        llvm::sort(Section.WeakDefSymbols.begin(), +                   Section.WeakDefSymbols.end()); +        llvm::sort(Section.TLVSymbols.begin(), Section.TLVSymbols.end()); +        Exports.emplace_back(std::move(Section)); +      } + +      ArchSet.clear(); +      SymbolToArchSet.clear(); + +      for (const auto *Symbol : File->undefineds()) { +        auto Architectures = Symbol->getArchitectures(); +        SymbolToArchSet[Symbol] = Architectures; +        ArchSet.insert(Architectures); +      } + +      for (auto Architectures : ArchSet) { +        UndefinedSection Section; +        Section.Architectures = Architectures; + +        for (const auto &SymArch : SymbolToArchSet) { +          if (SymArch.second != Architectures) +            continue; + +          const auto *Symbol = SymArch.first; +          switch (Symbol->getKind()) { +          case SymbolKind::GlobalSymbol: +            if (Symbol->isWeakReferenced()) +              Section.WeakRefSymbols.emplace_back(Symbol->getName()); +            else +              Section.Symbols.emplace_back(Symbol->getName()); +            break; +          case SymbolKind::ObjectiveCClass: +            if (File->getFileType() != FileType::TBD_V3) +              Section.Classes.emplace_back( +                  copyString("_" + Symbol->getName().str())); +            else +              Section.Classes.emplace_back(Symbol->getName()); +            break; +          case SymbolKind::ObjectiveCClassEHType: +            if (File->getFileType() != FileType::TBD_V3) +              Section.Symbols.emplace_back( +                  copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); +            else +              Section.ClassEHs.emplace_back(Symbol->getName()); +            break; +          case SymbolKind::ObjectiveCInstanceVariable: +            if (File->getFileType() != FileType::TBD_V3) +              Section.IVars.emplace_back( +                  copyString("_" + Symbol->getName().str())); +            else +              Section.IVars.emplace_back(Symbol->getName()); +            break; +          } +        } +        llvm::sort(Section.Symbols.begin(), Section.Symbols.end()); +        llvm::sort(Section.Classes.begin(), Section.Classes.end()); +        llvm::sort(Section.ClassEHs.begin(), Section.ClassEHs.end()); +        llvm::sort(Section.IVars.begin(), Section.IVars.end()); +        llvm::sort(Section.WeakRefSymbols.begin(), +                   Section.WeakRefSymbols.end()); +        Undefineds.emplace_back(std::move(Section)); +      } +    } + +    // TBD v1 - TBD v3 files only support one platform and several +    // architectures. It is possible to have more than one platform for TBD v3 +    // files, but the architectures don't apply to all +    // platforms, specifically to filter out the i386 slice from +    // platform macCatalyst. +    TargetList synthesizeTargets(ArchitectureSet Architectures, +                                          const PlatformSet &Platforms) { +      TargetList Targets; + +      for (auto Platform : Platforms) { +        Platform = mapToPlatformKind(Platform, Architectures.hasX86()); + +        for (const auto &&Architecture : Architectures) { +          if ((Architecture == AK_i386) && +              (Platform == PlatformKind::macCatalyst)) +            continue; + +          Targets.emplace_back(Architecture, Platform); +        } +      } +      return Targets; +    } + +    const InterfaceFile *denormalize(IO &IO) { +      auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); +      assert(Ctx); + +      auto *File = new InterfaceFile; +      File->setPath(Ctx->Path); +      File->setFileType(Ctx->FileKind); +      File->addTargets(synthesizeTargets(Architectures, Platforms)); +      for (auto &ID : UUIDs) +        File->addUUID(ID.first, ID.second); +      File->setInstallName(InstallName); +      File->setCurrentVersion(CurrentVersion); +      File->setCompatibilityVersion(CompatibilityVersion); +      File->setSwiftABIVersion(SwiftABIVersion); +      File->setObjCConstraint(ObjCConstraint); +      for (const auto &Target : File->targets()) +        File->addParentUmbrella(Target, ParentUmbrella); + +      if (Ctx->FileKind == FileType::TBD_V1) { +        File->setTwoLevelNamespace(); +        File->setApplicationExtensionSafe(); +      } else { +        File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); +        File->setApplicationExtensionSafe( +            !(Flags & TBDFlags::NotApplicationExtensionSafe)); +        File->setInstallAPI(Flags & TBDFlags::InstallAPI); +      } + +      for (const auto &Section : Exports) { +        const auto Targets = +            synthesizeTargets(Section.Architectures, Platforms); + +        for (const auto &Lib : Section.AllowableClients) +          for (const auto &Target : Targets) +            File->addAllowableClient(Lib, Target); + +        for (const auto &Lib : Section.ReexportedLibraries) +          for (const auto &Target : Targets) +            File->addReexportedLibrary(Lib, Target); + +        for (const auto &Symbol : Section.Symbols) { +          if (Ctx->FileKind != FileType::TBD_V3 && +              Symbol.value.startswith("_OBJC_EHTYPE_$_")) +            File->addSymbol(SymbolKind::ObjectiveCClassEHType, +                            Symbol.value.drop_front(15), Targets); +          else +            File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets); +        } +        for (auto &Symbol : Section.Classes) { +          auto Name = Symbol.value; +          if (Ctx->FileKind != FileType::TBD_V3) +            Name = Name.drop_front(); +          File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets); +        } +        for (auto &Symbol : Section.ClassEHs) +          File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets); +        for (auto &Symbol : Section.IVars) { +          auto Name = Symbol.value; +          if (Ctx->FileKind != FileType::TBD_V3) +            Name = Name.drop_front(); +          File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, +                          Targets); +        } +        for (auto &Symbol : Section.WeakDefSymbols) +          File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, +                          SymbolFlags::WeakDefined); +        for (auto &Symbol : Section.TLVSymbols) +          File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, +                          SymbolFlags::ThreadLocalValue); +      } + +      for (const auto &Section : Undefineds) { +        const auto Targets = +            synthesizeTargets(Section.Architectures, Platforms); +        for (auto &Symbol : Section.Symbols) { +          if (Ctx->FileKind != FileType::TBD_V3 && +              Symbol.value.startswith("_OBJC_EHTYPE_$_")) +            File->addSymbol(SymbolKind::ObjectiveCClassEHType, +                            Symbol.value.drop_front(15), Targets, +                            SymbolFlags::Undefined); +          else +            File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, +                            SymbolFlags::Undefined); +        } +        for (auto &Symbol : Section.Classes) { +          auto Name = Symbol.value; +          if (Ctx->FileKind != FileType::TBD_V3) +            Name = Name.drop_front(); +          File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, +                          SymbolFlags::Undefined); +        } +        for (auto &Symbol : Section.ClassEHs) +          File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, +                          SymbolFlags::Undefined); +        for (auto &Symbol : Section.IVars) { +          auto Name = Symbol.value; +          if (Ctx->FileKind != FileType::TBD_V3) +            Name = Name.drop_front(); +          File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, +                          SymbolFlags::Undefined); +        } +        for (auto &Symbol : Section.WeakRefSymbols) +          File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, +                          SymbolFlags::Undefined | SymbolFlags::WeakReferenced); +      } + +      return File; +    } + +    llvm::BumpPtrAllocator Allocator; +    StringRef copyString(StringRef String) { +      if (String.empty()) +        return {}; + +      void *Ptr = Allocator.Allocate(String.size(), 1); +      memcpy(Ptr, String.data(), String.size()); +      return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); +    } + +    std::vector<Architecture> Architectures; +    std::vector<UUID> UUIDs; +    PlatformSet Platforms; +    StringRef InstallName; +    PackedVersion CurrentVersion; +    PackedVersion CompatibilityVersion; +    SwiftVersion SwiftABIVersion{0}; +    ObjCConstraintType ObjCConstraint{ObjCConstraintType::None}; +    TBDFlags Flags{TBDFlags::None}; +    StringRef ParentUmbrella; +    std::vector<ExportSection> Exports; +    std::vector<UndefinedSection> Undefineds; +  }; + +  static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) { +    if (IO.mapTag("!tapi-tbd", false)) +      Ctx->FileKind = FileType::TBD_V4; +    else if (IO.mapTag("!tapi-tbd-v3", false)) +      Ctx->FileKind = FileType::TBD_V3; +    else if (IO.mapTag("!tapi-tbd-v2", false)) +      Ctx->FileKind = FileType::TBD_V2; +    else if (IO.mapTag("!tapi-tbd-v1", false) || +             IO.mapTag("tag:yaml.org,2002:map", false)) +      Ctx->FileKind = FileType::TBD_V1; +    else { +      Ctx->FileKind = FileType::Invalid; +      return; +    } +  } + +  static void mapping(IO &IO, const InterfaceFile *&File) { +    auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); +    assert((!Ctx || !IO.outputting() || +            (Ctx && Ctx->FileKind != FileType::Invalid)) && +           "File type is not set in YAML context"); + +    if (!IO.outputting()) { +      setFileTypeForInput(Ctx, IO); +      switch (Ctx->FileKind) { +      default: +        break; +      case FileType::TBD_V4: +        mapKeysToValuesV4(IO, File); +        return; +      case FileType::Invalid: +        IO.setError("unsupported file type"); +        return; +      } +    } else { +      // Set file type when writing. +      switch (Ctx->FileKind) { +      default: +        llvm_unreachable("unexpected file type"); +      case FileType::TBD_V4: +        mapKeysToValuesV4(IO, File); +        return; +      case FileType::TBD_V3: +        IO.mapTag("!tapi-tbd-v3", true); +        break; +      case FileType::TBD_V2: +        IO.mapTag("!tapi-tbd-v2", true); +        break; +      case FileType::TBD_V1: +        // Don't write the tag into the .tbd file for TBD v1 +        break; +      } +    } +    mapKeysToValues(Ctx->FileKind, IO, File); +  } + +  using SectionList = std::vector<SymbolSection>; +  struct NormalizedTBD_V4 { +    explicit NormalizedTBD_V4(IO &IO) {} +    NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) { +      auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); +      assert(Ctx); +      TBDVersion = Ctx->FileKind >> 1; +      Targets.insert(Targets.begin(), File->targets().begin(), +                     File->targets().end()); +      for (const auto &IT : File->uuids()) +        UUIDs.emplace_back(IT.first, IT.second); +      InstallName = File->getInstallName(); +      CurrentVersion = File->getCurrentVersion(); +      CompatibilityVersion = File->getCompatibilityVersion(); +      SwiftABIVersion = File->getSwiftABIVersion(); + +      Flags = TBDFlags::None; +      if (!File->isApplicationExtensionSafe()) +        Flags |= TBDFlags::NotApplicationExtensionSafe; + +      if (!File->isTwoLevelNamespace()) +        Flags |= TBDFlags::FlatNamespace; + +      if (File->isInstallAPI()) +        Flags |= TBDFlags::InstallAPI; + +      { +        std::map<std::string, TargetList> valueToTargetList; +        for (const auto &it : File->umbrellas()) +          valueToTargetList[it.second].emplace_back(it.first); + +        for (const auto &it : valueToTargetList) { +          UmbrellaSection CurrentSection; +          CurrentSection.Targets.insert(CurrentSection.Targets.begin(), +                                        it.second.begin(), it.second.end()); +          CurrentSection.Umbrella = it.first; +          ParentUmbrellas.emplace_back(std::move(CurrentSection)); +        } +      } + +      assignTargetsToLibrary(File->allowableClients(), AllowableClients); +      assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries); + +      auto handleSymbols = +          [](SectionList &CurrentSections, +             InterfaceFile::const_filtered_symbol_range Symbols, +             std::function<bool(const Symbol *)> Pred) { +            std::set<TargetList> TargetSet; +            std::map<const Symbol *, TargetList> SymbolToTargetList; +            for (const auto *Symbol : Symbols) { +              if (!Pred(Symbol)) +                continue; +              TargetList Targets(Symbol->targets()); +              SymbolToTargetList[Symbol] = Targets; +              TargetSet.emplace(std::move(Targets)); +            } +            for (const auto &TargetIDs : TargetSet) { +              SymbolSection CurrentSection; +              CurrentSection.Targets.insert(CurrentSection.Targets.begin(), +                                            TargetIDs.begin(), TargetIDs.end()); + +              for (const auto &IT : SymbolToTargetList) { +                if (IT.second != TargetIDs) +                  continue; + +                const auto *Symbol = IT.first; +                switch (Symbol->getKind()) { +                case SymbolKind::GlobalSymbol: +                  if (Symbol->isWeakDefined()) +                    CurrentSection.WeakSymbols.emplace_back(Symbol->getName()); +                  else if (Symbol->isThreadLocalValue()) +                    CurrentSection.TlvSymbols.emplace_back(Symbol->getName()); +                  else +                    CurrentSection.Symbols.emplace_back(Symbol->getName()); +                  break; +                case SymbolKind::ObjectiveCClass: +                  CurrentSection.Classes.emplace_back(Symbol->getName()); +                  break; +                case SymbolKind::ObjectiveCClassEHType: +                  CurrentSection.ClassEHs.emplace_back(Symbol->getName()); +                  break; +                case SymbolKind::ObjectiveCInstanceVariable: +                  CurrentSection.Ivars.emplace_back(Symbol->getName()); +                  break; +                } +              } +              sort(CurrentSection.Symbols); +              sort(CurrentSection.Classes); +              sort(CurrentSection.ClassEHs); +              sort(CurrentSection.Ivars); +              sort(CurrentSection.WeakSymbols); +              sort(CurrentSection.TlvSymbols); +              CurrentSections.emplace_back(std::move(CurrentSection)); +            } +          }; + +      handleSymbols(Exports, File->exports(), [](const Symbol *Symbol) { +        return !Symbol->isReexported(); +      }); +      handleSymbols(Reexports, File->exports(), [](const Symbol *Symbol) { +        return Symbol->isReexported(); +      }); +      handleSymbols(Undefineds, File->undefineds(), +                    [](const Symbol *Symbol) { return true; }); +    } + +    const InterfaceFile *denormalize(IO &IO) { +      auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); +      assert(Ctx); + +      auto *File = new InterfaceFile; +      File->setPath(Ctx->Path); +      File->setFileType(Ctx->FileKind); +      for (auto &id : UUIDs) +        File->addUUID(id.TargetID, id.Value); +      File->addTargets(Targets); +      File->setInstallName(InstallName); +      File->setCurrentVersion(CurrentVersion); +      File->setCompatibilityVersion(CompatibilityVersion); +      File->setSwiftABIVersion(SwiftABIVersion); +      for (const auto &CurrentSection : ParentUmbrellas) +        for (const auto &target : CurrentSection.Targets) +          File->addParentUmbrella(target, CurrentSection.Umbrella); +      File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); +      File->setApplicationExtensionSafe( +          !(Flags & TBDFlags::NotApplicationExtensionSafe)); +      File->setInstallAPI(Flags & TBDFlags::InstallAPI); + +      for (const auto &CurrentSection : AllowableClients) { +        for (const auto &lib : CurrentSection.Values) +          for (const auto &Target : CurrentSection.Targets) +            File->addAllowableClient(lib, Target); +      } + +      for (const auto &CurrentSection : ReexportedLibraries) { +        for (const auto &Lib : CurrentSection.Values) +          for (const auto &Target : CurrentSection.Targets) +            File->addReexportedLibrary(Lib, Target); +      } + +      auto handleSymbols = [File](const SectionList &CurrentSections, +                                  SymbolFlags Flag = SymbolFlags::None) { +        for (const auto &CurrentSection : CurrentSections) { +          for (auto &sym : CurrentSection.Symbols) +            File->addSymbol(SymbolKind::GlobalSymbol, sym, +                            CurrentSection.Targets, Flag); + +          for (auto &sym : CurrentSection.Classes) +            File->addSymbol(SymbolKind::ObjectiveCClass, sym, +                            CurrentSection.Targets); + +          for (auto &sym : CurrentSection.ClassEHs) +            File->addSymbol(SymbolKind::ObjectiveCClassEHType, sym, +                            CurrentSection.Targets); + +          for (auto &sym : CurrentSection.Ivars) +            File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym, +                            CurrentSection.Targets); + +          for (auto &sym : CurrentSection.WeakSymbols) +            File->addSymbol(SymbolKind::GlobalSymbol, sym, +                            CurrentSection.Targets); +          for (auto &sym : CurrentSection.TlvSymbols) +            File->addSymbol(SymbolKind::GlobalSymbol, sym, +                            CurrentSection.Targets, +                            SymbolFlags::ThreadLocalValue); +        } +      }; + +      handleSymbols(Exports); +      handleSymbols(Reexports, SymbolFlags::Rexported); +      handleSymbols(Undefineds, SymbolFlags::Undefined); + +      return File; +    } + +    unsigned TBDVersion; +    std::vector<UUIDv4> UUIDs; +    TargetList Targets; +    StringRef InstallName; +    PackedVersion CurrentVersion; +    PackedVersion CompatibilityVersion; +    SwiftVersion SwiftABIVersion{0}; +    std::vector<MetadataSection> AllowableClients; +    std::vector<MetadataSection> ReexportedLibraries; +    TBDFlags Flags{TBDFlags::None}; +    std::vector<UmbrellaSection> ParentUmbrellas; +    SectionList Exports; +    SectionList Reexports; +    SectionList Undefineds; + +  private: +    void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries, +                                std::vector<MetadataSection> &Section) { +      std::set<TargetList> targetSet; +      std::map<const InterfaceFileRef *, TargetList> valueToTargetList; +      for (const auto &library : Libraries) { +        TargetList targets(library.targets()); +        valueToTargetList[&library] = targets; +        targetSet.emplace(std::move(targets)); +      } + +      for (const auto &targets : targetSet) { +        MetadataSection CurrentSection; +        CurrentSection.Targets.insert(CurrentSection.Targets.begin(), +                                      targets.begin(), targets.end()); + +        for (const auto &it : valueToTargetList) { +          if (it.second != targets) +            continue; + +          CurrentSection.Values.emplace_back(it.first->getInstallName()); +        } +        llvm::sort(CurrentSection.Values); +        Section.emplace_back(std::move(CurrentSection)); +      } +    } +  }; + +  static void mapKeysToValues(FileType FileKind, IO &IO, +                              const InterfaceFile *&File) { +    MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File); +    IO.mapRequired("archs", Keys->Architectures); +    if (FileKind != FileType::TBD_V1) +      IO.mapOptional("uuids", Keys->UUIDs); +    IO.mapRequired("platform", Keys->Platforms); +    if (FileKind != FileType::TBD_V1) +      IO.mapOptional("flags", Keys->Flags, TBDFlags::None); +    IO.mapRequired("install-name", Keys->InstallName); +    IO.mapOptional("current-version", Keys->CurrentVersion, +                   PackedVersion(1, 0, 0)); +    IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, +                   PackedVersion(1, 0, 0)); +    if (FileKind != FileType::TBD_V3) +      IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0)); +    else +      IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, +                     SwiftVersion(0)); +    IO.mapOptional("objc-constraint", Keys->ObjCConstraint, +                   (FileKind == FileType::TBD_V1) +                       ? ObjCConstraintType::None +                       : ObjCConstraintType::Retain_Release); +    if (FileKind != FileType::TBD_V1) +      IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef()); +    IO.mapOptional("exports", Keys->Exports); +    if (FileKind != FileType::TBD_V1) +      IO.mapOptional("undefineds", Keys->Undefineds); +  } + +  static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) { +    MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO, +                                                                       File); +    IO.mapTag("!tapi-tbd", true); +    IO.mapRequired("tbd-version", Keys->TBDVersion); +    IO.mapRequired("targets", Keys->Targets); +    IO.mapOptional("uuids", Keys->UUIDs); +    IO.mapOptional("flags", Keys->Flags, TBDFlags::None); +    IO.mapRequired("install-name", Keys->InstallName); +    IO.mapOptional("current-version", Keys->CurrentVersion, +                   PackedVersion(1, 0, 0)); +    IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, +                   PackedVersion(1, 0, 0)); +    IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0)); +    IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas); +    auto OptionKind = MetadataSection::Option::Clients; +    IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients, +                              OptionKind); +    OptionKind = MetadataSection::Option::Libraries; +    IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries, +                              OptionKind); +    IO.mapOptional("exports", Keys->Exports); +    IO.mapOptional("reexports", Keys->Reexports); +    IO.mapOptional("undefineds", Keys->Undefineds); +  } +}; + +template <> +struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> { +  static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) { +    return Seq.size(); +  } +  static const InterfaceFile *& +  element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) { +    if (Index >= Seq.size()) +      Seq.resize(Index + 1); +    return Seq[Index]; +  } +}; + +} // end namespace yaml. + +namespace MachO { +static void DiagHandler(const SMDiagnostic &Diag, void *Context) { +  auto *File = static_cast<TextAPIContext *>(Context); +  SmallString<1024> Message; +  raw_svector_ostream S(Message); + +  SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path, +                       Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(), +                       Diag.getMessage(), Diag.getLineContents(), +                       Diag.getRanges(), Diag.getFixIts()); + +  NewDiag.print(nullptr, S); +  File->ErrorMessage = ("malformed file\n" + Message).str(); +} + +Expected<std::unique_ptr<InterfaceFile>> +TextAPIReader::get(MemoryBufferRef InputBuffer) { +  TextAPIContext Ctx; +  Ctx.Path = InputBuffer.getBufferIdentifier(); +  yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); + +  // Fill vector with interface file objects created by parsing the YAML file. +  std::vector<const InterfaceFile *> Files; +  YAMLIn >> Files; + +  // YAMLIn dynamically allocates for Interface file and in case of error, +  // memory leak will occur unless wrapped around unique_ptr +  auto File = std::unique_ptr<InterfaceFile>( +      const_cast<InterfaceFile *>(Files.front())); + +  if (YAMLIn.error()) +    return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error()); + +  return std::move(File); +} + +Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) { +  TextAPIContext Ctx; +  Ctx.Path = File.getPath(); +  Ctx.FileKind = File.getFileType(); +  llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); + +  std::vector<const InterfaceFile *> Files; +  Files.emplace_back(&File); + +  // Stream out yaml. +  YAMLOut << Files; + +  return Error::success(); +} + +} // end namespace MachO. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.cpp b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp new file mode 100644 index 000000000000..183c5d5a93b0 --- /dev/null +++ b/llvm/lib/TextAPI/MachO/TextStubCommon.cpp @@ -0,0 +1,225 @@ +//===- TextStubCommon.cpp -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Implememts common Text Stub YAML mappings. +// +//===----------------------------------------------------------------------===// + +#include "TextStubCommon.h" +#include "TextAPIContext.h" + +using namespace llvm::MachO; + +namespace llvm { +namespace yaml { + +void ScalarTraits<FlowStringRef>::output(const FlowStringRef &Value, void *Ctx, +                                         raw_ostream &OS) { +  ScalarTraits<StringRef>::output(Value, Ctx, OS); +} +StringRef ScalarTraits<FlowStringRef>::input(StringRef Value, void *Ctx, +                                             FlowStringRef &Out) { +  return ScalarTraits<StringRef>::input(Value, Ctx, Out.value); +} +QuotingType ScalarTraits<FlowStringRef>::mustQuote(StringRef Name) { +  return ScalarTraits<StringRef>::mustQuote(Name); +} + +void ScalarEnumerationTraits<ObjCConstraintType>::enumeration( +    IO &IO, ObjCConstraintType &Constraint) { +  IO.enumCase(Constraint, "none", ObjCConstraintType::None); +  IO.enumCase(Constraint, "retain_release", ObjCConstraintType::Retain_Release); +  IO.enumCase(Constraint, "retain_release_for_simulator", +              ObjCConstraintType::Retain_Release_For_Simulator); +  IO.enumCase(Constraint, "retain_release_or_gc", +              ObjCConstraintType::Retain_Release_Or_GC); +  IO.enumCase(Constraint, "gc", ObjCConstraintType::GC); +} + +void ScalarTraits<PlatformSet>::output(const PlatformSet &Values, void *IO, +                                       raw_ostream &OS) { + +  const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO); +  assert((!Ctx || Ctx->FileKind != FileType::Invalid) && +         "File type is not set in context"); + +  if (Ctx && Ctx->FileKind == TBD_V3 && Values.count(PlatformKind::macOS) && +      Values.count(PlatformKind::macCatalyst)) { +    OS << "zippered"; +    return; +  } + +  assert(Values.size() == 1U); +  switch (*Values.begin()) { +  default: +    llvm_unreachable("unexpected platform"); +    break; +  case PlatformKind::macOS: +    OS << "macosx"; +    break; +  case PlatformKind::iOS: +    OS << "ios"; +    break; +  case PlatformKind::watchOS: +    OS << "watchos"; +    break; +  case PlatformKind::tvOS: +    OS << "tvos"; +    break; +  case PlatformKind::bridgeOS: +    OS << "bridgeos"; +    break; +  } +} + +StringRef ScalarTraits<PlatformSet>::input(StringRef Scalar, void *IO, +                                           PlatformSet &Values) { +  const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO); +  assert((!Ctx || Ctx->FileKind != FileType::Invalid) && +         "File type is not set in context"); + +  if (Scalar == "zippered") { +    if (Ctx && Ctx->FileKind == FileType::TBD_V3) { +      Values.insert(PlatformKind::macOS); +      Values.insert(PlatformKind::macCatalyst); +      return {}; +    } +    return "invalid platform"; +  } + +  auto Platform = StringSwitch<PlatformKind>(Scalar) +                      .Case("unknown", PlatformKind::unknown) +                      .Case("macosx", PlatformKind::macOS) +                      .Case("ios", PlatformKind::iOS) +                      .Case("watchos", PlatformKind::watchOS) +                      .Case("tvos", PlatformKind::tvOS) +                      .Case("bridgeos", PlatformKind::bridgeOS) +                      .Case("iosmac", PlatformKind::macCatalyst) +                      .Default(PlatformKind::unknown); + +  if (Platform == PlatformKind::macCatalyst) +    if (Ctx && Ctx->FileKind != FileType::TBD_V3) +      return "invalid platform"; + +  if (Platform == PlatformKind::unknown) +    return "unknown platform"; + +  Values.insert(Platform); +  return {}; +} + +QuotingType ScalarTraits<PlatformSet>::mustQuote(StringRef) { +  return QuotingType::None; +} + +void ScalarBitSetTraits<ArchitectureSet>::bitset(IO &IO, +                                                 ArchitectureSet &Archs) { +#define ARCHINFO(arch, type, subtype)                                          \ +  IO.bitSetCase(Archs, #arch, 1U << static_cast<int>(AK_##arch)); +#include "llvm/TextAPI/MachO/Architecture.def" +#undef ARCHINFO +} + +void ScalarTraits<Architecture>::output(const Architecture &Value, void *, +                                        raw_ostream &OS) { +  OS << Value; +} +StringRef ScalarTraits<Architecture>::input(StringRef Scalar, void *, +                                            Architecture &Value) { +  Value = getArchitectureFromName(Scalar); +  return {}; +} +QuotingType ScalarTraits<Architecture>::mustQuote(StringRef) { +  return QuotingType::None; +} + +void ScalarTraits<PackedVersion>::output(const PackedVersion &Value, void *, +                                         raw_ostream &OS) { +  OS << Value; +} +StringRef ScalarTraits<PackedVersion>::input(StringRef Scalar, void *, +                                             PackedVersion &Value) { +  if (!Value.parse32(Scalar)) +    return "invalid packed version string."; +  return {}; +} +QuotingType ScalarTraits<PackedVersion>::mustQuote(StringRef) { +  return QuotingType::None; +} + +void ScalarTraits<SwiftVersion>::output(const SwiftVersion &Value, void *, +                                        raw_ostream &OS) { +  switch (Value) { +  case 1: +    OS << "1.0"; +    break; +  case 2: +    OS << "1.1"; +    break; +  case 3: +    OS << "2.0"; +    break; +  case 4: +    OS << "3.0"; +    break; +  default: +    OS << (unsigned)Value; +    break; +  } +} +StringRef ScalarTraits<SwiftVersion>::input(StringRef Scalar, void *IO, +                                            SwiftVersion &Value) { +  const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO); +  assert((!Ctx || Ctx->FileKind != FileType::Invalid) && +         "File type is not set in context"); + +  if (Ctx->FileKind == FileType::TBD_V4) { +    if (Scalar.getAsInteger(10, Value)) +      return "invalid Swift ABI version."; +    return {}; +  } else { +    Value = StringSwitch<SwiftVersion>(Scalar) +                .Case("1.0", 1) +                .Case("1.1", 2) +                .Case("2.0", 3) +                .Case("3.0", 4) +                .Default(0); +  } + +  if (Value != SwiftVersion(0)) +    return {}; + +  if (Scalar.getAsInteger(10, Value)) +    return "invalid Swift ABI version."; + +  return StringRef(); +} +QuotingType ScalarTraits<SwiftVersion>::mustQuote(StringRef) { +  return QuotingType::None; +} + +void ScalarTraits<UUID>::output(const UUID &Value, void *, raw_ostream &OS) { +  OS << Value.first << ": " << Value.second; +} +StringRef ScalarTraits<UUID>::input(StringRef Scalar, void *, UUID &Value) { +  auto Split = Scalar.split(':'); +  auto Arch = Split.first.trim(); +  auto UUID = Split.second.trim(); +  if (UUID.empty()) +    return "invalid uuid string pair"; +  Value.second = UUID; +  Value.first = Target{getArchitectureFromName(Arch), PlatformKind::unknown}; +  return {}; +} + +QuotingType ScalarTraits<UUID>::mustQuote(StringRef) { +  return QuotingType::Single; +} + +} // end namespace yaml. +} // end namespace llvm. diff --git a/llvm/lib/TextAPI/MachO/TextStubCommon.h b/llvm/lib/TextAPI/MachO/TextStubCommon.h new file mode 100644 index 000000000000..a558cbcec9fb --- /dev/null +++ b/llvm/lib/TextAPI/MachO/TextStubCommon.h @@ -0,0 +1,81 @@ +//===- TextStubCommon.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines common Text Stub YAML mappings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TEXTAPI_TEXT_STUB_COMMON_H +#define LLVM_TEXTAPI_TEXT_STUB_COMMON_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/TextAPI/MachO/ArchitectureSet.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" +#include "llvm/TextAPI/MachO/PackedVersion.h" + +using UUID = std::pair<llvm::MachO::Target, std::string>; + +LLVM_YAML_STRONG_TYPEDEF(llvm::StringRef, FlowStringRef) +LLVM_YAML_STRONG_TYPEDEF(uint8_t, SwiftVersion) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(UUID) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowStringRef) + +namespace llvm { +namespace yaml { + +template <> struct ScalarTraits<FlowStringRef> { +  static void output(const FlowStringRef &, void *, raw_ostream &); +  static StringRef input(StringRef, void *, FlowStringRef &); +  static QuotingType mustQuote(StringRef); +}; + +template <> struct ScalarEnumerationTraits<MachO::ObjCConstraintType> { +  static void enumeration(IO &, MachO::ObjCConstraintType &); +}; + +template <> struct ScalarTraits<MachO::PlatformSet> { +  static void output(const MachO::PlatformSet &, void *, raw_ostream &); +  static StringRef input(StringRef, void *, MachO::PlatformSet &); +  static QuotingType mustQuote(StringRef); +}; + +template <> struct ScalarBitSetTraits<MachO::ArchitectureSet> { +  static void bitset(IO &, MachO::ArchitectureSet &); +}; + +template <> struct ScalarTraits<MachO::Architecture> { +  static void output(const MachO::Architecture &, void *, raw_ostream &); +  static StringRef input(StringRef, void *, MachO::Architecture &); +  static QuotingType mustQuote(StringRef); +}; + +template <> struct ScalarTraits<MachO::PackedVersion> { +  static void output(const MachO::PackedVersion &, void *, raw_ostream &); +  static StringRef input(StringRef, void *, MachO::PackedVersion &); +  static QuotingType mustQuote(StringRef); +}; + +template <> struct ScalarTraits<SwiftVersion> { +  static void output(const SwiftVersion &, void *, raw_ostream &); +  static StringRef input(StringRef, void *, SwiftVersion &); +  static QuotingType mustQuote(StringRef); +}; + +template <> struct ScalarTraits<UUID> { +  static void output(const UUID &, void *, raw_ostream &); +  static StringRef input(StringRef, void *, UUID &); +  static QuotingType mustQuote(StringRef); +}; + +} // end namespace yaml. +} // end namespace llvm. + +#endif // LLVM_TEXTAPI_TEXT_STUB_COMMON_H | 
