[llvm] [TextAPI] Introduce granularity for handling ObjC Interface symbols (PR #79928)

Cyndy Ishida via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 29 17:25:17 PST 2024


https://github.com/cyndyishida created https://github.com/llvm/llvm-project/pull/79928

ObjCInterfaceRecords roughly align to the objc-classes key in tbd-files. They condensely represent up to 3 symbols. The problem here is that when represented this way, we lose granularity when these symbols could have different linkages or outright don't exist. This can happen frequently in interoptable code generated by the swift compiler. This adds fields and utility functions to express unique properties for these symbols. If the record does represent the same properties across all of its symbols, it will be treated the same in the TBD. Otherwise it will be printed in global's section.

>From b99c81dec1f48c1252caaa8dc80036d181abc37c Mon Sep 17 00:00:00 2001
From: Cyndy Ishida <cyndy_ishida at apple.com>
Date: Mon, 29 Jan 2024 12:55:08 -0800
Subject: [PATCH] [TextAPI] Introduce granularity for handling ObjC Interface
 symbols

ObjCInterfaceRecords roughly align to the objc-classes key in
tbd-files. They condensely represent up to 3 symbols. The problem here
is that when represented this way, we lose granularity when these
symbols could have different linkages or outright don't exist. This can
happen frequently in interoptable code generated by the swift compiler.
This adds fields and utility functions to express unique properties for
these symbols. If the record does represent the same properties across
all of its symbols, it will be treated the same in the TBD. Otherwise it
will be printed in global's section.
---
 llvm/include/llvm/TextAPI/InterfaceFile.h     |   8 +-
 llvm/include/llvm/TextAPI/Record.h            |  35 +-
 llvm/include/llvm/TextAPI/RecordsSlice.h      |   8 +-
 llvm/include/llvm/TextAPI/Symbol.h            |  23 +-
 llvm/include/llvm/TextAPI/SymbolSet.h         |   4 +-
 llvm/lib/TextAPI/RecordVisitor.cpp            |  37 +-
 llvm/lib/TextAPI/RecordsSlice.cpp             |  63 +-
 llvm/lib/TextAPI/Symbol.cpp                   |  23 +-
 llvm/lib/TextAPI/SymbolSet.cpp                |  19 +-
 .../tools/llvm-readtapi/stubify-ehtypes.test  | 859 ++++++++++++++++++
 llvm/unittests/TextAPI/RecordTests.cpp        |  32 +-
 llvm/unittests/TextAPI/TextStubV5Tests.cpp    |  78 ++
 12 files changed, 1134 insertions(+), 55 deletions(-)
 create mode 100644 llvm/test/tools/llvm-readtapi/stubify-ehtypes.test

diff --git a/llvm/include/llvm/TextAPI/InterfaceFile.h b/llvm/include/llvm/TextAPI/InterfaceFile.h
index 3b63f61877695..7984a8008771e 100644
--- a/llvm/include/llvm/TextAPI/InterfaceFile.h
+++ b/llvm/include/llvm/TextAPI/InterfaceFile.h
@@ -351,9 +351,11 @@ class InterfaceFile {
   ///
   /// \param Kind The kind of global symbol to record.
   /// \param Name The name of the symbol.
-  std::optional<const Symbol *> getSymbol(EncodeKind Kind,
-                                          StringRef Name) const {
-    if (auto *Sym = SymbolsSet->findSymbol(Kind, Name))
+  /// \param ObjCIF The ObjCInterface symbol type, if applicable.
+  std::optional<const Symbol *>
+  getSymbol(EncodeKind Kind, StringRef Name,
+            ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) const {
+    if (auto *Sym = SymbolsSet->findSymbol(Kind, Name, ObjCIF))
       return Sym;
     return std::nullopt;
   }
diff --git a/llvm/include/llvm/TextAPI/Record.h b/llvm/include/llvm/TextAPI/Record.h
index 4bb1be9d0ad4e..02af3098cc5a5 100644
--- a/llvm/include/llvm/TextAPI/Record.h
+++ b/llvm/include/llvm/TextAPI/Record.h
@@ -164,15 +164,42 @@ class ObjCCategoryRecord : public ObjCContainerRecord {
 class ObjCInterfaceRecord : public ObjCContainerRecord {
 public:
   ObjCInterfaceRecord(StringRef Name, RecordLinkage Linkage,
-                      bool HasEHType = false)
-      : ObjCContainerRecord(Name, Linkage), HasEHType(HasEHType) {}
+                      ObjCIFSymbolKind SymType)
+      : ObjCContainerRecord(Name, Linkage) {
+    updateLinkageForSymbols(SymType, Linkage);
+  }
+
+  bool hasExceptionAttribute() const {
+    return Linkages.EHType != RecordLinkage::Unknown;
+  }
+  bool isCompleteInterface() const {
+    return Linkages.Class >= RecordLinkage::Rexported &&
+           Linkages.MetaClass >= RecordLinkage::Rexported;
+  }
+  bool isExportedSymbol(ObjCIFSymbolKind CurrType) const {
+    return getLinkageForSymbol(CurrType) >= RecordLinkage::Rexported;
+  }
+
+  RecordLinkage getLinkageForSymbol(ObjCIFSymbolKind CurrType) const;
+  void updateLinkageForSymbols(ObjCIFSymbolKind SymType, RecordLinkage Link);
 
-  bool hasExceptionAttribute() const { return HasEHType; }
   bool addObjCCategory(ObjCCategoryRecord *Record);
   std::vector<ObjCCategoryRecord *> getObjCCategories() const;
 
 private:
-  bool HasEHType;
+  /// Linkage level for each symbol represented in ObjCInterfaceRecord.
+  struct Linkages {
+    RecordLinkage Class = RecordLinkage::Unknown;
+    RecordLinkage MetaClass = RecordLinkage::Unknown;
+    RecordLinkage EHType = RecordLinkage::Unknown;
+    bool operator==(const Linkages &other) const {
+      return std::tie(Class, MetaClass, EHType) ==
+             std::tie(other.Class, other.MetaClass, other.EHType);
+    }
+    bool operator!=(const Linkages &other) const { return !(*this == other); }
+  };
+  Linkages Linkages;
+
   // Non-owning containers of categories that extend the class.
   llvm::MapVector<StringRef, ObjCCategoryRecord *> Categories;
 };
diff --git a/llvm/include/llvm/TextAPI/RecordsSlice.h b/llvm/include/llvm/TextAPI/RecordsSlice.h
index 0f9e3fad1a304..f3db72121e68c 100644
--- a/llvm/include/llvm/TextAPI/RecordsSlice.h
+++ b/llvm/include/llvm/TextAPI/RecordsSlice.h
@@ -62,10 +62,10 @@ class RecordsSlice {
   ///
   /// \param Name The name of class, not symbol.
   /// \param Linkage The linkage of symbol.
-  /// \param HasEHType Whether symbol represents an eh_type.
+  /// \param SymType The symbols this class represents.
   /// \return The non-owning pointer to added record in slice.
   ObjCInterfaceRecord *addObjCInterface(StringRef Name, RecordLinkage Linkage,
-                                        bool HasEHType = false);
+                                        ObjCIFSymbolKind SymType);
 
   /// Add ObjC IVar record.
   ///
@@ -179,9 +179,9 @@ class RecordsSlice {
 
   /// Update set flags of requested record.
   ///
-  /// \param R The global record to update.
+  /// \param R The record to update.
   /// \param F Flags to update to.
-  void updateFlags(GlobalRecord *R, SymbolFlags F) { R->Flags = F; }
+  void updateFlags(Record *R, SymbolFlags F) { R->Flags |= F; }
 
   RecordMap<GlobalRecord> Globals;
   RecordMap<ObjCInterfaceRecord> Classes;
diff --git a/llvm/include/llvm/TextAPI/Symbol.h b/llvm/include/llvm/TextAPI/Symbol.h
index 37a149a39489f..e6514f01971ad 100644
--- a/llvm/include/llvm/TextAPI/Symbol.h
+++ b/llvm/include/llvm/TextAPI/Symbol.h
@@ -65,6 +65,19 @@ constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_";
 constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
 constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
 
+/// ObjC Interface symbol mappings.
+enum class ObjCIFSymbolKind : uint8_t {
+  None = 0,
+  /// Is OBJC_CLASS* symbol.
+  Class = 1U << 0,
+  /// Is OBJC_METACLASS* symbol.
+  MetaClass = 1U << 1,
+  /// Is OBJC_EHTYPE* symbol.
+  EHType = 1U << 2,
+
+  LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/EHType),
+};
+
 using TargetList = SmallVector<Target, 5>;
 
 // Keep containers that hold Targets in sorted order and uniqued.
@@ -165,18 +178,18 @@ class Symbol {
 struct SimpleSymbol {
   StringRef Name;
   EncodeKind Kind;
+  ObjCIFSymbolKind ObjCInterfaceType;
 
   bool operator<(const SimpleSymbol &O) const {
-    return std::tie(Name, Kind) < std::tie(O.Name, O.Kind);
+    return std::tie(Name, Kind, ObjCInterfaceType) <
+           std::tie(O.Name, O.Kind, O.ObjCInterfaceType);
   }
 };
 
-/// Determine EncodeKind from Flags and parsing Name.
+/// Get symbol classification by parsing the name of a symbol.
 ///
 /// \param Name The name of symbol.
-/// \param Flags The flags pre-determined for the symbol.
-SimpleSymbol parseSymbol(StringRef SymName,
-                         const SymbolFlags Flags = SymbolFlags::None);
+SimpleSymbol parseSymbol(StringRef SymName);
 
 } // end namespace MachO.
 } // end namespace llvm.
diff --git a/llvm/include/llvm/TextAPI/SymbolSet.h b/llvm/include/llvm/TextAPI/SymbolSet.h
index 966347f0feaa1..6ccabb9077208 100644
--- a/llvm/include/llvm/TextAPI/SymbolSet.h
+++ b/llvm/include/llvm/TextAPI/SymbolSet.h
@@ -107,7 +107,9 @@ class SymbolSet {
     return Global;
   }
 
-  const Symbol *findSymbol(EncodeKind Kind, StringRef Name) const;
+  const Symbol *
+  findSymbol(EncodeKind Kind, StringRef Name,
+             ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) const;
 
   struct const_symbol_iterator
       : public iterator_adaptor_base<
diff --git a/llvm/lib/TextAPI/RecordVisitor.cpp b/llvm/lib/TextAPI/RecordVisitor.cpp
index b049c9e579c3d..3ff6bbd8bbcb2 100644
--- a/llvm/lib/TextAPI/RecordVisitor.cpp
+++ b/llvm/lib/TextAPI/RecordVisitor.cpp
@@ -28,10 +28,20 @@ static bool shouldSkipRecord(const Record &R, const bool RecordUndefs) {
 }
 
 void SymbolConverter::visitGlobal(const GlobalRecord &GR) {
-  auto [SymName, SymKind] = parseSymbol(GR.getName(), GR.getFlags());
+  auto [SymName, SymKind, InterfaceType] = parseSymbol(GR.getName());
   if (shouldSkipRecord(GR, RecordUndefs))
     return;
   Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ);
+
+  if (InterfaceType == ObjCIFSymbolKind::None) {
+    Symbols->addGlobal(SymKind, SymName, GR.getFlags(), Targ);
+    return;
+  }
+
+  // It is impossible to hold a complete ObjCInterface with a single
+  // GlobalRecord, so continue to treat this symbol a generic global.
+  Symbols->addGlobal(EncodeKind::GlobalSymbol, GR.getName(), GR.getFlags(),
+                     Targ);
 }
 
 void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars,
@@ -48,11 +58,28 @@ void SymbolConverter::addIVars(const ArrayRef<ObjCIVarRecord *> IVars,
 
 void SymbolConverter::visitObjCInterface(const ObjCInterfaceRecord &ObjCR) {
   if (!shouldSkipRecord(ObjCR, RecordUndefs)) {
-    Symbols->addGlobal(EncodeKind::ObjectiveCClass, ObjCR.getName(),
-                       ObjCR.getFlags(), Targ);
-    if (ObjCR.hasExceptionAttribute())
-      Symbols->addGlobal(EncodeKind::ObjectiveCClassEHType, ObjCR.getName(),
+    if (ObjCR.isCompleteInterface()) {
+      Symbols->addGlobal(EncodeKind::ObjectiveCClass, ObjCR.getName(),
                          ObjCR.getFlags(), Targ);
+      if (ObjCR.hasExceptionAttribute())
+        Symbols->addGlobal(EncodeKind::ObjectiveCClassEHType, ObjCR.getName(),
+                           ObjCR.getFlags(), Targ);
+    } else {
+      // Because there is not a complete interface, visit individual symbols
+      // instead.
+      if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::EHType))
+        Symbols->addGlobal(EncodeKind::GlobalSymbol,
+                           (ObjC2EHTypePrefix + ObjCR.getName()).str(),
+                           ObjCR.getFlags(), Targ);
+      if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::Class))
+        Symbols->addGlobal(EncodeKind::GlobalSymbol,
+                           (ObjC2ClassNamePrefix + ObjCR.getName()).str(),
+                           ObjCR.getFlags(), Targ);
+      if (ObjCR.isExportedSymbol(ObjCIFSymbolKind::MetaClass))
+        Symbols->addGlobal(EncodeKind::GlobalSymbol,
+                           (ObjC2MetaClassNamePrefix + ObjCR.getName()).str(),
+                           ObjCR.getFlags(), Targ);
+    }
   }
 
   addIVars(ObjCR.getObjCIVars(), ObjCR.getName());
diff --git a/llvm/lib/TextAPI/RecordsSlice.cpp b/llvm/lib/TextAPI/RecordsSlice.cpp
index 7f6fad1705994..f07853e579242 100644
--- a/llvm/lib/TextAPI/RecordsSlice.cpp
+++ b/llvm/lib/TextAPI/RecordsSlice.cpp
@@ -22,15 +22,21 @@ using namespace llvm::MachO;
 Record *RecordsSlice::addRecord(StringRef Name, SymbolFlags Flags,
                                 GlobalRecord::Kind GV, RecordLinkage Linkage) {
   // Find a specific Record type to capture.
-  auto [APIName, SymKind] = parseSymbol(Name, Flags);
+  auto [APIName, SymKind, InterfaceType] = parseSymbol(Name);
   Name = APIName;
   switch (SymKind) {
   case EncodeKind::GlobalSymbol:
     return addGlobal(Name, Linkage, GV, Flags);
   case EncodeKind::ObjectiveCClass:
-    return addObjCInterface(Name, Linkage);
-  case EncodeKind::ObjectiveCClassEHType:
-    return addObjCInterface(Name, Linkage, /*HasEHType=*/true);
+    return addObjCInterface(Name, Linkage, InterfaceType);
+  case EncodeKind::ObjectiveCClassEHType: {
+    ObjCInterfaceRecord *Rec = addObjCInterface(Name, Linkage, InterfaceType);
+    // When classes without ehtype are used in try/catch blocks
+    // a weak-defined symbol is exported.
+    if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
+      updateFlags(Rec, SymbolFlags::WeakDefined);
+    return Rec;
+  }
   case EncodeKind::ObjectiveCInstanceVariable: {
     auto [Super, IVar] = Name.split('.');
     // Attempt to find super class.
@@ -88,6 +94,39 @@ GlobalRecord *RecordsSlice::findGlobal(StringRef Name,
   return Record;
 }
 
+RecordLinkage
+ObjCInterfaceRecord::getLinkageForSymbol(ObjCIFSymbolKind CurrType) const {
+  assert(CurrType <= ObjCIFSymbolKind::EHType &&
+         "expected single ObjCIFSymbolKind enum value");
+  if (CurrType == ObjCIFSymbolKind::Class)
+    return Linkages.Class;
+
+  if (CurrType == ObjCIFSymbolKind::MetaClass)
+    return Linkages.MetaClass;
+
+  if (CurrType == ObjCIFSymbolKind::EHType)
+    return Linkages.EHType;
+
+  llvm_unreachable("unexpected ObjCIFSymbolKind");
+}
+
+void ObjCInterfaceRecord::updateLinkageForSymbols(ObjCIFSymbolKind SymType,
+                                                  RecordLinkage Link) {
+  if ((SymType & ObjCIFSymbolKind::Class) == ObjCIFSymbolKind::Class)
+    Linkages.Class = std::max(Link, Linkages.Class);
+  if ((SymType & ObjCIFSymbolKind::MetaClass) == ObjCIFSymbolKind::MetaClass)
+    Linkages.MetaClass = std::max(Link, Linkages.MetaClass);
+  if ((SymType & ObjCIFSymbolKind::EHType) == ObjCIFSymbolKind::EHType)
+    Linkages.EHType = std::max(Link, Linkages.EHType);
+
+  // Obj-C Classes represent multiple symbols that could have competing
+  // linkages, in this case assign the largest one, when querying the linkage of
+  // the record itself. This allows visitors pick whether they want to account
+  // for complete symbol information.
+  Linkage =
+      std::max(Linkages.Class, std::max(Linkages.MetaClass, Linkages.EHType));
+}
+
 ObjCInterfaceRecord *RecordsSlice::findObjCInterface(StringRef Name) const {
   return findRecord<ObjCInterfaceRecord>(Name, Classes);
 }
@@ -152,21 +191,17 @@ GlobalRecord *RecordsSlice::addGlobal(StringRef Name, RecordLinkage Linkage,
 
 ObjCInterfaceRecord *RecordsSlice::addObjCInterface(StringRef Name,
                                                     RecordLinkage Linkage,
-                                                    bool HasEHType) {
+                                                    ObjCIFSymbolKind SymType) {
   Name = copyString(Name);
   auto Result = Classes.insert({Name, nullptr});
-  if (Result.second) {
+  if (Result.second)
     Result.first->second =
-        std::make_unique<ObjCInterfaceRecord>(Name, Linkage, HasEHType);
-  } else {
-    // ObjC classes represent multiple symbols that could have competing
-    // linkages, in those cases assign the largest one.
-    if (Linkage >= RecordLinkage::Rexported)
-      updateLinkage(Result.first->second.get(), Linkage);
-  }
-
+        std::make_unique<ObjCInterfaceRecord>(Name, Linkage, SymType);
+  else
+    Result.first->second->updateLinkageForSymbols(SymType, Linkage);
   return Result.first->second.get();
 }
+
 SymbolFlags Record::mergeFlags(SymbolFlags Flags, RecordLinkage Linkage) {
   // Add Linkage properties into Flags.
   switch (Linkage) {
diff --git a/llvm/lib/TextAPI/Symbol.cpp b/llvm/lib/TextAPI/Symbol.cpp
index e67627e139831..c899821e20f40 100644
--- a/llvm/lib/TextAPI/Symbol.cpp
+++ b/llvm/lib/TextAPI/Symbol.cpp
@@ -72,30 +72,23 @@ bool Symbol::operator==(const Symbol &O) const {
          std::tie(O.Name, O.Kind, O.Targets, RHSFlags);
 }
 
-SimpleSymbol parseSymbol(StringRef SymName, const SymbolFlags Flags) {
+SimpleSymbol parseSymbol(StringRef SymName) {
   if (SymName.starts_with(ObjC1ClassNamePrefix))
     return {SymName.drop_front(ObjC1ClassNamePrefix.size()),
-            EncodeKind::ObjectiveCClass};
+            EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::Class};
   if (SymName.starts_with(ObjC2ClassNamePrefix))
     return {SymName.drop_front(ObjC2ClassNamePrefix.size()),
-            EncodeKind::ObjectiveCClass};
+            EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::Class};
   if (SymName.starts_with(ObjC2MetaClassNamePrefix))
     return {SymName.drop_front(ObjC2MetaClassNamePrefix.size()),
-            EncodeKind::ObjectiveCClass};
-  if (SymName.starts_with(ObjC2EHTypePrefix)) {
-    // When classes without ehtype are used in try/catch blocks
-    // a weak-defined symbol is exported. In those cases, treat these as a
-    // global instead.
-    if ((Flags & SymbolFlags::WeakDefined) == SymbolFlags::WeakDefined)
-      return {SymName, EncodeKind::GlobalSymbol};
+            EncodeKind::ObjectiveCClass, ObjCIFSymbolKind::MetaClass};
+  if (SymName.starts_with(ObjC2EHTypePrefix))
     return {SymName.drop_front(ObjC2EHTypePrefix.size()),
-            EncodeKind::ObjectiveCClassEHType};
-  }
-
+            EncodeKind::ObjectiveCClassEHType, ObjCIFSymbolKind::EHType};
   if (SymName.starts_with(ObjC2IVarPrefix))
     return {SymName.drop_front(ObjC2IVarPrefix.size()),
-            EncodeKind::ObjectiveCInstanceVariable};
-  return {SymName, EncodeKind::GlobalSymbol};
+            EncodeKind::ObjectiveCInstanceVariable, ObjCIFSymbolKind::None};
+  return {SymName, EncodeKind::GlobalSymbol, ObjCIFSymbolKind::None};
 }
 
 } // end namespace MachO.
diff --git a/llvm/lib/TextAPI/SymbolSet.cpp b/llvm/lib/TextAPI/SymbolSet.cpp
index 0cbfa2f6bc2d6..2e0b4160c9b46 100644
--- a/llvm/lib/TextAPI/SymbolSet.cpp
+++ b/llvm/lib/TextAPI/SymbolSet.cpp
@@ -28,6 +28,21 @@ Symbol *SymbolSet::addGlobal(EncodeKind Kind, StringRef Name, SymbolFlags Flags,
   return Sym;
 }
 
-const Symbol *SymbolSet::findSymbol(EncodeKind Kind, StringRef Name) const {
-  return Symbols.lookup({Kind, Name});
+const Symbol *SymbolSet::findSymbol(EncodeKind Kind, StringRef Name,
+                                    ObjCIFSymbolKind ObjCIF) const {
+  if (auto result = Symbols.lookup({Kind, Name}))
+    return result;
+  if ((ObjCIF == ObjCIFSymbolKind::None) || (ObjCIF > ObjCIFSymbolKind::EHType))
+    return nullptr;
+  assert(ObjCIF <= ObjCIFSymbolKind::EHType &&
+         "expected single ObjCIFSymbolKind enum value");
+  // Non-complete ObjC Interfaces are represented as global symbols.
+  if (ObjCIF == ObjCIFSymbolKind::Class)
+    return Symbols.lookup(
+        {EncodeKind::GlobalSymbol, (ObjC2ClassNamePrefix + Name).str()});
+  if (ObjCIF == ObjCIFSymbolKind::MetaClass)
+    return Symbols.lookup(
+        {EncodeKind::GlobalSymbol, (ObjC2MetaClassNamePrefix + Name).str()});
+  return Symbols.lookup(
+      {EncodeKind::GlobalSymbol, (ObjC2EHTypePrefix + Name).str()});
 }
diff --git a/llvm/test/tools/llvm-readtapi/stubify-ehtypes.test b/llvm/test/tools/llvm-readtapi/stubify-ehtypes.test
new file mode 100644
index 0000000000000..2efed81f6d340
--- /dev/null
+++ b/llvm/test/tools/llvm-readtapi/stubify-ehtypes.test
@@ -0,0 +1,859 @@
+; RUN: rm -rf %t
+; RUN: split-file %s %t
+; RUN: yaml2obj %t/EHTypes.yaml -o %t/EHTypes
+; RUN: llvm-readtapi -stubify %t/EHTypes -o %t/EHTypes.tbd 2>&1 | FileCheck %s --allow-empty 
+; RUN: llvm-readtapi -compare %t/EHTypes.tbd %t/expected.tbd 2>&1 | FileCheck %s --allow-empty 
+
+; CHECK-NOT: error: 
+; CHECK-NOT: warning: 
+
+;--- expected.tbd
+{
+  "main_library": {
+    "exported_symbols": [
+      {
+        "data": {
+          "objc_class": [
+            "Custom"
+          ],
+          "weak": [
+            "_OBJC_EHTYPE_$_NSObject"
+          ]
+        }
+      }
+    ],
+    "flags": [
+      {
+        "attributes": [
+          "not_app_extension_safe"
+        ]
+      }
+    ],
+    "install_names": [
+      {
+        "name": "/System/Library/Frameworks/EHTypes.framework/Versions/A/EHTypes"
+      }
+    ],
+    "target_info": [
+      {
+        "min_deployment": "13",
+        "target": "x86_64-macos"
+      }
+    ]
+  },
+  "tapi_tbd_version": 5
+}
+
+;--- EHTypes.yaml
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x1000007
+  cpusubtype:      0x3
+  filetype:        0x6
+  ncmds:           16
+  sizeofcmds:      2208
+  flags:           0x118085
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         712
+    segname:         __TEXT
+    vmaddr:          0
+    vmsize:          12288
+    fileoff:         0
+    filesize:        12288
+    maxprot:         5
+    initprot:        5
+    nsects:          8
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x1CC0
+        size:            84
+        offset:          0x1CC0
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         554889E55350488D3D4B13000031C0E84C0000004883C4085B5DC34889C383FA0175294889DFE83B000000488D3D4613000031C0E8270000004883C4085B5DE9160000004889C3E80E0000004889DFE800000000
+      - sectname:        __stubs
+        segname:         __TEXT
+        addr:            0x1D14
+        size:            24
+        offset:          0x1D14
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000408
+        reserved1:       0x3
+        reserved2:       0x6
+        reserved3:       0x0
+        content:         FF25E6220000FF25E8220000FF25EA220000FF25EC220000
+      - sectname:        __stub_helper
+        segname:         __TEXT
+        addr:            0x1D2C
+        size:            56
+        offset:          0x1D2C
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         4C8D1D052300004153FF25D5120000906800000000E9E6FFFFFF6816000000E9DCFFFFFF682C000000E9D2FFFFFF6839000000E9C8FFFFFF
+      - sectname:        __gcc_except_tab
+        segname:         __TEXT
+        addr:            0x1D64
+        size:            28
+        offset:          0x1D64
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         FF9B190110060E1B01141700002B0E4400391B000001000084120000
+      - sectname:        __cstring
+        segname:         __TEXT
+        addr:            0x1D80
+        size:            44
+        offset:          0x1D80
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x2
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         4E534F626A65637400437573746F6D0074727920626C6F636B00657863657074696F6E0076313640303A3800
+      - sectname:        __objc_methname
+        segname:         __TEXT
+        addr:            0x1DAC
+        size:            10
+        offset:          0x1DAC
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x2
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         74657374436C61737300
+      - sectname:        __unwind_info
+        segname:         __TEXT
+        addr:            0x1DB8
+        size:            4164
+        offset:          0x1DB8
+        align:           2
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         010000001C00000001000000200000000100000024000000020000000100015108300000C01C0000440000003C000000141D00000000000044000000C01C0000641D0000030000000C0001001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+      - sectname:        __eh_frame
+        segname:         __TEXT
+        addr:            0x2E00
+        size:            32
+        offset:          0x2E00
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x6000000B
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         1C00000000000000017A504C5200017810079BF501000010100C070890010000
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         __DATA_CONST
+    vmaddr:          12288
+    vmsize:          4096
+    fileoff:         12288
+    filesize:        4096
+    maxprot:         3
+    initprot:        3
+    nsects:          4
+    flags:           16
+    Sections:
+      - sectname:        __got
+        segname:         __DATA_CONST
+        addr:            0x3000
+        size:            24
+        offset:          0x3000
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x6
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '204000000000000000000000000000000000000000000000'
+      - sectname:        __cfstring
+        segname:         __DATA_CONST
+        addr:            0x3018
+        size:            64
+        offset:          0x3018
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         0000000000000000C807000000000000901D00000000000009000000000000000000000000000000C8070000000000009A1D0000000000000900000000000000
+      - sectname:        __objc_classlist
+        segname:         __DATA_CONST
+        addr:            0x3058
+        size:            8
+        offset:          0x3058
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x10000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '1841000000000000'
+      - sectname:        __objc_imageinfo
+        segname:         __DATA_CONST
+        addr:            0x3060
+        size:            8
+        offset:          0x3060
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '0000000040000000'
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         392
+    segname:         __DATA
+    vmaddr:          16384
+    vmsize:          4096
+    fileoff:         16384
+    filesize:        4096
+    maxprot:         3
+    initprot:        3
+    nsects:          4
+    flags:           0
+    Sections:
+      - sectname:        __la_symbol_ptr
+        segname:         __DATA
+        addr:            0x4000
+        size:            32
+        offset:          0x4000
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x7
+        reserved1:       0x7
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         3C1D000000000000461D000000000000501D0000000000005A1D000000000000
+      - sectname:        __data
+        segname:         __DATA
+        addr:            0x4020
+        size:            32
+        offset:          0x4020
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         1000000000000000801D00000000000000000000000000000000000000000000
+      - sectname:        __objc_const
+        segname:         __DATA
+        addr:            0x4040
+        size:            176
+        offset:          0x4040
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         1800000001000000AC1D000000000000A41D000000000000C01C000000000000010000002800000028000000000000000000000000000000891D00000000000040400000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000008000000000000000000000000000000891D00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+      - sectname:        __objc_data
+        segname:         __DATA
+        addr:            0x40F0
+        size:            80
+        offset:          0x40F0
+        align:           3
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         00000000000000000000000000000000000000000000000000000000000000006040000000000000F040000000000000000000000000000000000000000000000000000000000000A840000000000000
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         72
+    segname:         __LINKEDIT
+    vmaddr:          20480
+    vmsize:          1272
+    fileoff:         20480
+    filesize:        1272
+    maxprot:         1
+    initprot:        1
+    nsects:          0
+    flags:           0
+  - cmd:             LC_DYLD_INFO_ONLY
+    cmdsize:         48
+    rebase_off:      20480
+    rebase_size:     32
+    bind_off:        20512
+    bind_size:       224
+    weak_bind_off:   20736
+    weak_bind_size:  32
+    lazy_bind_off:   20768
+    lazy_bind_size:  88
+    export_off:      20856
+    export_size:     88
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          20952
+    nsyms:           20
+    stroff:          21320
+    strsize:         432
+  - cmd:             LC_DYSYMTAB
+    cmdsize:         80
+    ilocalsym:       0
+    nlocalsym:       6
+    iextdefsym:      6
+    nextdefsym:      3
+    iundefsym:       9
+    nundefsym:       11
+    tocoff:          0
+    ntoc:            0
+    modtaboff:       0
+    nmodtab:         0
+    extrefsymoff:    0
+    nextrefsyms:     0
+    indirectsymoff:  21272
+    nindirectsyms:   11
+    extreloff:       0
+    nextrel:         0
+    locreloff:       0
+    nlocrel:         0
+  - cmd:             LC_ID_DYLIB
+    cmdsize:         88
+    dylib:
+      name:            24
+      timestamp:       0
+      current_version: 65536
+      compatibility_version: 65536
+    Content:         '/System/Library/Frameworks/EHTypes.framework/Versions/A/EHTypes'
+    ZeroPadBytes:    1
+  - cmd:             LC_UUID
+    cmdsize:         24
+    uuid:            4C4C44D7-5555-3144-A1F0-5AD6F1CB175B
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         32
+    platform:        1
+    minos:           851968
+    sdk:             918272
+    ntools:          1
+    Tools:
+      - tool:            4
+        version:         1245184
+  - cmd:             LC_LOAD_DYLIB
+    cmdsize:         96
+    dylib:
+      name:            24
+      timestamp:       0
+      current_version: 144310272
+      compatibility_version: 19660800
+    Content:         '/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation'
+    ZeroPadBytes:    3
+  - cmd:             LC_LOAD_DYLIB
+    cmdsize:         104
+    dylib:
+      name:            24
+      timestamp:       0
+      current_version: 144310272
+      compatibility_version: 9830400
+    Content:         '/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation'
+    ZeroPadBytes:    3
+  - cmd:             LC_LOAD_DYLIB
+    cmdsize:         56
+    dylib:
+      name:            24
+      timestamp:       0
+      current_version: 14942208
+      compatibility_version: 65536
+    Content:         '/usr/lib/libobjc.A.dylib'
+    ZeroPadBytes:    8
+  - cmd:             LC_LOAD_DYLIB
+    cmdsize:         56
+    dylib:
+      name:            24
+      timestamp:       0
+      current_version: 87576577
+      compatibility_version: 65536
+    Content:         '/usr/lib/libSystem.B.dylib'
+    ZeroPadBytes:    6
+  - cmd:             LC_FUNCTION_STARTS
+    cmdsize:         16
+    dataoff:         20944
+    datasize:        8
+  - cmd:             LC_DATA_IN_CODE
+    cmdsize:         16
+    dataoff:         20952
+    datasize:        0
+LinkEditData:
+  RebaseOpcodes:
+    - Opcode:          REBASE_OPCODE_SET_TYPE_IMM
+      Imm:             1
+    - Opcode:          REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             1
+      ExtraData:       [ 0x0 ]
+    - Opcode:          REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
+      Imm:             0
+      ExtraData:       [ 0x20 ]
+    - Opcode:          REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
+      Imm:             0
+      ExtraData:       [ 0x18 ]
+    - Opcode:          REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
+      Imm:             0
+      ExtraData:       [ 0x2, 0x8 ]
+    - Opcode:          REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ExtraData:       [ 0x0 ]
+    - Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+      Imm:             4
+    - Opcode:          REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+      Imm:             1
+    - Opcode:          REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
+      Imm:             0
+      ExtraData:       [ 0x18 ]
+    - Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+      Imm:             3
+    - Opcode:          REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+      Imm:             3
+    - Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+      Imm:             2
+    - Opcode:          REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+      Imm:             7
+    - Opcode:          REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
+      Imm:             0
+      ExtraData:       [ 0x48 ]
+    - Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+      Imm:             2
+    - Opcode:          REBASE_OPCODE_ADD_ADDR_IMM_SCALED
+      Imm:             3
+    - Opcode:          REBASE_OPCODE_DO_REBASE_IMM_TIMES
+      Imm:             1
+    - Opcode:          REBASE_OPCODE_DONE
+      Imm:             0
+  BindOpcodes:
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          ___objc_personality_v0
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             3
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             1
+      ULEBExtraData:   [ 0x8 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          dyld_stub_binder
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             4
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          ___CFConstantStringClassReference
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             2
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_ADD_ADDR_ULEB
+      Imm:             0
+      ULEBExtraData:   [ 0x18 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          _objc_ehtype_vtable
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             3
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ULEBExtraData:   [ 0x20 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_ADDEND_SLEB
+      Imm:             0
+      SLEBExtraData:   [ 16 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          '_OBJC_CLASS_$_NSObject'
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_ADD_ADDR_ULEB
+      Imm:             0
+      ULEBExtraData:   [ 0x8 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_ADDEND_SLEB
+      Imm:             0
+      SLEBExtraData:   [ 0 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_ADD_ADDR_ULEB
+      Imm:             0
+      ULEBExtraData:   [ 0xE8 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          '_OBJC_METACLASS_$_NSObject'
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_ADD_ADDR_ULEB
+      Imm:             0
+      ULEBExtraData:   [ 0xFFFFFFFFFFFFFFC8 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          __objc_empty_cache
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_ADD_ADDR_ULEB
+      Imm:             0
+      ULEBExtraData:   [ 0x20 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+  WeakBindOpcodes:
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          '_OBJC_EHTYPE_$_NSObject'
+    - Opcode:          BIND_OPCODE_SET_TYPE_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             1
+      ULEBExtraData:   [ 0x0 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+  LazyBindOpcodes:
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ULEBExtraData:   [ 0x0 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             4
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          __Unwind_Resume
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ULEBExtraData:   [ 0x8 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             3
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          _objc_end_catch
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ULEBExtraData:   [ 0x10 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             1
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          _NSLog
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
+      Imm:             2
+      ULEBExtraData:   [ 0x18 ]
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_DYLIB_ORDINAL_IMM
+      Imm:             3
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
+      Imm:             0
+      Symbol:          _objc_begin_catch
+    - Opcode:          BIND_OPCODE_DO_BIND
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+    - Opcode:          BIND_OPCODE_DONE
+      Imm:             0
+      Symbol:          ''
+  ExportTrie:
+    TerminalSize:    0
+    NodeOffset:      0
+    Name:            ''
+    Flags:           0x0
+    Address:         0x0
+    Other:           0x0
+    ImportName:      ''
+    Children:
+      - TerminalSize:    0
+        NodeOffset:      10
+        Name:            _OBJC_
+        Flags:           0x0
+        Address:         0x0
+        Other:           0x0
+        ImportName:      ''
+        Children:
+          - TerminalSize:    4
+            NodeOffset:      67
+            Name:            'EHTYPE_$_NSObject'
+            Flags:           0x4
+            Address:         0x4020
+            Other:           0x0
+            ImportName:      ''
+          - TerminalSize:    4
+            NodeOffset:      73
+            Name:            'CLASS_$_Custom'
+            Flags:           0x0
+            Address:         0x4118
+            Other:           0x0
+            ImportName:      ''
+          - TerminalSize:    4
+            NodeOffset:      79
+            Name:            'METACLASS_$_Custom'
+            Flags:           0x0
+            Address:         0x40F0
+            Other:           0x0
+            ImportName:      ''
+  NameList:
+    - n_strx:          2
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         7360
+    - n_strx:          22
+      n_type:          0xE
+      n_sect:          4
+      n_desc:          0
+      n_value:         7524
+    - n_strx:          40
+      n_type:          0xE
+      n_sect:          15
+      n_desc:          0
+      n_value:         16448
+    - n_strx:          70
+      n_type:          0xE
+      n_sect:          15
+      n_desc:          0
+      n_value:         16480
+    - n_strx:          99
+      n_type:          0xE
+      n_sect:          15
+      n_desc:          0
+      n_value:         16552
+    - n_strx:          124
+      n_type:          0xE
+      n_sect:          14
+      n_desc:          0
+      n_value:         16440
+    - n_strx:          139
+      n_type:          0xF
+      n_sect:          14
+      n_desc:          128
+      n_value:         16416
+    - n_strx:          163
+      n_type:          0xF
+      n_sect:          16
+      n_desc:          0
+      n_value:         16624
+    - n_strx:          188
+      n_type:          0xF
+      n_sect:          16
+      n_desc:          0
+      n_value:         16664
+    - n_strx:          209
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          256
+      n_value:         0
+    - n_strx:          216
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          239
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          266
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          1024
+      n_value:         0
+    - n_strx:          282
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          512
+      n_value:         0
+    - n_strx:          316
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          339
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          358
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          376
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          396
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          768
+      n_value:         0
+    - n_strx:          412
+      n_type:          0x1
+      n_sect:          0
+      n_desc:          1024
+      n_value:         0
+  StringTable:
+    - ' '
+    - '+[Custom testClass]'
+    - GCC_except_table0
+    - '__OBJC_$_CLASS_METHODS_Custom'
+    - '__OBJC_METACLASS_RO_$_Custom'
+    - '__OBJC_CLASS_RO_$_Custom'
+    - __dyld_private
+    - '_OBJC_EHTYPE_$_NSObject'
+    - '_OBJC_METACLASS_$_Custom'
+    - '_OBJC_CLASS_$_Custom'
+    - _NSLog
+    - '_OBJC_CLASS_$_NSObject'
+    - '_OBJC_METACLASS_$_NSObject'
+    - __Unwind_Resume
+    - ___CFConstantStringClassReference
+    - ___objc_personality_v0
+    - __objc_empty_cache
+    - _objc_begin_catch
+    - _objc_ehtype_vtable
+    - _objc_end_catch
+    - dyld_stub_binder
+    - ''
+    - ''
+    - ''
+  IndirectSymbols: [ 0x6, 0xE, 0x13, 0xC, 0x12, 0x9, 0x10, 0xC, 0x12, 0x9, 
+                     0x10 ]
+  FunctionStarts:  [ 0x1CC0 ]
+...
diff --git a/llvm/unittests/TextAPI/RecordTests.cpp b/llvm/unittests/TextAPI/RecordTests.cpp
index dbe58ca0eea59..37289eca1bdf6 100644
--- a/llvm/unittests/TextAPI/RecordTests.cpp
+++ b/llvm/unittests/TextAPI/RecordTests.cpp
@@ -33,9 +33,12 @@ TEST(TAPIRecord, Simple) {
 }
 
 TEST(TAPIRecord, SimpleObjC) {
-  ObjCInterfaceRecord Class{"NSObject", RecordLinkage::Exported};
+  const ObjCIFSymbolKind CompleteInterface =
+      ObjCIFSymbolKind::Class | ObjCIFSymbolKind::MetaClass;
+  ObjCInterfaceRecord Class{"NSObject", RecordLinkage::Exported,
+                            CompleteInterface};
   ObjCInterfaceRecord ClassEH{"NSObject", RecordLinkage::Exported,
-                              /*HasEHType=*/true};
+                              CompleteInterface | ObjCIFSymbolKind::EHType};
 
   EXPECT_TRUE(Class.isExported());
   EXPECT_EQ(Class.isExported(), ClassEH.isExported());
@@ -43,6 +46,31 @@ TEST(TAPIRecord, SimpleObjC) {
   EXPECT_TRUE(ClassEH.hasExceptionAttribute());
   EXPECT_EQ(ObjCIVarRecord::createScopedName("NSObject", "var"),
             "NSObject.var");
+  EXPECT_TRUE(Class.isCompleteInterface());
+  EXPECT_TRUE(ClassEH.isCompleteInterface());
+  EXPECT_TRUE(Class.isExportedSymbol(ObjCIFSymbolKind::MetaClass));
+  EXPECT_EQ(ClassEH.getLinkageForSymbol(ObjCIFSymbolKind::EHType),
+            RecordLinkage::Exported);
+}
+
+TEST(TAPIRecord, IncompleteObjC) {
+  ObjCInterfaceRecord Class{"NSObject", RecordLinkage::Rexported,
+                            ObjCIFSymbolKind::MetaClass};
+  EXPECT_EQ(Class.getLinkageForSymbol(ObjCIFSymbolKind::EHType),
+            RecordLinkage::Unknown);
+  EXPECT_EQ(Class.getLinkageForSymbol(ObjCIFSymbolKind::MetaClass),
+            RecordLinkage::Rexported);
+  EXPECT_TRUE(Class.isExportedSymbol(ObjCIFSymbolKind::MetaClass));
+  EXPECT_FALSE(Class.isCompleteInterface());
+  EXPECT_TRUE(Class.isExported());
+
+  Class.updateLinkageForSymbols(ObjCIFSymbolKind::Class,
+                                RecordLinkage::Internal);
+  EXPECT_TRUE(Class.isExported());
+  EXPECT_FALSE(Class.isCompleteInterface());
+  EXPECT_FALSE(Class.isExportedSymbol(ObjCIFSymbolKind::Class));
+  EXPECT_EQ(Class.getLinkageForSymbol(ObjCIFSymbolKind::Class),
+            RecordLinkage::Internal);
 }
 
 TEST(TAPIRecord, SimpleSlice) {
diff --git a/llvm/unittests/TextAPI/TextStubV5Tests.cpp b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
index ba6bf1ab4ef90..c77d13ef8f230 100644
--- a/llvm/unittests/TextAPI/TextStubV5Tests.cpp
+++ b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
@@ -1230,6 +1230,84 @@ TEST(TBDv5, NotForSharedCache) {
   EXPECT_TRUE(ReadFile->isOSLibNotForSharedCache());
 }
 
+TEST(TBDv5, ObjCInterfaces) {
+  static const char TBDv5File[] = R"({ 
+"tapi_tbd_version": 5,
+"main_library": {
+  "target_info": [
+    {
+      "target": "arm64-ios-simulator",
+      "min_deployment": "14.0"
+    }
+  ],
+  "install_names":[
+    { "name":"/S/L/F/Foo.framework/Foo" }
+  ],
+  "exported_symbols": [
+    {
+      "data": {
+         "global": [
+              "_global",
+              "_OBJC_METACLASS_$_Standalone",
+              "_OBJC_CLASS_$_Standalone2"
+          ],
+          "weak": ["_OBJC_EHTYPE_$_NSObject"],
+          "objc_class": [
+              "ClassA",
+              "ClassB"
+          ],
+          "objc_eh_type": ["ClassA"]
+      }
+    }]
+}})";
+
+  Expected<TBDFile> Result =
+      TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
+  EXPECT_TRUE(!!Result);
+  TBDFile File = std::move(Result.get());
+  EXPECT_EQ(FileType::TBD_V5, File->getFileType());
+  Target ExpectedTarget =
+      Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(14, 0));
+  EXPECT_EQ(*File->targets().begin(), ExpectedTarget);
+
+  // Check Symbols.
+  ExportedSymbolSeq Exports;
+  for (const auto *Sym : File->symbols()) {
+    ExportedSymbol Temp =
+        ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
+                       Sym->isWeakDefined() || Sym->isWeakReferenced(),
+                       Sym->isThreadLocalValue(), Sym->isData()};
+    Exports.emplace_back(std::move(Temp));
+  }
+  llvm::sort(Exports);
+
+  std::vector<ExportedSymbol> ExpectedExports = {
+      {EncodeKind::GlobalSymbol, "_OBJC_CLASS_$_Standalone2", false, false,
+       true},
+      {EncodeKind::GlobalSymbol, "_OBJC_EHTYPE_$_NSObject", true, false, true},
+      {EncodeKind::GlobalSymbol, "_OBJC_METACLASS_$_Standalone", false, false,
+       true},
+      {EncodeKind::GlobalSymbol, "_global", false, false, true},
+      {EncodeKind::ObjectiveCClass, "ClassA", false, false, true},
+      {EncodeKind::ObjectiveCClass, "ClassB", false, false, true},
+      {EncodeKind::ObjectiveCClassEHType, "ClassA", false, false, true}};
+
+  EXPECT_EQ(ExpectedExports.size(), Exports.size());
+  EXPECT_TRUE(
+      std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
+
+  SmallString<4096> Buffer;
+  raw_svector_ostream OS(Buffer);
+  Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
+  EXPECT_TRUE(!WriteResult);
+
+  Expected<TBDFile> Output =
+      TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
+  EXPECT_TRUE(!!Output);
+  TBDFile WriteResultFile = std::move(Output.get());
+  EXPECT_EQ(*File, *WriteResultFile);
+}
+
 TEST(TBDv5, MergeIF) {
   static const char TBDv5FileA[] = R"({
 "tapi_tbd_version": 5,



More information about the llvm-commits mailing list