From afed9308807d233f0da163b72e613b4a468c5c75 Mon Sep 17 00:00:00 2001
From: Iain Sandoe <iain@sandoe.co.uk>
Date: Sun, 2 Sep 2018 15:12:51 +0100
Subject: [PATCH] [llvm, objc] Add Apple ObjCMetaData library copied from
 clang-800.0.42.1.

---
 llvm/include/llvm/ObjCMetadata/ObjCBitcode.h  |  122 ++
 .../llvm/ObjCMetadata/ObjCMachOBinary.h       |  136 ++
 llvm/include/llvm/ObjCMetadata/ObjCMetadata.h |  298 ++++
 llvm/lib/CMakeLists.txt                       |    1 +
 llvm/lib/ObjCMetadata/CMakeLists.txt          |   11 +
 llvm/lib/ObjCMetadata/ObjCBitcode.cpp         |  863 +++++++++++
 llvm/lib/ObjCMetadata/ObjCMachOBinary.cpp     | 1356 +++++++++++++++++
 llvm/lib/ObjCMetadata/ObjCMetadata.cpp        |  177 +++
 llvm/lib/ObjCMetadata/macho-obj.h             |  588 +++++++
 9 files changed, 3552 insertions(+)
 create mode 100644 llvm/include/llvm/ObjCMetadata/ObjCBitcode.h
 create mode 100644 llvm/include/llvm/ObjCMetadata/ObjCMachOBinary.h
 create mode 100644 llvm/include/llvm/ObjCMetadata/ObjCMetadata.h
 create mode 100644 llvm/lib/ObjCMetadata/CMakeLists.txt
 create mode 100644 llvm/lib/ObjCMetadata/ObjCBitcode.cpp
 create mode 100644 llvm/lib/ObjCMetadata/ObjCMachOBinary.cpp
 create mode 100644 llvm/lib/ObjCMetadata/ObjCMetadata.cpp
 create mode 100644 llvm/lib/ObjCMetadata/macho-obj.h

diff --git a/llvm/include/llvm/ObjCMetadata/ObjCBitcode.h b/llvm/include/llvm/ObjCMetadata/ObjCBitcode.h
new file mode 100644
index 00000000000..980c874879b
--- /dev/null
+++ b/llvm/include/llvm/ObjCMetadata/ObjCBitcode.h
@@ -0,0 +1,122 @@
+//===- ObjCBitcode.h - ObjC Metadata Bitcode Interface ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares ObjCBitcode interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJCMETADATA_OBJCBITCODE_H
+#define LLVM_OBJCMETADATA_OBJCBITCODE_H
+
+#include <llvm/ADT/SmallVector.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/IR/Constants.h>
+#include <llvm/IR/GlobalValue.h>
+#include <llvm/IR/Module.h>
+#include <llvm/ObjCMetadata/ObjCMetadata.h>
+
+namespace llvm {
+
+class BitcodeMetadata : public ObjCMetaDataReader {
+public:
+  BitcodeMetadata(Module *M);
+
+  bool isObjC1() const override;
+  bool isObjC2() const override;
+
+  const Module *getOwningModule() const {
+    return OwningModule;
+  }
+
+  // Overrides ObjC Class Ref Implementation.
+  Expected<ObjCClassList> classes() const override;
+  Expected<ObjCClass> getObjCClassFromRef(ObjCClassRef Ref) const override;
+  bool isObjCClassExternal(ObjCClassRef Ref) const override;
+
+  // Overrides ObjC Category Ref Implementation.
+  Expected<ObjCCategoryList> categories() const override;
+  Expected<ObjCCategory>
+  getObjCCategoryFromRef(ObjCCategoryRef Ref) const override;
+
+  // Overrides ObjC Protocol Ref Implementation.
+  Expected<ObjCProtocolList> protocols() const override;
+  Expected<ObjCProtocol>
+  getObjCProtocolFromRef(ObjCProtocolRef Ref) const override;
+
+  // Overrides ObjC Class Implementation.
+  Expected<StringRef> getObjCClassName(ObjCClass ClassRef) const override;
+  Expected<StringRef> getObjCSuperClassName(ObjCClass Data) const override;
+  Expected<bool> isObjCClassSwift(ObjCClass Data) const override;
+  Expected<bool> isObjCClassMetaClass(ObjCClass Data) const override;
+  Expected<ObjCPropertyList>
+  materializePropertyList(ObjCClass Data) const override;
+  Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCClass Data) const override;
+  Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCClass Data) const override;
+
+  // Overrides ObjC Category Implementation.
+  Expected<StringRef> getObjCCategoryName(ObjCCategory Data) const override;
+  Expected<StringRef>
+  getObjCCategoryBaseClassName(ObjCCategory Data) const override;
+  Expected<ObjCPropertyList>
+  materializePropertyList(ObjCCategory Data) const override;
+  Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCCategory Data) const override;
+  Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCCategory Data) const override;
+
+  // Overrides ObjC Protocol Implementation.
+  Expected<StringRef> getObjCProtocolName(ObjCProtocol Data) const override;
+  Expected<ObjCPropertyList>
+  materializePropertyList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeOptionalInstanceMethodList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeOptionalClassMethodList(ObjCProtocol Data) const override;
+
+  // Override ObjC Property Implementation.
+  Expected<StringRef> getPropertyName(ObjCProperty Data) const override;
+  Expected<StringRef> getPropertyAttribute(ObjCProperty Data) const override;
+
+  // Override ObjC Method Implementation.
+  Expected<StringRef> getMethodName(ObjCMethod Data) const override;
+  Expected<StringRef> getMethodType(ObjCMethod Data) const override;
+
+  // Override ObjC Selector Ref Implementation.
+  Expected<ObjCSelectorList> referencedSelectors() const override;
+  Expected<StringRef> getObjCSelectorName(ObjCSelectorRef Ref) const override;
+
+  // Override Potentially defined selectors Implemetation.
+  void getAllPotentiallyDefinedSelectors(StringSet<> &Set) const override;
+
+  // Other.
+  StringRef getSymbolNameFromRef(ObjCRef Ref) const override;
+  StringRef guessClassNameBasedOnSymbol(StringRef Sym) const override;
+
+  // Helper function.
+  bool is64Bit() const {
+    return Triple(OwningModule->getTargetTriple()).isArch64Bit();
+  }
+  const DataLayout &getDataLayout() const {
+    return OwningModule->getDataLayout();
+  }
+  Expected<ConstantStruct*> getObjC2ClassRO(ObjCClass Data) const;
+
+private:
+  Module *OwningModule;
+};
+
+}
+
+#endif
diff --git a/llvm/include/llvm/ObjCMetadata/ObjCMachOBinary.h b/llvm/include/llvm/ObjCMetadata/ObjCMachOBinary.h
new file mode 100644
index 00000000000..3624c84375e
--- /dev/null
+++ b/llvm/include/llvm/ObjCMetadata/ObjCMachOBinary.h
@@ -0,0 +1,136 @@
+//===- ObjCMachOBinary.h - ObjC MachO Metadata Interface ---------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares ObjCMachOBinary interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJCMETADATA_OBJCMACHOBINARY_H
+#define LLVM_OBJCMETADATA_OBJCMACHOBINARY_H
+
+#include <llvm/Object/MachO.h>
+#include <llvm/ObjCMetadata/ObjCMetadata.h>
+
+namespace llvm {
+
+class MachOMetadata : public ObjCMetaDataReader {
+public:
+  MachOMetadata(const object::MachOObjectFile *Binary)
+      : OwningBinary(Binary) {}
+
+  const object::MachOObjectFile *getMachOObject() {
+    return cast<object::MachOObjectFile>(OwningBinary);
+  }
+
+  bool isObjC1() const override;
+  bool isObjC2() const override;
+
+  const object::MachOObjectFile *getOwningBinary() const {
+    return OwningBinary;
+  }
+
+  // Overrides ObjC Class Ref Implementation.
+  Expected<ObjCClassList> classes() const override;
+  Expected<ObjCClass> getObjCClassFromRef(ObjCClassRef Ref) const override;
+  bool isObjCClassExternal(ObjCClassRef Ref) const override;
+
+  // Overrides ObjC Category Ref Implementation.
+  Expected<ObjCCategoryList> categories() const override;
+  Expected<ObjCCategory>
+  getObjCCategoryFromRef(ObjCCategoryRef Ref) const override;
+
+  // Overrides ObjC Protocol Ref Implementation.
+  Expected<ObjCProtocolList> protocols() const override;
+  Expected<ObjCProtocol>
+  getObjCProtocolFromRef(ObjCProtocolRef Ref) const override;
+
+  // Overrides ObjC Class Implementation.
+  Expected<StringRef> getObjCClassName(ObjCClass ClassRef) const override;
+  Expected<StringRef> getObjCSuperClassName(ObjCClass Data) const override;
+  Expected<bool> isObjCClassSwift(ObjCClass Data) const override;
+  Expected<bool> isObjCClassMetaClass(ObjCClass Data) const override;
+  Expected<ObjCPropertyList>
+  materializePropertyList(ObjCClass Data) const override;
+  Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCClass Data) const override;
+  Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCClass Data) const override;
+
+  // Overrides ObjC Category Implementation.
+  Expected<StringRef> getObjCCategoryName(ObjCCategory Data) const override;
+  Expected<StringRef>
+  getObjCCategoryBaseClassName(ObjCCategory Data) const override;
+  Expected<ObjCPropertyList>
+  materializePropertyList(ObjCCategory Data) const override;
+  Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCCategory Data) const override;
+  Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCCategory Data) const override;
+
+  // Overrides ObjC Protocol Implementation.
+  Expected<StringRef> getObjCProtocolName(ObjCProtocol Data) const override;
+  Expected<ObjCPropertyList>
+  materializePropertyList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeOptionalInstanceMethodList(ObjCProtocol Data) const override;
+  Expected<ObjCMethodList>
+  materializeOptionalClassMethodList(ObjCProtocol Data) const override;
+
+  // Override ObjC Property Implementation.
+  Expected<StringRef> getPropertyName(ObjCProperty Data) const override;
+  Expected<StringRef> getPropertyAttribute(ObjCProperty Data) const override;
+
+  // Override ObjC Method Implementation.
+  Expected<StringRef> getMethodName(ObjCMethod Data) const override;
+  Expected<StringRef> getMethodType(ObjCMethod Data) const override;
+
+  // Override ObjC Selector Ref Implementation.
+  Expected<ObjCSelectorList> referencedSelectors() const override;
+  Expected<StringRef> getObjCSelectorName(ObjCSelectorRef Ref) const override;
+
+  // Override Potentially defined selectors Implemetation.
+  void getAllPotentiallyDefinedSelectors(StringSet<> &Set) const override;
+
+  // Other.
+  StringRef getSymbolNameFromRef(ObjCRef Ref) const override;
+  StringRef guessClassNameBasedOnSymbol(StringRef Sym) const override;
+
+  // Helper classes
+  const object::SectionRef getSection(const char *segname,
+                                      const char *sectname) const;
+
+  Expected<StringRef> getValueFromAddress(uint64_t Address, uint64_t size,
+                                          bool objc_only = false) const;
+  Expected<StringRef> getStringFromAddress(uint64_t Address,
+                                           bool allowEmpty = false) const;
+  Expected<StringRef> getSymbolFromAddress(uint64_t Address,
+                                           uint64_t &offset) const;
+  bool isAddressEncrypted(uint64_t Address) const;
+  // Only available on pointer size.
+  Expected<uint64_t> getResolvedValueFromAddress64(uint64_t Address) const;
+  Expected<uint32_t> getResolvedValueFromAddress32(uint64_t Address) const;
+
+  // ObjC2 helper classes
+  Expected<ObjCRef> getObjC2ClassRO64(ObjCClass Data) const;
+  Expected<ObjCRef> getObjC2ClassRO32(ObjCClass Data) const;
+  Expected<ObjCClass> getObjC2MetaClass64(ObjCClass Data) const;
+  Expected<ObjCClass> getObjC2MetaClass32(ObjCClass Data) const;
+  // ObjC1 helper classes
+
+private:
+  const object::MachOObjectFile *OwningBinary;
+};
+
+}
+
+#endif
diff --git a/llvm/include/llvm/ObjCMetadata/ObjCMetadata.h b/llvm/include/llvm/ObjCMetadata/ObjCMetadata.h
new file mode 100644
index 00000000000..b7e1eee9831
--- /dev/null
+++ b/llvm/include/llvm/ObjCMetadata/ObjCMetadata.h
@@ -0,0 +1,298 @@
+//===- ObjCMetadata.h - Objective C Metadata Interface ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares ObjCMetadata Interfaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJCMETADATA_OBJCMETADATA_H
+#define LLVM_OBJCMETADATA_OBJCMETADATA_H
+
+#include <llvm/ADT/StringRef.h>
+#include <llvm/ADT/StringSet.h>
+#include <llvm/ADT/SmallVector.h>
+#include <llvm/IR/Constant.h>
+#include <llvm/Object/SymbolicFile.h>
+#include <llvm/Support/Error.h>
+#include <utility>
+
+namespace llvm {
+
+class ObjCRef {
+public:
+  uint64_t getValue() const { return v.a; }
+  void setValue(uint64_t value) { v.a = value; }
+
+  Constant *getLLVMConstant() const { return v.c; }
+  void setLLVMConstant(Constant *C) { v.c = C; }
+
+  int64_t getOffset() const { return offset; }
+  void setOffset(int64_t bytes) { offset = bytes; }
+
+  ObjCRef() {
+    memset(&v, 0, sizeof(v));
+  }
+  ObjCRef(uint64_t value) : offset (0) {
+    v.a = value;
+  }
+  ObjCRef(Constant *C) : offset (0) {
+    v.c = C;
+  }
+  ObjCRef(Constant *C, int64_t offset) : offset(offset) {
+    v.c = C;
+  }
+
+  bool operator==(const ObjCRef &Other) const {
+    return std::memcmp(&v, &(Other.v), sizeof(v)) == 0;
+  }
+
+  bool operator!=(const ObjCRef &Other) const {
+    return !(*this == Other);
+  }
+
+private:
+  union {
+    uint64_t a;
+    Constant *c;
+  } v;
+  int64_t offset; // only used with v is Constant. FIXME: this is a hack.
+};
+
+class ObjCMetaDataReader;
+class ObjCClassRef;
+class ObjCProtocolRef;
+class ObjCCategoryRef;
+class ObjCMethod;
+class ObjCProperty;
+class ObjCSelectorRef;
+
+typedef SmallVector<ObjCMethod, 2> ObjCMethodList;
+typedef SmallVector<ObjCProperty, 2> ObjCPropertyList;
+typedef SmallVector<ObjCClassRef, 2> ObjCClassList;
+typedef SmallVector<ObjCCategoryRef, 2> ObjCCategoryList;
+typedef SmallVector<ObjCProtocolRef, 2> ObjCProtocolList;
+typedef SmallVector<ObjCSelectorRef, 2> ObjCSelectorList;
+
+class ObjCInfoBase {
+public:
+  ObjCInfoBase(const ObjCMetaDataReader *Reader)
+      : Data(), MetadataReader(Reader) {}
+  ObjCInfoBase(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : Data(Data), MetadataReader(Reader) {}
+
+  bool operator==(const ObjCInfoBase &Other) const {
+    return Data == Other.Data;
+  }
+
+  ObjCRef &getRawContent() { return Data; }
+
+protected:
+  ObjCRef Data;
+  const ObjCMetaDataReader *MetadataReader;
+};
+
+class ObjCProperty : public ObjCInfoBase {
+public:
+  ObjCProperty(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCProperty(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getName() const;
+  Expected<StringRef> getAttribute() const;
+
+  // Query for setter and getter.
+  // Return empty string if doesn't exists.
+  Expected<std::string> getGetter() const;
+  Expected<std::string> getSetter() const;
+};
+
+class ObjCMethod : public ObjCInfoBase {
+public:
+  ObjCMethod(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCMethod(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getName() const;
+  Expected<StringRef> getType() const;
+};
+
+// Interface to read the ObjCClass.
+class ObjCClass : public ObjCInfoBase {
+public:
+  ObjCClass(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCClass(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getName() const;
+  Expected<StringRef> getSuperClassName() const;
+
+  Expected<bool> isSwift() const;
+  Expected<bool> isMetaClass() const;
+
+  Expected<ObjCPropertyList> properties() const;
+  Expected<ObjCMethodList> instanceMethods() const;
+  Expected<ObjCMethodList> classMethods() const;
+};
+
+class ObjCCategory : public ObjCInfoBase {
+public:
+  ObjCCategory(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCCategory(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getName() const;
+  Expected<StringRef> getBaseClassName() const;
+
+  Expected<ObjCPropertyList> properties() const;
+  Expected<ObjCMethodList> instanceMethods() const;
+  Expected<ObjCMethodList> classMethods() const;
+};
+
+class ObjCProtocol : public ObjCInfoBase {
+public:
+  ObjCProtocol(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCProtocol(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getName() const;
+
+  Expected<ObjCPropertyList> properties() const;
+  Expected<ObjCMethodList> instanceMethods() const;
+  Expected<ObjCMethodList> classMethods() const;
+  Expected<ObjCMethodList> optionalInstanceMethods() const;
+  Expected<ObjCMethodList> optionalClassMethods() const;
+};
+
+class ObjCClassRef : public ObjCInfoBase {
+public:
+  ObjCClassRef(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCClassRef(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getClassName() const;
+  bool isExternal() const;
+  Expected<ObjCClass> getObjCClass() const;
+  Expected<ObjCClass> operator*() const { return getObjCClass(); }
+};
+
+class ObjCCategoryRef : public ObjCInfoBase {
+public:
+  ObjCCategoryRef(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCCategoryRef(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<ObjCCategory> getObjCCategory() const;
+  Expected<ObjCCategory> operator*() const { return getObjCCategory(); }
+};
+
+class ObjCProtocolRef : public ObjCInfoBase {
+public:
+  ObjCProtocolRef(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCProtocolRef(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<ObjCProtocol> getObjCProtocol() const;
+  Expected<ObjCProtocol> operator*() const { return getObjCProtocol(); }
+};
+
+class ObjCSelectorRef : public ObjCInfoBase {
+public:
+  ObjCSelectorRef(const ObjCMetaDataReader *Reader) : ObjCInfoBase(Reader) {}
+  ObjCSelectorRef(const ObjCMetaDataReader *Reader, ObjCRef Data)
+      : ObjCInfoBase(Reader, Data) {}
+
+  Expected<StringRef> getSelector() const;
+};
+
+// ObjC Metadata Reader.
+class ObjCMetaDataReader {
+public:
+  virtual ~ObjCMetaDataReader() {}
+
+  // General
+  virtual bool isObjC1() const = 0;
+  virtual bool isObjC2() const = 0;
+
+  // ObjCClassRef.
+  virtual Expected<ObjCClassList> classes() const = 0;
+  virtual Expected<ObjCClass> getObjCClassFromRef(ObjCClassRef Ref) const = 0;
+  virtual bool isObjCClassExternal(ObjCClassRef Ref) const = 0;
+
+  // ObjCCategoryRef.
+  virtual Expected<ObjCCategoryList> categories() const = 0;
+  virtual Expected<ObjCCategory>
+  getObjCCategoryFromRef(ObjCCategoryRef Ref) const = 0;
+
+  // ObjCProtocolRef.
+  virtual Expected<ObjCProtocolList> protocols() const = 0;
+  virtual Expected<ObjCProtocol>
+  getObjCProtocolFromRef(ObjCProtocolRef Ref) const = 0;
+
+  // ObjCClass.
+  virtual Expected<StringRef> getObjCClassName(ObjCClass Data) const = 0;
+  virtual Expected<StringRef>
+  getObjCSuperClassName(ObjCClass Data) const = 0;
+  virtual Expected<bool> isObjCClassSwift(ObjCClass Data) const = 0;
+  virtual Expected<bool> isObjCClassMetaClass(ObjCClass Data) const = 0;
+  virtual Expected<ObjCPropertyList>
+  materializePropertyList(ObjCClass Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCClass Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCClass Data) const = 0;
+  
+  // ObjCCategory.
+  virtual Expected<StringRef> getObjCCategoryName(ObjCCategory Data) const = 0;
+  virtual Expected<StringRef>
+  getObjCCategoryBaseClassName(ObjCCategory Data) const = 0;
+  virtual Expected<ObjCPropertyList>
+  materializePropertyList(ObjCCategory Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCCategory Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCCategory Data) const = 0;
+
+  // ObjCProtocol.
+  virtual Expected<StringRef> getObjCProtocolName(ObjCProtocol Data) const = 0;
+  virtual Expected<ObjCPropertyList>
+  materializePropertyList(ObjCProtocol Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeInstanceMethodList(ObjCProtocol Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeClassMethodList(ObjCProtocol Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeOptionalInstanceMethodList(ObjCProtocol Data) const = 0;
+  virtual Expected<ObjCMethodList>
+  materializeOptionalClassMethodList(ObjCProtocol Data) const = 0;
+  
+  // ObjCProperty.
+  virtual Expected<StringRef> getPropertyName(ObjCProperty Data) const = 0;
+  virtual Expected<StringRef>
+  getPropertyAttribute(ObjCProperty Data) const = 0;
+
+  // ObjCMethod.
+  virtual Expected<StringRef> getMethodName(ObjCMethod Data) const = 0;
+  virtual Expected<StringRef> getMethodType(ObjCMethod Data) const = 0;
+
+  // ObjCSelectorRef.
+  virtual Expected<ObjCSelectorList> referencedSelectors() const = 0;
+  virtual Expected<StringRef>
+  getObjCSelectorName(ObjCSelectorRef Ref) const = 0;
+
+  // Potentially defined selectors.
+  virtual void getAllPotentiallyDefinedSelectors(StringSet<> &Set) const = 0;
+
+  // Other.
+  virtual StringRef getSymbolNameFromRef(ObjCRef Ref) const = 0;
+  virtual StringRef guessClassNameBasedOnSymbol(StringRef Sym) const = 0;
+};
+
+}
+
+#endif
diff --git a/llvm/lib/CMakeLists.txt b/llvm/lib/CMakeLists.txt
index ecf8b93d253..5ed501e0c90 100644
--- a/llvm/lib/CMakeLists.txt
+++ b/llvm/lib/CMakeLists.txt
@@ -14,6 +14,7 @@ add_subdirectory(LTO)
 add_subdirectory(MC)
 add_subdirectory(Object)
 add_subdirectory(ObjectYAML)
+add_subdirectory(ObjCMetadata)
 add_subdirectory(Option)
 add_subdirectory(DebugInfo)
 add_subdirectory(ExecutionEngine)
diff --git a/llvm/lib/ObjCMetadata/CMakeLists.txt b/llvm/lib/ObjCMetadata/CMakeLists.txt
new file mode 100644
index 00000000000..81cd8f2947b
--- /dev/null
+++ b/llvm/lib/ObjCMetadata/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_llvm_library(LLVMObjCMetadata
+  ObjCBitcode.cpp
+  ObjCMetadata.cpp
+  ObjCMachOBinary.cpp
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/ObjCMetadata
+
+  DEPENDS
+  intrinsics_gen
+  )
diff --git a/llvm/lib/ObjCMetadata/ObjCBitcode.cpp b/llvm/lib/ObjCMetadata/ObjCBitcode.cpp
new file mode 100644
index 00000000000..d8026a10b74
--- /dev/null
+++ b/llvm/lib/ObjCMetadata/ObjCBitcode.cpp
@@ -0,0 +1,863 @@
+//===- ObjCBitcode.cpp - Bitcode ObjC Metadata Reader -----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the classes needed to parse ObjCMetadata in Bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjCMetadata/ObjCBitcode.h"
+#include "llvm/ObjCMetadata/ObjCMetadata.h"
+#include "llvm/Analysis/InstructionSimplify.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/Constant.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Operator.h"
+#include "llvm/Support/Error.h"
+
+#include "macho-obj.h"
+
+using namespace llvm;
+using namespace object;
+
+static Value *GetValueAtStructOffset(ConstantStruct *CS, uint64_t offset,
+                                     const DataLayout &DL) {
+  StructType* ST = CS->getType();
+  unsigned index = DL.getStructLayout(ST)->getElementContainingOffset(offset);
+  Value* Ret = CS->getOperand(index);
+  offset -= DL.getStructLayout(ST)->getElementOffset(index);
+  if (offset != 0) {
+    CS = dyn_cast<ConstantStruct>(Ret);
+    ST = CS->getType();
+    return GetValueAtStructOffset(CS, offset, DL);
+  }
+  return Ret;
+}
+
+Value *GetRealValue(Value *GV, const DataLayout &DL) {
+  int64_t offset = 0;
+  auto basePtr = dyn_cast<GlobalVariable>(
+      GetPointerBaseWithConstantOffset(GV, offset, DL));
+  if (!basePtr || !basePtr->hasInitializer()) {
+      return nullptr;
+  }
+  if (offset == 0)
+    return basePtr->getInitializer();
+  else if (auto CS = dyn_cast<ConstantStruct>(basePtr->getInitializer()))
+    return GetValueAtStructOffset(CS, offset, DL);
+  else
+    return nullptr;
+}
+
+static User *GlobalOpToUser(Value *v) {
+  auto base_user = dyn_cast<User>(v);
+  assert(base_user && "Provided value is not a user!");
+  auto op0 = dyn_cast<User>(base_user->getOperand(0));
+  assert(op0 && "User doesn't have User operands!");
+  return op0;
+}
+
+// This is basically the GetUnderlyingObject in ValueTracking Analysis,
+// except it works through non-pointer types.
+static Value *GetUnderlyingValue(Value *V, const DataLayout &DL,
+                                 unsigned MaxLookup) {
+  for (unsigned Count = 0; MaxLookup == 0 || Count < MaxLookup; ++Count) {
+    if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
+      V = GEP->getPointerOperand();
+    } else if (Operator::getOpcode(V) == Instruction::BitCast ||
+               Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
+      V = cast<Operator>(V)->getOperand(0);
+    } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
+      if (!GA->isDefinitionExact())
+        return V;
+      V = GA->getAliasee();
+    } else if (PtrToIntOperator *PTI = dyn_cast<PtrToIntOperator>(V)) {
+      V = PTI->getPointerOperand();
+    } else {
+      // See if InstructionSimplify knows any relevant tricks.
+      if (Instruction *I = dyn_cast<Instruction>(V))
+        // TODO: Acquire a DominatorTree and AssumptionCache and use them.
+        if (Value *Simplified = SimplifyInstruction(I, DL, nullptr)) {
+          V = Simplified;
+          continue;
+        }
+
+      return V;
+    }
+  }
+  return V;
+}
+
+// Check if a selector is actually defined with corresponding method,
+// even though it is not showing up when walking through the objc class
+// info. For example, this will find the selector defined in @objc swift
+// generic class.
+static bool hasUserInMethodList(const Value *V, const Module *M,
+                                unsigned maxDepth = 4) {
+  // Search through all the uses of the selector string to see if there are any
+  // usage in the __DATA,__objc_const section that looks like a method entry.
+  for (const auto &user : V->users()) {
+    if (auto *GV = dyn_cast<GlobalValue>(user)) {
+      if (GV->hasSection()) {
+        StringRef Section = GV->getSection();
+        std::string SectionName;
+        // Trim all spaces in the section name.
+        for (auto c : Section) {
+          if (c != ' ')
+            SectionName.push_back(c);
+        }
+        // Potential match of a method list.
+        // The method list should have type {i32, i32, [n x {i8*, i8*, i8*}]}.
+        if (StringRef(SectionName).startswith("__DATA,__objc_const") &&
+            V->getType()->isStructTy() &&
+            V->getType()->getStructNumElements() == 3 &&
+            V->getType()->getStructElementType(0)->isIntegerTy() &&
+            V->getType()->getStructElementType(1)->isIntegerTy() &&
+            V->getType()->getStructElementType(2)->isArrayTy())
+          return true;
+      }
+    }
+    // Recursively find method list.
+    if (maxDepth != 0 && hasUserInMethodList(user, M, maxDepth - 1))
+      return true;
+  }
+  return false;
+}
+
+BitcodeMetadata::BitcodeMetadata(Module *M) : OwningModule(M) {}
+
+Expected<ObjCClassList> BitcodeMetadata::classes() const {
+  ObjCClassList ClassList;
+  for (auto &GV : OwningModule->globals()) {
+    if (GV.hasSection()) {
+      StringRef Section = GV.getSection();
+      std::string SectionName;
+      // Trim all spaces in the section name.
+      for (auto c : Section) {
+        if (c != ' ')
+          SectionName.push_back(c);
+      }
+      if (SectionName == "__DATA,__objc_classlist,regular,no_dead_strip") {
+        auto structList = dyn_cast<Constant>(
+            GetUnderlyingObject(GV.getInitializer(), getDataLayout(), 2));
+        for (const auto &op : structList->operands())
+          ClassList.push_back(ObjCClassRef(this, cast<Constant>(&op)));
+      }
+    }
+  }
+
+  return ClassList;
+}
+
+Expected<ObjCClass>
+BitcodeMetadata::getObjCClassFromRef(ObjCClassRef Ref) const {
+  auto GV = Ref.getRawContent().getLLVMConstant();
+  int64_t class_offset = 0;
+  auto objc_class = dyn_cast<GlobalVariable>(
+      GetPointerBaseWithConstantOffset(GV, class_offset, getDataLayout()));
+  if (!objc_class)
+    return make_error<StringError>("Unable to find class associsated",
+                                   object_error::parse_failed);
+
+  return ObjCClass(this, {objc_class, class_offset});
+}
+
+bool BitcodeMetadata::isObjCClassExternal(ObjCClassRef Ref) const {
+  if (auto GV = cast<GlobalVariable>(Ref.getRawContent().getLLVMConstant())) {
+    if (GV->hasInitializer())
+      return false;
+  }
+  return true;
+}
+
+Expected<ObjCCategoryList> BitcodeMetadata::categories() const {
+  ObjCCategoryList CategoryList;
+  for (auto &GV : OwningModule->globals()) {
+    if (GV.hasSection()) {
+      StringRef Section = GV.getSection();
+      std::string SectionName;
+      // Trim all spaces in the section name.
+      for (auto c : Section) {
+        if (c != ' ')
+          SectionName.push_back(c);
+      }
+      if (SectionName == "__DATA,__objc_catlist,regular,no_dead_strip") {
+        auto structList = dyn_cast<Constant>(
+            GetUnderlyingObject(GV.getInitializer(), getDataLayout(), 2));
+        for (const auto &op : structList->operands())
+          CategoryList.push_back(ObjCCategoryRef(this, cast<Constant>(&op)));
+      }
+    }
+  }
+  return CategoryList;
+}
+
+Expected<ObjCCategory>
+BitcodeMetadata::getObjCCategoryFromRef(ObjCCategoryRef Ref) const {
+  auto GV = Ref.getRawContent().getLLVMConstant();
+  int64_t cat_offset = 0;
+  auto objc_category = dyn_cast<GlobalVariable>(
+      GetPointerBaseWithConstantOffset(GV, cat_offset, getDataLayout()));
+  if (!objc_category)
+    return make_error<StringError>("Unable to find category associsated",
+                                   object_error::parse_failed);
+
+  return ObjCCategory(this, {objc_category, cat_offset});
+}
+
+Expected<ObjCProtocolList> BitcodeMetadata::protocols() const {
+  ObjCProtocolList ProtocolList;
+  for (auto &GV : OwningModule->globals()) {
+    if (GV.hasSection()) {
+      StringRef Section = GV.getSection();
+      std::string SectionName;
+      // Trim all spaces in the section name.
+      for (auto c : Section) {
+        if (c != ' ')
+          SectionName.push_back(c);
+      }
+      if (SectionName == "__DATA,__objc_protolist,coalesced,no_dead_strip") {
+        ProtocolList.push_back(ObjCProtocolRef(this, &GV));
+      }
+    }
+  }
+  return ProtocolList;
+}
+
+Expected<ObjCProtocol>
+BitcodeMetadata::getObjCProtocolFromRef(ObjCProtocolRef Ref) const {
+  auto GV = cast<GlobalVariable>(Ref.getRawContent().getLLVMConstant());
+  auto protocol = dyn_cast<GlobalVariable>(
+      GetUnderlyingObject(GV->getInitializer(), getDataLayout(), 2));
+  if (!protocol)
+    return make_error<StringError>("Unable to find protocol associsated",
+                                   object_error::parse_failed);
+
+  return ObjCProtocol(this, protocol);
+}
+
+Expected<StringRef>
+BitcodeMetadata::getObjCClassName(ObjCClass ClassRef) const {
+  if (auto ro = getObjC2ClassRO(ClassRef)) {
+    unsigned offset =
+        is64Bit() ? offsetof(class_ro64_t, name) : offsetof(class_ro32_t, name);
+    auto class_name_global = dyn_cast<GlobalVariable>(GetUnderlyingObject(
+        GetValueAtStructOffset(*ro, offset, getDataLayout()), getDataLayout(),
+        2));
+    if (!class_name_global)
+      return make_error<StringError>("Could not read ObjC class name",
+                                     object_error::parse_failed);
+    ConstantDataSequential *CD =
+        dyn_cast<ConstantDataSequential>(class_name_global->getInitializer());
+    if (!CD)
+      return make_error<StringError>(
+          "Class name must be a ConstantDataSequential",
+          object_error::parse_failed);
+    return CD->getAsString().rtrim('\0');
+  } else
+    return ro.takeError();
+}
+
+Expected<StringRef>
+BitcodeMetadata::getObjCSuperClassName(ObjCClass Data) const {
+  auto objc_class =
+      cast<GlobalVariable>(Data.getRawContent().getLLVMConstant());
+  auto objc_class_t = cast<ConstantStruct>(
+      GlobalOpToUser(GetUnderlyingValue(objc_class, getDataLayout(), 2)));
+  int64_t class_offset = Data.getRawContent().getOffset();
+  // read class_ro
+  unsigned offset = is64Bit() ? offsetof(class64_t, superclass)
+                              : offsetof(class32_t, superclass);
+  auto superclass_t = GetValueAtStructOffset(
+      objc_class_t, class_offset + offset, getDataLayout());
+  if (!isa<ConstantPointerNull>(superclass_t)) {
+    if (auto superclass_global = dyn_cast<GlobalVariable>(superclass_t)) {
+      auto superclassref = ObjCClassRef(this, superclass_global);
+      return superclassref.getClassName();
+    } else
+      return make_error<StringError>("Cannot process superclass",
+                                     object_error::parse_failed);
+  }
+  return StringRef();
+}
+
+Expected<bool> BitcodeMetadata::isObjCClassSwift(ObjCClass Data) const {
+  ConstantStruct *objc_class_t = nullptr;
+  if (auto objc_class =
+          dyn_cast<GlobalVariable>(Data.getRawContent().getLLVMConstant())) {
+    objc_class_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_class, getDataLayout(), 2)));
+  } else if (auto objc_class = dyn_cast<ConstantStruct>(
+                 Data.getRawContent().getLLVMConstant()))
+    objc_class_t = objc_class;
+  else
+    return make_error<StringError>("Unexpected type for objc class",
+                                   object_error::parse_failed);
+
+  int64_t class_offset = Data.getRawContent().getOffset();
+  // read class_ro
+  unsigned offset =
+      is64Bit() ? offsetof(class64_t, data) : offsetof(class32_t, data);
+  auto class_ro_v = GetValueAtStructOffset(objc_class_t, class_offset + offset,
+                                           getDataLayout());
+  if (isa<ConstantExpr>(class_ro_v)) {
+    // swift generates class_ro with an offset using add constant expr
+    return true;
+  }
+  return false;
+}
+
+Expected<bool> BitcodeMetadata::isObjCClassMetaClass(ObjCClass Data) const {
+  if (auto ro = getObjC2ClassRO(Data)) {
+    unsigned offset = is64Bit() ? offsetof(class_ro64_t, flags)
+                                : offsetof(class_ro32_t, flags);
+    auto ClassFlag = dyn_cast<ConstantInt>(
+        GetUnderlyingValue(GetValueAtStructOffset(*ro, offset, getDataLayout()),
+                           getDataLayout(), 2));
+    if (!ClassFlag)
+      return make_error<StringError>("Could not get flags from objc class",
+                                     object_error::parse_failed);
+    return ((ClassFlag->getZExtValue() & RO_META) != 0);
+  } else
+    return ro.takeError();
+}
+
+Expected<ObjCPropertyList>
+BitcodeMetadata::materializePropertyList(ObjCClass ClassRef) const {
+  ObjCPropertyList PropertyList;
+  if (auto ro = getObjC2ClassRO(ClassRef)) {
+    unsigned offset = is64Bit() ? offsetof(class_ro64_t, baseProperties)
+                                : offsetof(class_ro32_t, baseProperties);
+    auto objc_prop_list = dyn_cast<GlobalVariable>(
+        GetUnderlyingValue(GetValueAtStructOffset(*ro, offset, getDataLayout()),
+                           getDataLayout(), 2));
+    if (objc_prop_list && objc_prop_list->hasInitializer()) {
+      auto property_list_t = GlobalOpToUser(objc_prop_list);
+      auto property_list = cast<Constant>(property_list_t->getOperand(2));
+      for (auto &op : property_list->operands())
+        PropertyList.push_back(ObjCProperty(this, cast<Constant>(&op)));
+    }
+    return PropertyList;
+  } else
+    return ro.takeError();
+}
+
+Expected<StringRef> BitcodeMetadata::getPropertyName(ObjCProperty Data) const {
+  auto NameVar = dyn_cast<GlobalVariable>(
+      GetUnderlyingValue(Data.getRawContent().getLLVMConstant()->getOperand(0),
+                         getDataLayout(), 2));
+  if (!NameVar)
+    return make_error<StringError>("Could not find property name",
+                                   object_error::parse_failed);
+
+  ConstantDataSequential *CD =
+      dyn_cast<ConstantDataSequential>(NameVar->getInitializer());
+  if (!CD)
+    return make_error<StringError>("Could not parse property name",
+                                   object_error::parse_failed);
+
+  return CD->getAsString().rtrim('\0');
+}
+
+Expected<StringRef>
+BitcodeMetadata::getPropertyAttribute(ObjCProperty Data) const {
+  auto AttrVar = dyn_cast<GlobalVariable>(
+      GetUnderlyingValue(Data.getRawContent().getLLVMConstant()->getOperand(1),
+                         getDataLayout(), 2));
+  if (!AttrVar)
+    return make_error<StringError>("Could not find property attr",
+                                   object_error::parse_failed);
+
+  ConstantDataSequential *CD =
+      dyn_cast<ConstantDataSequential>(AttrVar->getInitializer());
+  if (!CD)
+    return make_error<StringError>("Could not parse property attr",
+                                   object_error::parse_failed);
+
+  return CD->getAsString().rtrim('\0');
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeInstanceMethodList(ObjCClass ClassRef) const {
+  ObjCMethodList MethodList;
+  if (auto ro = getObjC2ClassRO(ClassRef)) {
+    unsigned offset = is64Bit() ? offsetof(class_ro64_t, baseMethods)
+                                : offsetof(class_ro32_t, baseMethods);
+    auto objc_method_list = dyn_cast<User>(
+        GetUnderlyingValue(GetValueAtStructOffset(*ro, offset, getDataLayout()),
+                           getDataLayout(), 2));
+    if (objc_method_list->getNumOperands() != 0) {
+      auto methList =
+          cast<User>(GlobalOpToUser(objc_method_list)->getOperand(2));
+      for (auto &op : methList->operands())
+        MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+    }
+    return MethodList;
+  } else
+    return ro.takeError();
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeClassMethodList(ObjCClass ClassRef) const {
+  ConstantStruct *objc_class_t = nullptr;
+  if (auto objc_class = dyn_cast<GlobalVariable>(
+          ClassRef.getRawContent().getLLVMConstant())) {
+    objc_class_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_class, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc meta class",
+                                   object_error::parse_failed);
+
+  int64_t class_offset = ClassRef.getRawContent().getOffset();
+  auto metaclass =
+      GetValueAtStructOffset(objc_class_t, class_offset, getDataLayout());
+  int64_t metaclass_offset = 0;
+  auto metaclass_g = dyn_cast<GlobalVariable>(GetPointerBaseWithConstantOffset(
+      metaclass, metaclass_offset, getDataLayout()));
+
+  if (!metaclass_g)
+    return make_error<StringError>("Unable to find meta class associsated",
+                                   object_error::parse_failed);
+
+  auto MetaClass = ObjCClass(this, {metaclass_g, metaclass_offset});
+  return materializeInstanceMethodList(MetaClass);
+}
+
+Expected<StringRef>
+BitcodeMetadata::getObjCCategoryName(ObjCCategory Cat) const {
+  ConstantStruct *objc_cat_t = nullptr;
+  if (auto objc_category =
+          dyn_cast<GlobalVariable>(Cat.getRawContent().getLLVMConstant())) {
+    objc_cat_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_category, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc category",
+                                   object_error::parse_failed);
+
+  int64_t cat_offset = Cat.getRawContent().getOffset();
+  unsigned offset =
+      is64Bit() ? offsetof(category64_t, name) : offsetof(category32_t, name);
+  auto catname = dyn_cast<GlobalVariable>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_cat_t, cat_offset + offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (!catname)
+    return make_error<StringError>("Cannot extract catogery name",
+                                   object_error::parse_failed);
+
+  ConstantDataSequential *CD =
+      dyn_cast<ConstantDataSequential>(catname->getInitializer());
+  if (!CD)
+    return make_error<StringError>(
+        "Category name must be a ConstantDataSequential",
+        object_error::parse_failed);
+  return CD->getAsString().rtrim('\0');
+}
+
+Expected<StringRef>
+BitcodeMetadata::getObjCCategoryBaseClassName(ObjCCategory Cat) const {
+  ConstantStruct *objc_cat_t = nullptr;
+  if (auto objc_category =
+          dyn_cast<GlobalVariable>(Cat.getRawContent().getLLVMConstant())) {
+    objc_cat_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_category, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc category",
+                                   object_error::parse_failed);
+
+  int64_t cat_offset = Cat.getRawContent().getOffset();
+  unsigned offset =
+      is64Bit() ? offsetof(category64_t, cls) : offsetof(category32_t, cls);
+  auto baseCls = dyn_cast<GlobalVariable>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_cat_t, cat_offset + offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (!baseCls)
+    return make_error<StringError>("Cannot extract category base class",
+                                   object_error::parse_failed);
+  auto baseClsRef = ObjCClassRef(this, baseCls);
+  return baseClsRef.getClassName();
+}
+
+Expected<ObjCPropertyList>
+BitcodeMetadata::materializePropertyList(ObjCCategory Cat) const {
+  ConstantStruct *objc_cat_t = nullptr;
+  if (auto objc_category =
+          dyn_cast<GlobalVariable>(Cat.getRawContent().getLLVMConstant())) {
+    objc_cat_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_category, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc category",
+                                   object_error::parse_failed);
+
+  ObjCPropertyList PropertyList;
+  int64_t cat_offset = Cat.getRawContent().getOffset();
+  unsigned offset = is64Bit() ? offsetof(category64_t, instanceProperties)
+                              : offsetof(category32_t, instanceProperties);
+  auto props = dyn_cast<GlobalVariable>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_cat_t, cat_offset + offset, getDataLayout()),
+      getDataLayout(), 2));
+
+  if (props && props->hasInitializer()) {
+    auto property_list_t = GlobalOpToUser(props);
+    auto property_list = cast<Constant>(property_list_t->getOperand(2));
+    for (auto &op : property_list->operands())
+      PropertyList.push_back(ObjCProperty(this, cast<Constant>(&op)));
+  }
+  return PropertyList;
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeInstanceMethodList(ObjCCategory Cat) const {
+  ConstantStruct *objc_cat_t = nullptr;
+  if (auto objc_category =
+          dyn_cast<GlobalVariable>(Cat.getRawContent().getLLVMConstant())) {
+    objc_cat_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_category, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc category",
+                                   object_error::parse_failed);
+
+  ObjCMethodList MethodList;
+  int64_t cat_offset = Cat.getRawContent().getOffset();
+  unsigned offset = is64Bit() ? offsetof(category64_t, instanceMethods)
+                              : offsetof(category32_t, instanceMethods);
+  auto method_list_global = dyn_cast<User>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_cat_t, cat_offset + offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (method_list_global->getNumOperands() != 0) {
+    auto methList =
+        dyn_cast<User>(GlobalOpToUser(method_list_global)->getOperand(2));
+    for (auto &op : methList->operands())
+      MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+  }
+  return MethodList;
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeClassMethodList(ObjCCategory Cat) const {
+  ConstantStruct *objc_cat_t = nullptr;
+  if (auto objc_category =
+          dyn_cast<GlobalVariable>(Cat.getRawContent().getLLVMConstant())) {
+    objc_cat_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_category, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc category",
+                                   object_error::parse_failed);
+
+  ObjCMethodList MethodList;
+  int64_t cat_offset = Cat.getRawContent().getOffset();
+  unsigned offset = is64Bit() ? offsetof(category64_t, classMethods)
+                              : offsetof(category32_t, classMethods);
+  auto method_list_global = dyn_cast<User>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_cat_t, cat_offset + offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (method_list_global->getNumOperands() != 0) {
+    auto methList =
+        dyn_cast<User>(GlobalOpToUser(method_list_global)->getOperand(2));
+    for (auto &op : methList->operands())
+      MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+  }
+  return MethodList;
+}
+
+Expected<StringRef>
+BitcodeMetadata::getObjCProtocolName(ObjCProtocol Data) const {
+  auto *objc_proto_t = cast<ConstantStruct>(GlobalOpToUser(GetUnderlyingValue(
+      Data.getRawContent().getLLVMConstant(), getDataLayout(), 2)));
+  if (!objc_proto_t)
+    return make_error<StringError>("Unexpected type for objc protocol",
+                                   object_error::parse_failed);
+
+  unsigned offset =
+      is64Bit() ? offsetof(protocol64_t, name) : offsetof(protocol32_t, name);
+  auto protoName = dyn_cast<GlobalVariable>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_proto_t, offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (!protoName)
+    return make_error<StringError>("Cannot extract protocol name",
+                                   object_error::parse_failed);
+
+  ConstantDataSequential *CD =
+      dyn_cast<ConstantDataSequential>(protoName->getInitializer());
+  if (!CD)
+    return make_error<StringError>(
+        "Protocol name must be a ConstantDataSequential",
+        object_error::parse_failed);
+  return CD->getAsString().rtrim('\0');
+}
+
+Expected<ObjCPropertyList>
+BitcodeMetadata::materializePropertyList(ObjCProtocol Data) const {
+  auto *objc_proto_t = cast<ConstantStruct>(GlobalOpToUser(GetUnderlyingValue(
+      Data.getRawContent().getLLVMConstant(), getDataLayout(), 2)));
+  if (!objc_proto_t)
+    return make_error<StringError>("Unexpected type for objc protocol",
+                                   object_error::parse_failed);
+
+  unsigned offset = is64Bit() ? offsetof(protocol64_t, instanceProperties)
+                              : offsetof(protocol32_t, instanceProperties);
+
+  ObjCPropertyList PropertyList;
+  auto props = dyn_cast<GlobalVariable>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_proto_t, offset, getDataLayout()),
+      getDataLayout(), 2));
+
+  if (props && props->hasInitializer()) {
+    auto property_list_t = GlobalOpToUser(props);
+    auto property_list = cast<Constant>(property_list_t->getOperand(2));
+    for (auto &op : property_list->operands())
+      PropertyList.push_back(ObjCProperty(this, cast<Constant>(&op)));
+  }
+  return PropertyList;
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeInstanceMethodList(ObjCProtocol Data) const {
+  auto *objc_proto_t = cast<ConstantStruct>(GlobalOpToUser(GetUnderlyingValue(
+      Data.getRawContent().getLLVMConstant(), getDataLayout(), 2)));
+  if (!objc_proto_t)
+    return make_error<StringError>("Unexpected type for objc protocol",
+                                   object_error::parse_failed);
+
+  unsigned offset = is64Bit() ? offsetof(protocol64_t, instanceMethods)
+                              : offsetof(protocol32_t, instanceMethods);
+
+  ObjCMethodList MethodList;
+  auto method_list_global = dyn_cast<User>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_proto_t, offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (method_list_global->getNumOperands() != 0) {
+    auto methList =
+        dyn_cast<User>(GlobalOpToUser(method_list_global)->getOperand(2));
+    for (auto &op : methList->operands())
+      MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+  }
+  return MethodList;
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeClassMethodList(ObjCProtocol Data) const {
+  auto *objc_proto_t = cast<ConstantStruct>(GlobalOpToUser(GetUnderlyingValue(
+      Data.getRawContent().getLLVMConstant(), getDataLayout(), 2)));
+  if (!objc_proto_t)
+    return make_error<StringError>("Unexpected type for objc protocol",
+                                   object_error::parse_failed);
+
+  unsigned offset = is64Bit() ? offsetof(protocol64_t, classMethods)
+                              : offsetof(protocol32_t, classMethods);
+
+  ObjCMethodList MethodList;
+  auto method_list_global = dyn_cast<User>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_proto_t, offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (method_list_global->getNumOperands() != 0) {
+    auto methList =
+        dyn_cast<User>(GlobalOpToUser(method_list_global)->getOperand(2));
+    for (auto &op : methList->operands())
+      MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+  }
+  return MethodList;
+}
+
+Expected<ObjCMethodList> BitcodeMetadata::materializeOptionalInstanceMethodList(
+    ObjCProtocol Data) const {
+  auto *objc_proto_t = cast<ConstantStruct>(GlobalOpToUser(GetUnderlyingValue(
+      Data.getRawContent().getLLVMConstant(), getDataLayout(), 2)));
+  if (!objc_proto_t)
+    return make_error<StringError>("Unexpected type for objc protocol",
+                                   object_error::parse_failed);
+
+  unsigned offset = is64Bit() ? offsetof(protocol64_t, optionalInstanceMethods)
+                              : offsetof(protocol32_t, optionalInstanceMethods);
+
+  ObjCMethodList MethodList;
+  auto method_list_global = dyn_cast<User>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_proto_t, offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (method_list_global->getNumOperands() != 0) {
+    auto methList =
+        dyn_cast<User>(GlobalOpToUser(method_list_global)->getOperand(2));
+    for (auto &op : methList->operands())
+      MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+  }
+  return MethodList;
+}
+
+Expected<ObjCMethodList>
+BitcodeMetadata::materializeOptionalClassMethodList(ObjCProtocol Data) const {
+  auto *objc_proto_t = cast<ConstantStruct>(GlobalOpToUser(GetUnderlyingValue(
+      Data.getRawContent().getLLVMConstant(), getDataLayout(), 2)));
+  if (!objc_proto_t)
+    return make_error<StringError>("Unexpected type for objc protocol",
+                                   object_error::parse_failed);
+
+  unsigned offset = is64Bit() ? offsetof(protocol64_t, optionalClassMethods)
+                              : offsetof(protocol32_t, optionalClassMethods);
+
+  ObjCMethodList MethodList;
+  auto method_list_global = dyn_cast<User>(GetUnderlyingObject(
+      GetValueAtStructOffset(objc_proto_t, offset, getDataLayout()),
+      getDataLayout(), 2));
+  if (method_list_global->getNumOperands() != 0) {
+    auto methList =
+        dyn_cast<User>(GlobalOpToUser(method_list_global)->getOperand(2));
+    for (auto &op : methList->operands())
+      MethodList.push_back(ObjCMethod(this, cast<Constant>(&op)));
+  }
+  return MethodList;
+}
+
+Expected<StringRef> BitcodeMetadata::getMethodName(ObjCMethod Data) const {
+  auto objcMeth = Data.getRawContent().getLLVMConstant();
+  auto NameVar = dyn_cast<GlobalVariable>(
+      GetUnderlyingObject(objcMeth->getOperand(0), getDataLayout(), 2));
+  if (!NameVar)
+    return make_error<StringError>("Could not find property name",
+                                   object_error::parse_failed);
+
+  ConstantDataSequential *CD =
+      dyn_cast<ConstantDataSequential>(NameVar->getInitializer());
+  if (!CD)
+    return make_error<StringError>("Could not parse property name",
+                                   object_error::parse_failed);
+  return CD->getAsString().rtrim('\0');
+}
+
+Expected<StringRef> BitcodeMetadata::getMethodType(ObjCMethod Data) const {
+  auto objcMeth = Data.getRawContent().getLLVMConstant();
+  auto TypeVar = dyn_cast<GlobalVariable>(
+      GetUnderlyingObject(objcMeth->getOperand(1), getDataLayout(), 2));
+  if (!TypeVar)
+    return make_error<StringError>("Could not find property name",
+                                   object_error::parse_failed);
+
+  ConstantDataSequential *CD =
+      dyn_cast<ConstantDataSequential>(TypeVar->getInitializer());
+  if (!CD)
+    return make_error<StringError>("Could not parse property name",
+                                   object_error::parse_failed);
+  return CD->getAsString().rtrim('\0');
+}
+
+Expected<ObjCSelectorList> BitcodeMetadata::referencedSelectors() const {
+  ObjCSelectorList SelectorList;
+  for (auto &GV : OwningModule->globals()) {
+    if (GV.hasSection()) {
+      StringRef Section = GV.getSection();
+      std::string SectionName;
+      // Trim all spaces in the section name.
+      for (auto c : Section) {
+        if (c != ' ')
+          SectionName.push_back(c);
+      }
+      if (SectionName ==
+          "__DATA,__objc_selrefs,literal_pointers,no_dead_strip") {
+        SelectorList.push_back(ObjCSelectorRef(this, &GV));
+      }
+    }
+  }
+  return SelectorList;
+}
+
+Expected<StringRef>
+BitcodeMetadata::getObjCSelectorName(ObjCSelectorRef Ref) const {
+  auto GV = dyn_cast<GlobalVariable>(Ref.getRawContent().getLLVMConstant());
+  auto sel_global =
+      GetUnderlyingObject(GV->getInitializer(), getDataLayout(), 2);
+  auto CD = dyn_cast<ConstantDataSequential>(GlobalOpToUser(sel_global));
+  if (!CD)
+    return make_error<StringError>("could not read selref",
+                                   object_error::parse_failed);
+  return CD->getAsString().rtrim('\0');
+}
+
+void BitcodeMetadata::getAllPotentiallyDefinedSelectors(
+    StringSet<> &Set) const {
+  auto ignoreError = [](Error &&E) {
+    handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
+      return; // ignore.
+    });
+  };
+  if (auto selectors = referencedSelectors()) {
+    for (auto &sel : *selectors) {
+      auto GV = dyn_cast<GlobalVariable>(sel.getRawContent().getLLVMConstant());
+      auto sel_global =
+          GetUnderlyingObject(GV->getInitializer(), getDataLayout(), 2);
+      if (hasUserInMethodList(sel_global, OwningModule)) {
+        if (auto name = sel.getSelector())
+          Set.insert(*name);
+        else
+          ignoreError(name.takeError());
+      }
+    }
+  } else
+    ignoreError(selectors.takeError());
+}
+
+bool BitcodeMetadata::isObjC1() const { return !isObjC2(); }
+
+bool BitcodeMetadata::isObjC2() const {
+  auto versionMD = OwningModule->getModuleFlag("Objective-C Version");
+  if (versionMD) {
+    auto objcVer =
+        cast<ConstantInt>(cast<ConstantAsMetadata>(versionMD)->getValue())
+            ->getZExtValue();
+    if (objcVer == 2) {
+      return true;
+    }
+  }
+  return false;
+}
+
+Expected<ConstantStruct *>
+BitcodeMetadata::getObjC2ClassRO(ObjCClass Data) const {
+  ConstantStruct *objc_class_t = nullptr;
+  if (auto objc_class =
+          dyn_cast<GlobalVariable>(Data.getRawContent().getLLVMConstant())) {
+    objc_class_t = cast<ConstantStruct>(
+        GlobalOpToUser(GetUnderlyingValue(objc_class, getDataLayout(), 2)));
+  } else
+    return make_error<StringError>("Unexpected type for objc class",
+                                   object_error::parse_failed);
+
+  int64_t class_offset = Data.getRawContent().getOffset();
+  // read class_ro
+  unsigned offset =
+      is64Bit() ? offsetof(class64_t, data) : offsetof(class32_t, data);
+  auto class_ro_v = GetValueAtStructOffset(objc_class_t, class_offset + offset,
+                                           getDataLayout());
+  if (auto CE = dyn_cast<ConstantExpr>(class_ro_v)) {
+    // swift generates class_ro with an offset using add constant expr
+    class_ro_v = CE->getOperand(0);
+  }
+  auto class_ro_global = dyn_cast<GlobalVariable>(
+      GetUnderlyingValue(class_ro_v, getDataLayout(), 2));
+  if (!class_ro_global)
+    return make_error<StringError>("Could not read ObjCClass RO data",
+                                   object_error::parse_failed);
+  auto class_ro = dyn_cast<ConstantStruct>(GlobalOpToUser(
+      GetUnderlyingValue(class_ro_global, getDataLayout(), 4)));
+  if (!class_ro)
+    return make_error<StringError>("Could not process ObjCClass RO data",
+                                   object_error::parse_failed);
+  return class_ro;
+}
+
+StringRef BitcodeMetadata::getSymbolNameFromRef(ObjCRef Ref) const {
+  return Ref.getLLVMConstant()->getName();
+}
+
+StringRef BitcodeMetadata::guessClassNameBasedOnSymbol(StringRef Sym) const {
+  if (Sym.startswith("OBJC_CLASS_$_"))
+    return Sym.drop_front(strlen("OBJC_CLASS_$_"));
+  else if (Sym.startswith("\01.objc_class_name_"))
+    return Sym.drop_front(strlen("\01.objc_class_name_"));
+  else
+    return Sym;
+}
diff --git a/llvm/lib/ObjCMetadata/ObjCMachOBinary.cpp b/llvm/lib/ObjCMetadata/ObjCMachOBinary.cpp
new file mode 100644
index 00000000000..a8613dd6854
--- /dev/null
+++ b/llvm/lib/ObjCMetadata/ObjCMachOBinary.cpp
@@ -0,0 +1,1356 @@
+//===- ObjCMachOBinary.cpp - Mach-O ObjC Metadata Reader --------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the classes needed to parse ObjCMetadata in MachO Object.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ObjCMetadata/ObjCMetadata.h"
+#include "llvm/ObjCMetadata/ObjCMachOBinary.h"
+#include "llvm/Object/MachO.h"
+
+#include "macho-obj.h"
+
+using namespace llvm;
+using namespace object;
+
+Expected<ObjCClassList> MachOMetadata::classes() const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCClassList ClassList;
+  SectionRef ClassSect = getSection("__OBJC2", "__class_list");
+  if (ClassSect == SectionRef())
+    ClassSect = getSection("__DATA", "__objc_classlist");
+  // Return empty if the section doesn't exists.
+  if (ClassSect == SectionRef())
+    return ClassList;
+  if (ClassSect.getSize() % OwningBinary->getBytesInAddress() != 0)
+    return make_error<StringError>(
+        "objc class section size is not a multiple of pointer size",
+        object_error::parse_failed);
+
+  for (unsigned i = 0; i < ClassSect.getSize();
+       i += OwningBinary->getBytesInAddress())
+    ClassList.push_back(ObjCClassRef(this, ClassSect.getAddress() + i));
+
+  return ClassList;
+}
+
+Expected<ObjCClass> MachOMetadata::getObjCClassFromRef(ObjCClassRef Ref) const {
+  if (OwningBinary->is64Bit()) {
+    if (auto class_ptr =
+            getResolvedValueFromAddress64(Ref.getRawContent().getValue()))
+      return ObjCClass(this, *class_ptr);
+    else
+      return class_ptr.takeError();
+  } else {
+    if (auto class_ptr =
+            getResolvedValueFromAddress32(Ref.getRawContent().getValue()))
+      return ObjCClass(this, *class_ptr);
+    else
+      return class_ptr.takeError();
+  }
+}
+
+bool MachOMetadata::isObjCClassExternal(ObjCClassRef Ref) const {
+  if (OwningBinary->is64Bit()) {
+    if (auto addr =
+            getResolvedValueFromAddress64(Ref.getRawContent().getValue())) {
+      if (*addr == 0)
+        return true;
+      else
+        return false;
+    } else {
+      // assume external if can't get class.
+      // ignore error and return true.
+      handleAllErrors(addr.takeError(),
+                      [&](const ErrorInfoBase &EI) { return; });
+      return true;
+    }
+  } else {
+    if (auto addr =
+            getResolvedValueFromAddress32(Ref.getRawContent().getValue())) {
+      if (*addr == 0)
+        return true;
+      else
+        return false;
+    } else {
+      // assume external if can't get class.
+      // ignore error and return true.
+      handleAllErrors(addr.takeError(),
+                      [&](const ErrorInfoBase &EI) { return; });
+      return true;
+    }
+  }
+}
+
+StringRef MachOMetadata::getSymbolNameFromRef(ObjCRef Ref) const {
+  uint64_t offset;
+  if (auto symName =
+          getSymbolFromAddress(Ref.getValue(), offset))
+    return *symName;
+  else {
+    // ignore error and return empty string.
+    handleAllErrors(symName.takeError(),
+                    [&](const ErrorInfoBase &EI) { return; });
+    return StringRef();
+  }
+}
+
+StringRef MachOMetadata::guessClassNameBasedOnSymbol(StringRef Sym) const {
+  if (Sym.startswith("_OBJC_CLASS_$_"))
+    return Sym.drop_front(strlen("_OBJC_CLASS_$_"));
+  else if (Sym.startswith(".objc_class_name_"))
+    return Sym.drop_front(strlen(".objc_class_name_"));
+  else
+    return Sym;
+}
+
+Expected<ObjCCategoryList> MachOMetadata::categories() const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCCategoryList CategoryList;
+  SectionRef CatSect = getSection("__OBJC2", "__category_list");
+  if (CatSect == SectionRef())
+    CatSect = getSection("__DATA", "__objc_catlist");
+  // Return empty if the section doesn't exists.
+  if (CatSect == SectionRef())
+    return CategoryList;
+  if (CatSect.getSize() % OwningBinary->getBytesInAddress() != 0)
+    return make_error<StringError>(
+        "objc category section size is not a multiple of pointer size",
+        object_error::parse_failed);
+
+  for (unsigned i = 0; i < CatSect.getSize();
+       i += OwningBinary->getBytesInAddress())
+    CategoryList.push_back(ObjCCategoryRef(this, CatSect.getAddress() + i));
+
+  return CategoryList;
+}
+
+Expected<ObjCCategory>
+MachOMetadata::getObjCCategoryFromRef(ObjCCategoryRef Ref) const {
+  if (OwningBinary->is64Bit()) {
+    if (auto cat_ptr =
+            getResolvedValueFromAddress64(Ref.getRawContent().getValue()))
+      return ObjCCategory(this, *cat_ptr);
+    else
+      return cat_ptr.takeError();
+  } else {
+    if (auto cat_ptr =
+            getResolvedValueFromAddress32(Ref.getRawContent().getValue()))
+      return ObjCCategory(this, *cat_ptr);
+    else
+      return cat_ptr.takeError();
+  }
+}
+
+Expected<ObjCProtocolList> MachOMetadata::protocols() const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCProtocolList ProtocolList;
+  SectionRef ProtoSect = getSection("__OBJC2", "__protocol_list");
+  if (ProtoSect == SectionRef())
+    ProtoSect = getSection("__DATA", "__objc_protolist");
+  // Return empty if the section doesn't exists.
+  if (ProtoSect == SectionRef())
+    return ProtocolList;
+  if (ProtoSect.getSize() % OwningBinary->getBytesInAddress() != 0)
+    return make_error<StringError>(
+        "objc protocol section size is not a multiple of pointer size",
+        object_error::parse_failed);
+
+  for (unsigned i = 0; i < ProtoSect.getSize();
+       i += OwningBinary->getBytesInAddress())
+    ProtocolList.push_back(ObjCProtocolRef(this, ProtoSect.getAddress() + i));
+
+  return ProtocolList;
+}
+
+Expected<ObjCProtocol>
+MachOMetadata::getObjCProtocolFromRef(ObjCProtocolRef Ref) const {
+  if (OwningBinary->is64Bit()) {
+    if (auto proto_ptr =
+            getResolvedValueFromAddress64(Ref.getRawContent().getValue()))
+      return ObjCProtocol(this, *proto_ptr);
+    else
+      return proto_ptr.takeError();
+  } else {
+    if (auto proto_ptr =
+            getResolvedValueFromAddress32(Ref.getRawContent().getValue()))
+      return ObjCProtocol(this, *proto_ptr);
+    else
+      return proto_ptr.takeError();
+  }
+}
+
+Expected<StringRef> MachOMetadata::getObjCClassName(ObjCClass ClassRef) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto ro = getObjC2ClassRO64(ClassRef)) {
+      if (auto name = getResolvedValueFromAddress64(
+              ro->getValue() + offsetof(class_ro64_t, name)))
+        return getStringFromAddress(*name);
+      else
+        return name.takeError();
+    } else
+      return ro.takeError();
+  } else {
+    if (auto ro = getObjC2ClassRO32(ClassRef)) {
+      if (auto name = getResolvedValueFromAddress32(
+              ro->getValue() + offsetof(class_ro32_t, name)))
+        return getStringFromAddress(*name);
+      else
+        return name.takeError();
+    } else
+      return ro.takeError();
+  }
+}
+
+Expected<StringRef> MachOMetadata::getObjCSuperClassName(ObjCClass Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    uint64_t superAddr =
+        Data.getRawContent().getValue() + offsetof(class64_t, superclass);
+    ObjCClassRef super(this, superAddr);
+    if (auto superName = super.getClassName())
+      return *superName;
+    else
+      return superName.takeError();
+  } else {
+    uint64_t superAddr =
+        Data.getRawContent().getValue() + offsetof(class32_t, superclass);
+    ObjCClassRef super(this, superAddr);
+    if (auto superName = super.getClassName())
+      return *superName;
+    else
+      return superName.takeError();
+  }
+}
+
+Expected<bool> MachOMetadata::isObjCClassSwift(ObjCClass Data) const {
+  if (isObjC1())
+    return false;
+  if (OwningBinary->is64Bit()) {
+    if (auto class_ro = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() + offsetof(class64_t, data))) {
+      return ((*class_ro & ~0x7) != 0);
+    } else
+      return class_ro.takeError();
+  } else {
+    if (auto class_ro = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() + offsetof(class32_t, data))) {
+      return ((*class_ro & ~0x3) != 0);
+    } else
+      return class_ro.takeError();
+  }
+}
+
+Expected<bool> MachOMetadata::isObjCClassMetaClass(ObjCClass Data) const {
+  if (isObjC1())
+    return false;
+  if (OwningBinary->is64Bit()) {
+    if (auto class_ro = getObjC2ClassRO64(Data)) {
+      uint32_t f;
+      if (auto flags = getValueFromAddress(class_ro->getValue() +
+                                               offsetof(class_ro64_t, flags),
+                                           sizeof(f))) {
+        memcpy(&f, flags->data(), sizeof(f));
+        if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+          sys::swapByteOrder(f);
+        return ((f & RO_META) != 0);
+      } else
+        return flags.takeError();
+    } else
+      return class_ro.takeError();
+  } else {
+    if (auto class_ro = getObjC2ClassRO32(Data)) {
+      uint32_t f;
+      if (auto flags = getValueFromAddress(class_ro->getValue() +
+                                               offsetof(class_ro32_t, flags),
+                                           sizeof(f))) {
+        memcpy(&f, flags->data(), sizeof(f));
+        if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+          sys::swapByteOrder(f);
+        return ((f & RO_META) != 0);
+      } else
+        return flags.takeError();
+    } else
+      return class_ro.takeError();
+  }
+}
+
+Expected<ObjCPropertyList>
+MachOMetadata::materializePropertyList(ObjCClass ClassRef) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCPropertyList PropertyList;
+  if (OwningBinary->is64Bit()) {
+    if (auto ro = getObjC2ClassRO64(ClassRef)) {
+      if (auto baseProperties = getResolvedValueFromAddress64(
+              ro->getValue() + offsetof(class_ro64_t, baseProperties))) {
+        if (!*baseProperties)
+          return PropertyList;
+        objc_property_list64 propList;
+        if (auto pList =
+                getValueFromAddress(*baseProperties, sizeof(propList)))
+          memcpy(&propList, pList->data(), sizeof(propList));
+        else
+          return pList.takeError();
+        if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+          swapStruct(propList);
+        for (unsigned i = 0; i < propList.count; ++ i)
+          PropertyList.push_back(ObjCProperty(
+              this, *baseProperties + sizeof(objc_property_list64) +
+                        i * sizeof(objc_property64)));
+        return PropertyList;
+      } else
+        return baseProperties.takeError();
+    } else
+      return ro.takeError();
+  } else {
+    if (auto ro = getObjC2ClassRO32(ClassRef)) {
+      if (auto baseProperties = getResolvedValueFromAddress32(
+              ro->getValue() + offsetof(class_ro32_t, baseProperties))) {
+        if (!*baseProperties)
+          return PropertyList;
+        objc_property_list32 propList;
+        if (auto pList =
+                getValueFromAddress(*baseProperties, sizeof(propList)))
+          memcpy(&propList, pList->data(), sizeof(propList));
+        else
+          return pList.takeError();
+        if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+          swapStruct(propList);
+        for (unsigned i = 0; i < propList.count; ++ i)
+          PropertyList.push_back(ObjCProperty(
+              this, *baseProperties + sizeof(objc_property_list32) +
+                        i * sizeof(objc_property32)));
+        return PropertyList;
+      } else
+        return baseProperties.takeError();
+    } else
+      return ro.takeError();
+  }
+}
+
+Expected<StringRef> MachOMetadata::getPropertyName(ObjCProperty Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto propName = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() + offsetof(objc_property64, name)))
+      return getStringFromAddress(*propName);
+    else
+      return propName.takeError();
+  } else {
+    if (auto propName = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() + offsetof(objc_property32, name)))
+      return getStringFromAddress(*propName);
+    else
+      return propName.takeError();
+  }
+}
+
+Expected<StringRef>
+MachOMetadata::getPropertyAttribute(ObjCProperty Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto propAttr = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(objc_property64, attributes)))
+      return getStringFromAddress(*propAttr);
+    else
+      return propAttr.takeError();
+  } else {
+    if (auto propAttr = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(objc_property32, attributes)))
+      return getStringFromAddress(*propAttr);
+    else
+      return propAttr.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeInstanceMethodList(ObjCClass ClassRef) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto ro = getObjC2ClassRO64(ClassRef)) {
+      if (auto baseMethods = getResolvedValueFromAddress64(
+              ro->getValue() + offsetof(class_ro64_t, baseMethods))) {
+        if (!*baseMethods)
+          return MethodList;
+        method_list64_t methodList;
+        if (auto mList =
+                getValueFromAddress(*baseMethods, sizeof(methodList)))
+          memcpy(&methodList, mList->data(), sizeof(methodList));
+        else
+          return mList.takeError();
+        if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+          swapStruct(methodList);
+        for (unsigned i = 0; i < methodList.count; ++i)
+          MethodList.push_back(ObjCMethod(this, *baseMethods +
+                                                    sizeof(method_list64_t) +
+                                                    i * sizeof(method64_t)));
+        return MethodList;
+      } else
+        return baseMethods.takeError();
+    } else
+      return ro.takeError();
+  } else {
+    if (auto ro = getObjC2ClassRO32(ClassRef)) {
+      if (auto baseMethods = getResolvedValueFromAddress32(
+              ro->getValue() + offsetof(class_ro32_t, baseMethods))) {
+        if (!*baseMethods)
+          return MethodList;
+        method_list32_t methodList;
+        if (auto mList =
+                getValueFromAddress(*baseMethods, sizeof(methodList)))
+          memcpy(&methodList, mList->data(), sizeof(methodList));
+        else
+          return mList.takeError();
+        if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+          swapStruct(methodList);
+        for (unsigned i = 0; i < methodList.count; ++i)
+          MethodList.push_back(ObjCMethod(this, *baseMethods +
+                                                    sizeof(method_list32_t) +
+                                                    i * sizeof(method32_t)));
+        return MethodList;
+      } else
+        return baseMethods.takeError();
+    } else
+      return ro.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeClassMethodList(ObjCClass ClassRef) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto meta = getObjC2MetaClass64(ClassRef)) {
+      if (meta->getRawContent().getValue() == 0)
+        return ObjCMethodList();
+      else
+        return materializeInstanceMethodList(*meta);
+    } else
+      return meta.takeError();
+  } else {
+    if (auto meta = getObjC2MetaClass32(ClassRef)) {
+      if (meta->getRawContent().getValue() == 0)
+        return ObjCMethodList();
+      else
+        return materializeInstanceMethodList(*meta);
+    } else
+      return meta.takeError();
+  }
+}
+
+Expected<StringRef> MachOMetadata::getObjCCategoryName(ObjCCategory Cat) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto name = getResolvedValueFromAddress64(
+            Cat.getRawContent().getValue() + offsetof(category64_t, name)))
+      return getStringFromAddress(*name);
+    else
+      return name.takeError();
+  } else {
+    if (auto name = getResolvedValueFromAddress32(
+            Cat.getRawContent().getValue() + offsetof(category32_t, name)))
+      return getStringFromAddress(*name);
+    else
+      return name.takeError();
+  }
+}
+
+Expected<StringRef>
+MachOMetadata::getObjCCategoryBaseClassName(ObjCCategory Cat) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    uint64_t baseClassAddr =
+        Cat.getRawContent().getValue() + offsetof(category64_t, cls);
+    ObjCClassRef cls(this, baseClassAddr);
+    if (auto clsName = cls.getClassName())
+      return *clsName;
+    else
+      return clsName.takeError();
+  } else {
+    uint64_t baseClassAddr =
+        Cat.getRawContent().getValue() + offsetof(category32_t, cls);
+    ObjCClassRef cls(this, baseClassAddr);
+    if (auto clsName = cls.getClassName())
+      return *clsName;
+    else
+      return clsName.takeError();
+  }
+}
+
+Expected<ObjCPropertyList>
+MachOMetadata::materializePropertyList(ObjCCategory Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCPropertyList PropertyList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(category64_t, instanceProperties))) {
+      if (*iprop == 0)
+        return PropertyList;
+
+      objc_property_list64 propList;
+      if (auto pList = getValueFromAddress(*iprop, sizeof(propList)))
+        memcpy(&propList, pList->data(), sizeof(propList));
+      else
+        return pList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(propList);
+      for (unsigned i = 0; i < propList.count; ++ i)
+        PropertyList.push_back(
+            ObjCProperty(this, *iprop + sizeof(objc_property_list64) +
+                                   i * sizeof(objc_property64)));
+      return PropertyList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(category32_t, instanceProperties))) {
+      if (*iprop == 0)
+        return PropertyList;
+
+      objc_property_list32 propList;
+      if (auto pList = getValueFromAddress(*iprop, sizeof(propList)))
+        memcpy(&propList, pList->data(), sizeof(propList));
+      else
+        return pList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(propList);
+      for (unsigned i = 0; i < propList.count; ++ i)
+        PropertyList.push_back(
+            ObjCProperty(this, *iprop + sizeof(objc_property_list32) +
+                                   i * sizeof(objc_property32)));
+      return PropertyList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeInstanceMethodList(ObjCCategory Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(category64_t, instanceMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list64_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list64_t) +
+                                                  i * sizeof(method64_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(category32_t, instanceMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list32_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list32_t) +
+                                                  i * sizeof(method32_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeClassMethodList(ObjCCategory Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(category64_t, classMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list64_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list64_t) +
+                                                  i * sizeof(method64_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(category32_t, classMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list32_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list32_t) +
+                                                  i * sizeof(method32_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<StringRef>
+MachOMetadata::getObjCProtocolName(ObjCProtocol Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto name = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() + offsetof(protocol64_t, name)))
+      return getStringFromAddress(*name);
+    else
+      return name.takeError();
+  } else {
+    if (auto name = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() + offsetof(protocol32_t, name)))
+      return getStringFromAddress(*name);
+    else
+      return name.takeError();
+  }
+}
+
+Expected<ObjCPropertyList>
+MachOMetadata::materializePropertyList(ObjCProtocol Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCPropertyList PropertyList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(protocol64_t, instanceProperties))) {
+      if (*iprop == 0)
+        return PropertyList;
+
+      objc_property_list64 propList;
+      if (auto pList = getValueFromAddress(*iprop, sizeof(propList)))
+        memcpy(&propList, pList->data(), sizeof(propList));
+      else
+        return pList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(propList);
+      for (unsigned i = 0; i < propList.count; ++ i)
+        PropertyList.push_back(
+            ObjCProperty(this, *iprop + sizeof(objc_property_list64) +
+                                   i * sizeof(objc_property64)));
+      return PropertyList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(protocol32_t, instanceProperties))) {
+      if (*iprop == 0)
+        return PropertyList;
+
+      objc_property_list32 propList;
+      if (auto pList = getValueFromAddress(*iprop, sizeof(propList)))
+        memcpy(&propList, pList->data(), sizeof(propList));
+      else
+        return pList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(propList);
+      for (unsigned i = 0; i < propList.count; ++ i)
+        PropertyList.push_back(
+            ObjCProperty(this, *iprop + sizeof(objc_property_list32) +
+                                   i * sizeof(objc_property32)));
+      return PropertyList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeInstanceMethodList(ObjCProtocol Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(protocol64_t, instanceMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list64_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list64_t) +
+                                                  i * sizeof(method64_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(protocol32_t, instanceMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list32_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list32_t) +
+                                                  i * sizeof(method32_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeClassMethodList(ObjCProtocol Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(protocol64_t, classMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list64_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list64_t) +
+                                                  i * sizeof(method64_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(protocol32_t, classMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list32_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list32_t) +
+                                                  i * sizeof(method32_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeOptionalInstanceMethodList(ObjCProtocol Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(protocol64_t, optionalInstanceMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list64_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list64_t) +
+                                                  i * sizeof(method64_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(protocol32_t, optionalInstanceMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list32_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list32_t) +
+                                                  i * sizeof(method32_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<ObjCMethodList>
+MachOMetadata::materializeOptionalClassMethodList(ObjCProtocol Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCMethodList MethodList;
+  if (OwningBinary->is64Bit()) {
+    if (auto iprop = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() +
+            offsetof(protocol64_t, optionalClassMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list64_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list64_t) +
+                                                  i * sizeof(method64_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  } else {
+    if (auto iprop = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() +
+            offsetof(protocol32_t, optionalClassMethods))) {
+      if (*iprop == 0)
+        return MethodList;
+
+      method_list32_t methodList;
+      if (auto mList = getValueFromAddress(*iprop, sizeof(methodList)))
+        memcpy(&methodList, mList->data(), sizeof(methodList));
+      else
+        return mList.takeError();
+      if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+        swapStruct(methodList);
+      for (unsigned i = 0; i < methodList.count; ++ i)
+        MethodList.push_back(ObjCMethod(this, *iprop + sizeof(method_list32_t) +
+                                                  i * sizeof(method32_t)));
+      return MethodList;
+    } else
+      return iprop.takeError();
+  }
+}
+
+Expected<StringRef> MachOMetadata::getMethodName(ObjCMethod Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto methodName = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() + offsetof(method64_t, name)))
+      return getStringFromAddress(*methodName);
+    else
+      return methodName.takeError();
+  } else {
+    if (auto methodName = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() + offsetof(method32_t, name)))
+      return getStringFromAddress(*methodName);
+    else
+      return methodName.takeError();
+  }
+}
+
+Expected<StringRef> MachOMetadata::getMethodType(ObjCMethod Data) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto methodTypes = getResolvedValueFromAddress64(
+            Data.getRawContent().getValue() + offsetof(method64_t, types)))
+      return getStringFromAddress(*methodTypes);
+    else
+      return methodTypes.takeError();
+  } else {
+    if (auto methodTypes = getResolvedValueFromAddress32(
+            Data.getRawContent().getValue() + offsetof(method32_t, types)))
+      return getStringFromAddress(*methodTypes);
+    else
+      return methodTypes.takeError();
+  }
+}
+
+Expected<ObjCSelectorList> MachOMetadata::referencedSelectors() const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  ObjCSelectorList SelectorList;
+  SectionRef SelSect = getSection("__DATA", "__objc_selrefs");
+  // Return empty if the section doesn't exists.
+  if (SelSect == SectionRef())
+    return SelectorList;
+
+  if (SelSect.getSize() % OwningBinary->getBytesInAddress() != 0)
+    return make_error<StringError>(
+        "objc class section size is not a multiple of pointer size",
+        object_error::parse_failed);
+
+  for (unsigned i = 0; i < SelSect.getSize();
+       i += OwningBinary->getBytesInAddress())
+    SelectorList.push_back(ObjCSelectorRef(this, SelSect.getAddress() + i));
+
+  return SelectorList;
+}
+
+Expected<StringRef>
+MachOMetadata::getObjCSelectorName(ObjCSelectorRef Ref) const {
+  if (isObjC1())
+    return make_error<StringError>("Unsupported ObjC Runtime",
+                                   object_error::parse_failed);
+  if (OwningBinary->is64Bit()) {
+    if (auto sel =
+            getResolvedValueFromAddress64(Ref.getRawContent().getValue()))
+      return getStringFromAddress(*sel);
+    else
+      return sel.takeError();
+  } else {
+    if (auto sel =
+            getResolvedValueFromAddress32(Ref.getRawContent().getValue()))
+      return getStringFromAddress(*sel);
+    else
+      return sel.takeError();
+  }
+}
+
+void MachOMetadata::getAllPotentiallyDefinedSelectors(StringSet<> &Set) const {
+  // Clear the set.
+  Set.clear();
+  SectionRef ObjCConstSect = getSection("__DATA", "__objc_const");
+  SectionRef MethodNameSect = getSection("__TEXT", "__objc_methname");
+  if (ObjCConstSect == SectionRef() || MethodNameSect == SectionRef())
+    return;
+
+  auto ignoreError = [](Error &&E) {
+    handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
+      return; // ignore.
+    });
+  };
+
+  if (auto sels = referencedSelectors()) {
+    StringSet<> refSels;
+    for (auto sel : *sels) {
+      if (auto selName = sel.getSelector())
+        refSels.insert(*selName);
+      else
+        ignoreError(selName.takeError());
+    }
+    if (OwningBinary->is64Bit()) {
+      for (uint64_t A = ObjCConstSect.getAddress(),
+                    E = ObjCConstSect.getAddress() + ObjCConstSect.getSize();
+           A < E; A += OwningBinary->getBytesInAddress()) {
+        auto methodName = getResolvedValueFromAddress64(A);
+        if (!methodName) {
+          ignoreError(methodName.takeError());
+          continue;
+        }
+        if (*methodName >= MethodNameSect.getAddress() &&
+            *methodName <
+                MethodNameSect.getAddress() + MethodNameSect.getSize()) {
+          if (auto name = getStringFromAddress(*methodName)) {
+            if (refSels.find(*name) != refSels.end())
+              Set.insert(*name);
+          } else
+            ignoreError(name.takeError());
+        }
+      }
+    } else {
+      for (uint64_t A = ObjCConstSect.getAddress(),
+                    E = ObjCConstSect.getAddress() + ObjCConstSect.getSize();
+           A < E; A += OwningBinary->getBytesInAddress()) {
+        auto methodName = getResolvedValueFromAddress32(A);
+        if (!methodName) {
+          ignoreError(methodName.takeError());
+          continue;
+        }
+        if (*methodName >= MethodNameSect.getAddress() &&
+            *methodName <
+                MethodNameSect.getAddress() + MethodNameSect.getSize()) {
+          if (auto name = getStringFromAddress(*methodName)) {
+            if (refSels.find(*name) != refSels.end())
+              Set.insert(*name);
+          } else
+            ignoreError(name.takeError());
+        }
+      }
+    }
+  } else
+    ignoreError(sels.takeError());
+}
+
+bool MachOMetadata::isObjC1() const { return !isObjC2(); }
+
+bool MachOMetadata::isObjC2() const {
+  if (OwningBinary->is64Bit() ||
+      OwningBinary->getHeader().cputype == MachO::CPU_TYPE_ARM)
+    return true;
+
+  return !(getSection("__OBJC", "__module_info") == SectionRef());
+}
+
+const SectionRef MachOMetadata::getSection(const char *segname,
+                                           const char *sectname) const {
+  for (const SectionRef &Section : OwningBinary->sections()) {
+    StringRef SectName;
+    Section.getName(SectName);
+    DataRefImpl Ref = Section.getRawDataRefImpl();
+    StringRef SegName = OwningBinary->getSectionFinalSegmentName(Ref);
+    if (SegName == segname && SectName == sectname)
+      return Section;
+  }
+  return SectionRef();
+}
+
+Expected<StringRef> MachOMetadata::getValueFromAddress(uint64_t Address,
+                                                       uint64_t size,
+                                                       bool objc_only) const {
+  if (isAddressEncrypted(Address))
+    return make_error<StringError>("Value at the address is encrypted",
+                                   object_error::parse_failed);
+  for (const SectionRef &Section : OwningBinary->sections()) {
+    uint64_t SectAddress = Section.getAddress();
+    uint64_t SectSize = Section.getSize();
+    if (SectSize == 0)
+      continue;
+    if (objc_only) {
+      StringRef SectName;
+      Section.getName(SectName);
+      DataRefImpl Ref = Section.getRawDataRefImpl();
+      StringRef SegName = OwningBinary->getSectionFinalSegmentName(Ref);
+      if (SegName != "__OBJC" && SectName != "__cstring")
+        continue;
+    }
+    if (Address >= SectAddress && Address < SectAddress + SectSize) {
+      uint64_t offset = Address - SectAddress;
+      StringRef SectContents;
+      Section.getContents(SectContents);
+      // size == 0 implies the length of the string.
+      StringRef Target = (size == 0)
+                             ? StringRef(SectContents.data() + offset)
+                             : StringRef(SectContents.data() + offset, size);
+      if (Target.size() + offset > SectSize)
+        return make_error<StringError>(
+            "Data extends pass the end of the section",
+            object_error::parse_failed);
+      return Target;
+    }
+  }
+  return make_error<StringError>("Pointer out of bound",
+                                 object_error::parse_failed);
+}
+
+bool MachOMetadata::isAddressEncrypted(uint64_t Address) const {
+  // Find encrypted range.
+  if (OwningBinary->is64Bit()) {
+    uint64_t fileOffset = 0;
+    for (const auto &LC : OwningBinary->load_commands()) {
+      if (LC.C.cmd == MachO::LC_SEGMENT_64) {
+        MachO::segment_command_64 cmd =
+            OwningBinary->getSegment64LoadCommand(LC);
+        if (Address > cmd.vmaddr && Address < cmd.vmaddr + cmd.vmsize)
+          fileOffset = Address - cmd.vmaddr + cmd.fileoff;
+      }
+    }
+    for (const auto &LC : OwningBinary->load_commands()) {
+      if (LC.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
+        MachO::encryption_info_command_64 cmd =
+            OwningBinary->getEncryptionInfoCommand64(LC);
+        if (cmd.cryptid == 0)
+          continue;
+        if (fileOffset > cmd.cryptoff &&
+            fileOffset < cmd.cryptoff + cmd.cryptsize)
+          return true;
+      }
+    }
+  } else {
+    uint64_t fileOffset = 0;
+    for (const auto &LC : OwningBinary->load_commands()) {
+      if (LC.C.cmd == MachO::LC_SEGMENT) {
+        MachO::segment_command cmd = OwningBinary->getSegmentLoadCommand(LC);
+        if (Address > cmd.vmaddr && Address < cmd.vmaddr + cmd.vmsize)
+          fileOffset = Address - cmd.vmaddr + cmd.fileoff;
+      }
+    }
+    for (const auto &LC : OwningBinary->load_commands()) {
+      if (LC.C.cmd == MachO::LC_ENCRYPTION_INFO) {
+        MachO::encryption_info_command cmd =
+            OwningBinary->getEncryptionInfoCommand(LC);
+        if (cmd.cryptid == 0)
+          continue;
+        if (fileOffset > cmd.cryptoff &&
+            fileOffset < cmd.cryptoff + cmd.cryptsize)
+          return true;
+      }
+    }
+  }
+  return false;
+}
+
+Expected<StringRef> MachOMetadata::getStringFromAddress(uint64_t Address,
+                                                        bool allowEmpty) const {
+  if (isAddressEncrypted(Address))
+    return "#EncryptedString#";
+
+  for (const SectionRef &Section : OwningBinary->sections()) {
+    uint64_t SectAddress = Section.getAddress();
+    uint64_t SectSize = Section.getSize();
+    if (SectSize == 0)
+      continue;
+    if (Address >= SectAddress && Address < SectAddress + SectSize) {
+      uint64_t offset = Address - SectAddress;
+      StringRef SectContents;
+      Section.getContents(SectContents);
+      StringRef Target = StringRef(SectContents.data() + offset);
+      if (Target.size() + offset >= SectSize)
+        return make_error<StringError>(
+            "Data extends pass the end of the section",
+            object_error::parse_failed);
+      if (Target.empty() && !allowEmpty)
+        return make_error<StringError>(
+            "Expect to read a none zero length string",
+            object_error::parse_failed);
+
+      return Target;
+    }
+  }
+  return make_error<StringError>("Pointer out of bound",
+                                 object_error::parse_failed);
+}
+
+Expected<StringRef>
+MachOMetadata::getSymbolFromAddress(uint64_t Address, uint64_t &offset) const {
+  // Reset offset.
+  offset = 0;
+
+  // Found the section.
+  SectionRef S;
+  uint64_t SectOffset = 0;
+  for (const SectionRef &Section : OwningBinary->sections()) {
+    uint64_t SectAddress = Section.getAddress();
+    uint64_t SectSize = Section.getSize();
+    if (SectSize == 0)
+      continue;
+    if (Address >= SectAddress && Address < SectAddress + SectSize) {
+      SectOffset = Address - SectAddress;
+      S = Section;
+      break;
+    }
+  }
+  if (S == SectionRef())
+    return make_error<StringError>("Address not in range of the macho file",
+                                   object_error::parse_failed);
+
+  // See if there is an external relocation entry at the sect_offset.
+  bool reloc_found = false;
+  DataRefImpl Rel;
+  MachO::any_relocation_info RE;
+  bool isExtern = false;
+  SymbolRef Symbol;
+  for (const RelocationRef &Reloc : S.relocations()) {
+    uint64_t RelocOffset = Reloc.getOffset();
+    if (RelocOffset == SectOffset) {
+      Rel = Reloc.getRawDataRefImpl();
+      RE = OwningBinary->getRelocation(Rel);
+      if (OwningBinary->isRelocationScattered(RE))
+        continue;
+      isExtern = OwningBinary->getPlainRelocationExternal(RE);
+      if (isExtern) {
+        symbol_iterator RelocSym = Reloc.getSymbol();
+        Symbol = *RelocSym;
+      }
+      reloc_found = true;
+      break;
+    }
+  }
+  // If there is an external relocation entry for a symbol in this section
+  // at this section_offset then use that symbol's value for the n_value
+  // and return its name.
+  const char *SymbolName = nullptr;
+  if (reloc_found && isExtern) {
+    offset = Symbol.getValue();
+    Expected<StringRef> NameOrError = Symbol.getName();
+    if (!NameOrError) {
+      return NameOrError.takeError();
+    }
+    StringRef Name = *NameOrError;
+    if (!Name.empty()) {
+      SymbolName = Name.data();
+      return SymbolName;
+    }
+  }
+  return StringRef();
+}
+
+Expected<uint64_t>
+MachOMetadata::getResolvedValueFromAddress64(uint64_t Address) const {
+  uint64_t ptr;
+  if (auto p = getValueFromAddress(Address, sizeof(ptr)))
+    memcpy(&ptr, p->data(), sizeof(ptr));
+  else
+    return p.takeError();
+  if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+    sys::swapByteOrder(ptr);
+  uint64_t offset;
+  if (auto symbol = getSymbolFromAddress(Address, offset))
+    ptr += offset;
+  else
+    return symbol.takeError();
+  return ptr;
+}
+
+Expected<uint32_t>
+MachOMetadata::getResolvedValueFromAddress32(uint64_t Address) const {
+  uint32_t ptr;
+  if (auto p = getValueFromAddress(Address, sizeof(ptr)))
+    memcpy(&ptr, p->data(), sizeof(ptr));
+  else
+    return p.takeError();
+  if (OwningBinary->isLittleEndian() != sys::IsLittleEndianHost)
+    sys::swapByteOrder(ptr);
+  uint64_t offset;
+  if (auto symbol = getSymbolFromAddress(Address, offset))
+    ptr += offset;
+  else
+    return symbol.takeError();
+  return ptr;
+}
+
+Expected<ObjCRef> MachOMetadata::getObjC2ClassRO64(ObjCClass Data) const {
+  assert(isObjC2() && OwningBinary->is64Bit() &&
+         "Only support 64 bit Obj2 runtime");
+  if (auto class_ro = getResolvedValueFromAddress64(
+          Data.getRawContent().getValue() + offsetof(class64_t, data))) {
+    return *class_ro & ~0x7;
+  } else
+    return class_ro.takeError();
+}
+
+Expected<ObjCRef> MachOMetadata::getObjC2ClassRO32(ObjCClass Data) const {
+  assert(isObjC2() && !OwningBinary->is64Bit() &&
+         "Only support 32 bit Obj2 runtime");
+  if (auto class_ro = getResolvedValueFromAddress32(
+          Data.getRawContent().getValue() + offsetof(class32_t, data))) {
+    return *class_ro & ~0x3;
+  } else
+    return class_ro.takeError();
+}
+
+Expected<ObjCClass> MachOMetadata::getObjC2MetaClass64(ObjCClass Data) const {
+  assert(isObjC2() && OwningBinary->is64Bit() &&
+         "Only support 64 bit Obj2 runtime");
+  if (auto isa = getResolvedValueFromAddress64(Data.getRawContent().getValue() +
+                                               offsetof(class64_t, isa))) {
+    if (*isa) {
+      return ObjCClass(this, *isa);
+    } else
+      return ObjCClass(this);
+  } else
+    return isa.takeError();
+}
+
+Expected<ObjCClass> MachOMetadata::getObjC2MetaClass32(ObjCClass Data) const {
+  assert(isObjC2() && !OwningBinary->is64Bit() &&
+         "Only support 32 bit Obj2 runtime");
+  if (auto isa = getResolvedValueFromAddress32(Data.getRawContent().getValue() +
+                                               offsetof(class32_t, isa))) {
+    if (*isa) {
+      return ObjCClass(this, *isa);
+    } else
+      return ObjCClass(this);
+  } else
+    return isa.takeError();
+}
diff --git a/llvm/lib/ObjCMetadata/ObjCMetadata.cpp b/llvm/lib/ObjCMetadata/ObjCMetadata.cpp
new file mode 100644
index 00000000000..a692e1273cf
--- /dev/null
+++ b/llvm/lib/ObjCMetadata/ObjCMetadata.cpp
@@ -0,0 +1,177 @@
+//===- ObjCMetadata.cpp - ObjC Metadata Reader ------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the classes needed to parse ObjCMetadata.
+//
+//===----------------------------------------------------------------------===//
+#include "llvm/ObjCMetadata/ObjCMetadata.h"
+
+using namespace llvm;
+
+Expected<ObjCClass> ObjCClassRef::getObjCClass() const {
+  return MetadataReader->getObjCClassFromRef(*this);
+}
+
+Expected<ObjCCategory> ObjCCategoryRef::getObjCCategory() const {
+  return MetadataReader->getObjCCategoryFromRef(*this);
+}
+
+Expected<ObjCProtocol> ObjCProtocolRef::getObjCProtocol() const {
+  return MetadataReader->getObjCProtocolFromRef(*this);
+}
+
+Expected<StringRef> ObjCClass::getName() const {
+  return MetadataReader->getObjCClassName(*this);
+}
+
+Expected<StringRef> ObjCClassRef::getClassName() const {
+  if (MetadataReader->isObjCClassExternal(*this)) {
+    StringRef symName = MetadataReader->getSymbolNameFromRef(Data);
+    return MetadataReader->guessClassNameBasedOnSymbol(symName);
+  } else if (auto class_t = getObjCClass())
+    return class_t->getName();
+  else
+    return class_t.takeError();
+}
+
+bool ObjCClassRef::isExternal() const {
+  return MetadataReader->isObjCClassExternal(*this);
+}
+
+Expected<StringRef> ObjCClass::getSuperClassName() const {
+  return MetadataReader->getObjCSuperClassName(*this);
+}
+
+Expected<bool> ObjCClass::isSwift() const {
+  return MetadataReader->isObjCClassSwift(*this);
+}
+
+Expected<bool> ObjCClass::isMetaClass() const {
+  return MetadataReader->isObjCClassMetaClass(*this);
+}
+
+Expected<ObjCPropertyList> ObjCClass::properties() const {
+  return MetadataReader->materializePropertyList(*this);
+}
+
+Expected<ObjCMethodList> ObjCClass::instanceMethods() const {
+  return MetadataReader->materializeInstanceMethodList(*this);
+}
+
+Expected<ObjCMethodList> ObjCClass::classMethods() const {
+  return MetadataReader->materializeClassMethodList(*this);
+}
+
+Expected<StringRef> ObjCCategory::getName() const {
+  return MetadataReader->getObjCCategoryName(*this);
+}
+
+Expected<StringRef> ObjCCategory::getBaseClassName() const {
+  return MetadataReader->getObjCCategoryBaseClassName(*this);
+}
+
+Expected<ObjCPropertyList> ObjCCategory::properties() const {
+  return MetadataReader->materializePropertyList(*this);
+}
+
+Expected<ObjCMethodList> ObjCCategory::instanceMethods() const {
+  return MetadataReader->materializeInstanceMethodList(*this);
+}
+
+Expected<ObjCMethodList> ObjCCategory::classMethods() const {
+  return MetadataReader->materializeClassMethodList(*this);
+}
+
+Expected<StringRef> ObjCProtocol::getName() const {
+  return MetadataReader->getObjCProtocolName(*this);
+}
+
+Expected<ObjCPropertyList> ObjCProtocol::properties() const {
+  return MetadataReader->materializePropertyList(*this);
+}
+
+Expected<ObjCMethodList> ObjCProtocol::instanceMethods() const {
+  return MetadataReader->materializeInstanceMethodList(*this);
+}
+
+Expected<ObjCMethodList> ObjCProtocol::classMethods() const {
+  return MetadataReader->materializeClassMethodList(*this);
+}
+
+Expected<ObjCMethodList> ObjCProtocol::optionalInstanceMethods() const {
+  return MetadataReader->materializeOptionalInstanceMethodList(*this);
+}
+
+Expected<ObjCMethodList> ObjCProtocol::optionalClassMethods() const {
+  return MetadataReader->materializeOptionalClassMethodList(*this);
+}
+
+Expected<StringRef> ObjCProperty::getName() const {
+  return MetadataReader->getPropertyName(*this);
+}
+
+Expected<StringRef> ObjCProperty::getAttribute() const {
+  return MetadataReader->getPropertyAttribute(*this);
+}
+
+Expected<std::string> ObjCProperty::getGetter() const {
+  auto Name = getName();
+  if (!Name)
+    return Name.takeError();
+  if (*Name == "#EncryptedString#")
+    return *Name;
+  auto Attr = getAttribute();
+  if (!Attr)
+    return Attr.takeError();
+  // Find getter attribute.
+  SmallVector<StringRef, 4> Attrs;
+  Attr->split(Attrs, ',');
+  for (auto a : Attrs) {
+    if (a.startswith("G"))
+      return a.drop_front(1).str();
+  }
+  // Otherwise returns property name.
+  return Name->str();
+}
+
+Expected<std::string> ObjCProperty::getSetter() const {
+  auto Name = getName();
+  if (!Name)
+    return Name.takeError();
+  if (*Name == "#EncryptedString#")
+    return *Name;
+  auto Attr = getAttribute();
+  if (!Attr)
+    return Attr.takeError();
+  // Find setter attribute.
+  SmallVector<StringRef, 4> Attrs;
+  Attr->split(Attrs, ',');
+  for (auto a : Attrs) {
+    if (a.startswith("S"))
+      return a.drop_front(1).str();
+    else if (a.startswith("R"))
+      return std::string(); // Read-only property
+  }
+  // Otherwise returns property name.
+  std::string setter =
+      "set" + Name->substr(0, 1).upper() + Name->substr(1).str() + ":";
+  return setter;
+}
+
+Expected<StringRef> ObjCMethod::getName() const {
+  return MetadataReader->getMethodName(*this);
+}
+
+Expected<StringRef> ObjCMethod::getType() const {
+  return MetadataReader->getMethodType(*this);
+}
+
+Expected<StringRef> ObjCSelectorRef::getSelector() const {
+  return MetadataReader->getObjCSelectorName(*this);
+}
diff --git a/llvm/lib/ObjCMetadata/macho-obj.h b/llvm/lib/ObjCMetadata/macho-obj.h
new file mode 100644
index 00000000000..93a32a55235
--- /dev/null
+++ b/llvm/lib/ObjCMetadata/macho-obj.h
@@ -0,0 +1,588 @@
+#ifndef LLVM_LIB_OBJCMETADATA_MACHO_OBJ_H
+#define LLVM_LIB_OBJCMETADATA_MACHO_OBJ_H
+
+#include <llvm/Support/SwapByteOrder.h>
+
+// These are structs in the Objective-C meta data and read to produce the
+// comments for disassembly.  While these are part of the ABI they are no
+// public defintions.  So the are here not in include/llvm/Support/MachO.h .
+
+// The cfstring object in a 64-bit Mach-O file.
+struct cfstring64_t {
+  uint64_t isa;        // class64_t * (64-bit pointer)
+  uint64_t flags;      // flag bits
+  uint64_t characters; // char * (64-bit pointer)
+  uint64_t length;     // number of non-NULL characters in above
+};
+
+// The class object in a 64-bit Mach-O file.
+struct class64_t {
+  uint64_t isa;        // class64_t * (64-bit pointer)
+  uint64_t superclass; // class64_t * (64-bit pointer)
+  uint64_t cache;      // Cache (64-bit pointer)
+  uint64_t vtable;     // IMP * (64-bit pointer)
+  uint64_t data;       // class_ro64_t * (64-bit pointer)
+};
+
+struct class32_t {
+  uint32_t isa;        /* class32_t * (32-bit pointer) */
+  uint32_t superclass; /* class32_t * (32-bit pointer) */
+  uint32_t cache;      /* Cache (32-bit pointer) */
+  uint32_t vtable;     /* IMP * (32-bit pointer) */
+  uint32_t data;       /* class_ro32_t * (32-bit pointer) */
+};
+
+struct class_ro64_t {
+  uint32_t flags;
+  uint32_t instanceStart;
+  uint32_t instanceSize;
+  uint32_t reserved;
+  uint64_t ivarLayout;     // const uint8_t * (64-bit pointer)
+  uint64_t name;           // const char * (64-bit pointer)
+  uint64_t baseMethods;    // const method_list_t * (64-bit pointer)
+  uint64_t baseProtocols;  // const protocol_list_t * (64-bit pointer)
+  uint64_t ivars;          // const ivar_list_t * (64-bit pointer)
+  uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
+  uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
+};
+
+struct class_ro32_t {
+  uint32_t flags;
+  uint32_t instanceStart;
+  uint32_t instanceSize;
+  uint32_t ivarLayout;     /* const uint8_t * (32-bit pointer) */
+  uint32_t name;           /* const char * (32-bit pointer) */
+  uint32_t baseMethods;    /* const method_list_t * (32-bit pointer) */
+  uint32_t baseProtocols;  /* const protocol_list_t * (32-bit pointer) */
+  uint32_t ivars;          /* const ivar_list_t * (32-bit pointer) */
+  uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
+  uint32_t baseProperties; /* const struct objc_property_list *
+                                                   (32-bit pointer) */
+};
+
+/* Values for class_ro{64,32}_t->flags */
+#define RO_META (1 << 0)
+#define RO_ROOT (1 << 1)
+#define RO_HAS_CXX_STRUCTORS (1 << 2)
+
+struct method_list64_t {
+  uint32_t entsize;
+  uint32_t count;
+  /* struct method64_t first;  These structures follow inline */
+};
+
+struct method_list32_t {
+  uint32_t entsize;
+  uint32_t count;
+  /* struct method32_t first;  These structures follow inline */
+};
+
+struct method64_t {
+  uint64_t name;  /* SEL (64-bit pointer) */
+  uint64_t types; /* const char * (64-bit pointer) */
+  uint64_t imp;   /* IMP (64-bit pointer) */
+};
+
+struct method32_t {
+  uint32_t name;  /* SEL (32-bit pointer) */
+  uint32_t types; /* const char * (32-bit pointer) */
+  uint32_t imp;   /* IMP (32-bit pointer) */
+};
+
+struct protocol_list64_t {
+  uint64_t count; /* uintptr_t (a 64-bit value) */
+  /* struct protocol64_t * list[0];  These pointers follow inline */
+};
+
+struct protocol_list32_t {
+  uint32_t count; /* uintptr_t (a 32-bit value) */
+  /* struct protocol32_t * list[0];  These pointers follow inline */
+};
+
+struct protocol64_t {
+  uint64_t isa;                     /* id * (64-bit pointer) */
+  uint64_t name;                    /* const char * (64-bit pointer) */
+  uint64_t protocols;               /* struct protocol_list64_t *
+                                                    (64-bit pointer) */
+  uint64_t instanceMethods;         /* method_list_t * (64-bit pointer) */
+  uint64_t classMethods;            /* method_list_t * (64-bit pointer) */
+  uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
+  uint64_t optionalClassMethods;    /* method_list_t * (64-bit pointer) */
+  uint64_t instanceProperties;      /* struct objc_property_list *
+                                                       (64-bit pointer) */
+};
+
+struct protocol32_t {
+  uint32_t isa;                     /* id * (32-bit pointer) */
+  uint32_t name;                    /* const char * (32-bit pointer) */
+  uint32_t protocols;               /* struct protocol_list_t *
+                                                    (32-bit pointer) */
+  uint32_t instanceMethods;         /* method_list_t * (32-bit pointer) */
+  uint32_t classMethods;            /* method_list_t * (32-bit pointer) */
+  uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
+  uint32_t optionalClassMethods;    /* method_list_t * (32-bit pointer) */
+  uint32_t instanceProperties;      /* struct objc_property_list *
+                                                       (32-bit pointer) */
+};
+
+struct ivar_list64_t {
+  uint32_t entsize;
+  uint32_t count;
+  /* struct ivar64_t first;  These structures follow inline */
+};
+
+struct ivar_list32_t {
+  uint32_t entsize;
+  uint32_t count;
+  /* struct ivar32_t first;  These structures follow inline */
+};
+
+struct ivar64_t {
+  uint64_t offset; /* uintptr_t * (64-bit pointer) */
+  uint64_t name;   /* const char * (64-bit pointer) */
+  uint64_t type;   /* const char * (64-bit pointer) */
+  uint32_t alignment;
+  uint32_t size;
+};
+
+struct ivar32_t {
+  uint32_t offset; /* uintptr_t * (32-bit pointer) */
+  uint32_t name;   /* const char * (32-bit pointer) */
+  uint32_t type;   /* const char * (32-bit pointer) */
+  uint32_t alignment;
+  uint32_t size;
+};
+
+struct objc_property_list64 {
+  uint32_t entsize;
+  uint32_t count;
+  /* struct objc_property64 first;  These structures follow inline */
+};
+
+struct objc_property_list32 {
+  uint32_t entsize;
+  uint32_t count;
+  /* struct objc_property32 first;  These structures follow inline */
+};
+
+struct objc_property64 {
+  uint64_t name;       /* const char * (64-bit pointer) */
+  uint64_t attributes; /* const char * (64-bit pointer) */
+};
+
+struct objc_property32 {
+  uint32_t name;       /* const char * (32-bit pointer) */
+  uint32_t attributes; /* const char * (32-bit pointer) */
+};
+
+struct category64_t {
+  uint64_t name;               /* const char * (64-bit pointer) */
+  uint64_t cls;                /* struct class_t * (64-bit pointer) */
+  uint64_t instanceMethods;    /* struct method_list_t * (64-bit pointer) */
+  uint64_t classMethods;       /* struct method_list_t * (64-bit pointer) */
+  uint64_t protocols;          /* struct protocol_list_t * (64-bit pointer) */
+  uint64_t instanceProperties; /* struct objc_property_list *
+                                  (64-bit pointer) */
+};
+
+struct category32_t {
+  uint32_t name;               /* const char * (32-bit pointer) */
+  uint32_t cls;                /* struct class_t * (32-bit pointer) */
+  uint32_t instanceMethods;    /* struct method_list_t * (32-bit pointer) */
+  uint32_t classMethods;       /* struct method_list_t * (32-bit pointer) */
+  uint32_t protocols;          /* struct protocol_list_t * (32-bit pointer) */
+  uint32_t instanceProperties; /* struct objc_property_list *
+                                  (32-bit pointer) */
+};
+
+struct objc_image_info64 {
+  uint32_t version;
+  uint32_t flags;
+};
+struct objc_image_info32 {
+  uint32_t version;
+  uint32_t flags;
+};
+struct imageInfo_t {
+  uint32_t version;
+  uint32_t flags;
+};
+/* masks for objc_image_info.flags */
+#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)
+#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)
+
+struct message_ref64 {
+  uint64_t imp; /* IMP (64-bit pointer) */
+  uint64_t sel; /* SEL (64-bit pointer) */
+};
+
+struct message_ref32 {
+  uint32_t imp; /* IMP (32-bit pointer) */
+  uint32_t sel; /* SEL (32-bit pointer) */
+};
+
+// Objective-C 1 (32-bit only) meta data structs.
+
+struct objc_module_t {
+  uint32_t version;
+  uint32_t size;
+  uint32_t name;   /* char * (32-bit pointer) */
+  uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
+};
+
+struct objc_symtab_t {
+  uint32_t sel_ref_cnt;
+  uint32_t refs; /* SEL * (32-bit pointer) */
+  uint16_t cls_def_cnt;
+  uint16_t cat_def_cnt;
+  // uint32_t defs[1];        /* void * (32-bit pointer) variable size */
+};
+
+struct objc_class_t {
+  uint32_t isa;         /* struct objc_class * (32-bit pointer) */
+  uint32_t super_class; /* struct objc_class * (32-bit pointer) */
+  uint32_t name;        /* const char * (32-bit pointer) */
+  int32_t version;
+  int32_t info;
+  int32_t instance_size;
+  uint32_t ivars;       /* struct objc_ivar_list * (32-bit pointer) */
+  uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
+  uint32_t cache;       /* struct objc_cache * (32-bit pointer) */
+  uint32_t protocols;   /* struct objc_protocol_list * (32-bit pointer) */
+};
+
+#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))
+// class is not a metaclass
+#define CLS_CLASS 0x1
+// class is a metaclass
+#define CLS_META 0x2
+
+struct objc_category_t {
+  uint32_t category_name;    /* char * (32-bit pointer) */
+  uint32_t class_name;       /* char * (32-bit pointer) */
+  uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
+  uint32_t class_methods;    /* struct objc_method_list * (32-bit pointer) */
+  uint32_t protocols;        /* struct objc_protocol_list * (32-bit ptr) */
+};
+
+struct objc_ivar_t {
+  uint32_t ivar_name; /* char * (32-bit pointer) */
+  uint32_t ivar_type; /* char * (32-bit pointer) */
+  int32_t ivar_offset;
+};
+
+struct objc_ivar_list_t {
+  int32_t ivar_count;
+  // struct objc_ivar_t ivar_list[1];          /* variable length structure */
+};
+
+struct objc_method_list_t {
+  uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
+  int32_t method_count;
+  // struct objc_method_t method_list[1];      /* variable length structure */
+};
+
+struct objc_method_t {
+  uint32_t method_name;  /* SEL, aka struct objc_selector * (32-bit pointer) */
+  uint32_t method_types; /* char * (32-bit pointer) */
+  uint32_t method_imp;   /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
+                            (32-bit pointer) */
+};
+
+struct objc_protocol_list_t {
+  uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
+  int32_t count;
+  // uint32_t list[1];   /* Protocol *, aka struct objc_protocol_t *
+  //                        (32-bit pointer) */
+};
+
+struct objc_protocol_t {
+  uint32_t isa;              /* struct objc_class * (32-bit pointer) */
+  uint32_t protocol_name;    /* char * (32-bit pointer) */
+  uint32_t protocol_list;    /* struct objc_protocol_list * (32-bit pointer) */
+  uint32_t instance_methods; /* struct objc_method_description_list *
+                                (32-bit pointer) */
+  uint32_t class_methods;    /* struct objc_method_description_list *
+                                (32-bit pointer) */
+};
+
+struct objc_method_description_list_t {
+  int32_t count;
+  // struct objc_method_description_t list[1];
+};
+
+struct objc_method_description_t {
+  uint32_t name;  /* SEL, aka struct objc_selector * (32-bit pointer) */
+  uint32_t types; /* char * (32-bit pointer) */
+};
+
+inline void swapStruct(struct cfstring64_t &cfs) {
+  llvm::sys::swapByteOrder(cfs.isa);
+  llvm::sys::swapByteOrder(cfs.flags);
+  llvm::sys::swapByteOrder(cfs.characters);
+  llvm::sys::swapByteOrder(cfs.length);
+}
+
+inline void swapStruct(struct class64_t &c) {
+  llvm::sys::swapByteOrder(c.isa);
+  llvm::sys::swapByteOrder(c.superclass);
+  llvm::sys::swapByteOrder(c.cache);
+  llvm::sys::swapByteOrder(c.vtable);
+  llvm::sys::swapByteOrder(c.data);
+}
+
+inline void swapStruct(struct class32_t &c) {
+  llvm::sys::swapByteOrder(c.isa);
+  llvm::sys::swapByteOrder(c.superclass);
+  llvm::sys::swapByteOrder(c.cache);
+  llvm::sys::swapByteOrder(c.vtable);
+  llvm::sys::swapByteOrder(c.data);
+}
+
+inline void swapStruct(struct class_ro64_t &cro) {
+  llvm::sys::swapByteOrder(cro.flags);
+  llvm::sys::swapByteOrder(cro.instanceStart);
+  llvm::sys::swapByteOrder(cro.instanceSize);
+  llvm::sys::swapByteOrder(cro.reserved);
+  llvm::sys::swapByteOrder(cro.ivarLayout);
+  llvm::sys::swapByteOrder(cro.name);
+  llvm::sys::swapByteOrder(cro.baseMethods);
+  llvm::sys::swapByteOrder(cro.baseProtocols);
+  llvm::sys::swapByteOrder(cro.ivars);
+  llvm::sys::swapByteOrder(cro.weakIvarLayout);
+  llvm::sys::swapByteOrder(cro.baseProperties);
+}
+
+inline void swapStruct(struct class_ro32_t &cro) {
+  llvm::sys::swapByteOrder(cro.flags);
+  llvm::sys::swapByteOrder(cro.instanceStart);
+  llvm::sys::swapByteOrder(cro.instanceSize);
+  llvm::sys::swapByteOrder(cro.ivarLayout);
+  llvm::sys::swapByteOrder(cro.name);
+  llvm::sys::swapByteOrder(cro.baseMethods);
+  llvm::sys::swapByteOrder(cro.baseProtocols);
+  llvm::sys::swapByteOrder(cro.ivars);
+  llvm::sys::swapByteOrder(cro.weakIvarLayout);
+  llvm::sys::swapByteOrder(cro.baseProperties);
+}
+
+inline void swapStruct(struct method_list64_t &ml) {
+  llvm::sys::swapByteOrder(ml.entsize);
+  llvm::sys::swapByteOrder(ml.count);
+}
+
+inline void swapStruct(struct method_list32_t &ml) {
+  llvm::sys::swapByteOrder(ml.entsize);
+  llvm::sys::swapByteOrder(ml.count);
+}
+
+inline void swapStruct(struct method64_t &m) {
+  llvm::sys::swapByteOrder(m.name);
+  llvm::sys::swapByteOrder(m.types);
+  llvm::sys::swapByteOrder(m.imp);
+}
+
+inline void swapStruct(struct method32_t &m) {
+  llvm::sys::swapByteOrder(m.name);
+  llvm::sys::swapByteOrder(m.types);
+  llvm::sys::swapByteOrder(m.imp);
+}
+
+inline void swapStruct(struct protocol_list64_t &pl) {
+  llvm::sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct protocol_list32_t &pl) {
+  llvm::sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct protocol64_t &p) {
+  llvm::sys::swapByteOrder(p.isa);
+  llvm::sys::swapByteOrder(p.name);
+  llvm::sys::swapByteOrder(p.protocols);
+  llvm::sys::swapByteOrder(p.instanceMethods);
+  llvm::sys::swapByteOrder(p.classMethods);
+  llvm::sys::swapByteOrder(p.optionalInstanceMethods);
+  llvm::sys::swapByteOrder(p.optionalClassMethods);
+  llvm::sys::swapByteOrder(p.instanceProperties);
+}
+
+inline void swapStruct(struct protocol32_t &p) {
+  llvm::sys::swapByteOrder(p.isa);
+  llvm::sys::swapByteOrder(p.name);
+  llvm::sys::swapByteOrder(p.protocols);
+  llvm::sys::swapByteOrder(p.instanceMethods);
+  llvm::sys::swapByteOrder(p.classMethods);
+  llvm::sys::swapByteOrder(p.optionalInstanceMethods);
+  llvm::sys::swapByteOrder(p.optionalClassMethods);
+  llvm::sys::swapByteOrder(p.instanceProperties);
+}
+
+inline void swapStruct(struct ivar_list64_t &il) {
+  llvm::sys::swapByteOrder(il.entsize);
+  llvm::sys::swapByteOrder(il.count);
+}
+
+inline void swapStruct(struct ivar_list32_t &il) {
+  llvm::sys::swapByteOrder(il.entsize);
+  llvm::sys::swapByteOrder(il.count);
+}
+
+inline void swapStruct(struct ivar64_t &i) {
+  llvm::sys::swapByteOrder(i.offset);
+  llvm::sys::swapByteOrder(i.name);
+  llvm::sys::swapByteOrder(i.type);
+  llvm::sys::swapByteOrder(i.alignment);
+  llvm::sys::swapByteOrder(i.size);
+}
+
+inline void swapStruct(struct ivar32_t &i) {
+  llvm::sys::swapByteOrder(i.offset);
+  llvm::sys::swapByteOrder(i.name);
+  llvm::sys::swapByteOrder(i.type);
+  llvm::sys::swapByteOrder(i.alignment);
+  llvm::sys::swapByteOrder(i.size);
+}
+
+inline void swapStruct(struct objc_property_list64 &pl) {
+  llvm::sys::swapByteOrder(pl.entsize);
+  llvm::sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct objc_property_list32 &pl) {
+  llvm::sys::swapByteOrder(pl.entsize);
+  llvm::sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct objc_property64 &op) {
+  llvm::sys::swapByteOrder(op.name);
+  llvm::sys::swapByteOrder(op.attributes);
+}
+
+inline void swapStruct(struct objc_property32 &op) {
+  llvm::sys::swapByteOrder(op.name);
+  llvm::sys::swapByteOrder(op.attributes);
+}
+
+inline void swapStruct(struct category64_t &c) {
+  llvm::sys::swapByteOrder(c.name);
+  llvm::sys::swapByteOrder(c.cls);
+  llvm::sys::swapByteOrder(c.instanceMethods);
+  llvm::sys::swapByteOrder(c.classMethods);
+  llvm::sys::swapByteOrder(c.protocols);
+  llvm::sys::swapByteOrder(c.instanceProperties);
+}
+
+inline void swapStruct(struct category32_t &c) {
+  llvm::sys::swapByteOrder(c.name);
+  llvm::sys::swapByteOrder(c.cls);
+  llvm::sys::swapByteOrder(c.instanceMethods);
+  llvm::sys::swapByteOrder(c.classMethods);
+  llvm::sys::swapByteOrder(c.protocols);
+  llvm::sys::swapByteOrder(c.instanceProperties);
+}
+
+inline void swapStruct(struct objc_image_info64 &o) {
+  llvm::sys::swapByteOrder(o.version);
+  llvm::sys::swapByteOrder(o.flags);
+}
+
+inline void swapStruct(struct objc_image_info32 &o) {
+  llvm::sys::swapByteOrder(o.version);
+  llvm::sys::swapByteOrder(o.flags);
+}
+
+inline void swapStruct(struct imageInfo_t &o) {
+  llvm::sys::swapByteOrder(o.version);
+  llvm::sys::swapByteOrder(o.flags);
+}
+
+inline void swapStruct(struct message_ref64 &mr) {
+  llvm::sys::swapByteOrder(mr.imp);
+  llvm::sys::swapByteOrder(mr.sel);
+}
+
+inline void swapStruct(struct message_ref32 &mr) {
+  llvm::sys::swapByteOrder(mr.imp);
+  llvm::sys::swapByteOrder(mr.sel);
+}
+
+inline void swapStruct(struct objc_module_t &module) {
+  llvm::sys::swapByteOrder(module.version);
+  llvm::sys::swapByteOrder(module.size);
+  llvm::sys::swapByteOrder(module.name);
+  llvm::sys::swapByteOrder(module.symtab);
+}
+
+inline void swapStruct(struct objc_symtab_t &symtab) {
+  llvm::sys::swapByteOrder(symtab.sel_ref_cnt);
+  llvm::sys::swapByteOrder(symtab.refs);
+  llvm::sys::swapByteOrder(symtab.cls_def_cnt);
+  llvm::sys::swapByteOrder(symtab.cat_def_cnt);
+}
+
+inline void swapStruct(struct objc_class_t &objc_class) {
+  llvm::sys::swapByteOrder(objc_class.isa);
+  llvm::sys::swapByteOrder(objc_class.super_class);
+  llvm::sys::swapByteOrder(objc_class.name);
+  llvm::sys::swapByteOrder(objc_class.version);
+  llvm::sys::swapByteOrder(objc_class.info);
+  llvm::sys::swapByteOrder(objc_class.instance_size);
+  llvm::sys::swapByteOrder(objc_class.ivars);
+  llvm::sys::swapByteOrder(objc_class.methodLists);
+  llvm::sys::swapByteOrder(objc_class.cache);
+  llvm::sys::swapByteOrder(objc_class.protocols);
+}
+
+inline void swapStruct(struct objc_category_t &objc_category) {
+  llvm::sys::swapByteOrder(objc_category.category_name);
+  llvm::sys::swapByteOrder(objc_category.class_name);
+  llvm::sys::swapByteOrder(objc_category.instance_methods);
+  llvm::sys::swapByteOrder(objc_category.class_methods);
+  llvm::sys::swapByteOrder(objc_category.protocols);
+}
+
+inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
+  llvm::sys::swapByteOrder(objc_ivar_list.ivar_count);
+}
+
+inline void swapStruct(struct objc_ivar_t &objc_ivar) {
+  llvm::sys::swapByteOrder(objc_ivar.ivar_name);
+  llvm::sys::swapByteOrder(objc_ivar.ivar_type);
+  llvm::sys::swapByteOrder(objc_ivar.ivar_offset);
+}
+
+inline void swapStruct(struct objc_method_list_t &method_list) {
+  llvm::sys::swapByteOrder(method_list.obsolete);
+  llvm::sys::swapByteOrder(method_list.method_count);
+}
+
+inline void swapStruct(struct objc_method_t &method) {
+  llvm::sys::swapByteOrder(method.method_name);
+  llvm::sys::swapByteOrder(method.method_types);
+  llvm::sys::swapByteOrder(method.method_imp);
+}
+
+inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
+  llvm::sys::swapByteOrder(protocol_list.next);
+  llvm::sys::swapByteOrder(protocol_list.count);
+}
+
+inline void swapStruct(struct objc_protocol_t &protocol) {
+  llvm::sys::swapByteOrder(protocol.isa);
+  llvm::sys::swapByteOrder(protocol.protocol_name);
+  llvm::sys::swapByteOrder(protocol.protocol_list);
+  llvm::sys::swapByteOrder(protocol.instance_methods);
+  llvm::sys::swapByteOrder(protocol.class_methods);
+}
+
+inline void swapStruct(struct objc_method_description_list_t &mdl) {
+  llvm::sys::swapByteOrder(mdl.count);
+}
+
+inline void swapStruct(struct objc_method_description_t &md) {
+  llvm::sys::swapByteOrder(md.name);
+  llvm::sys::swapByteOrder(md.types);
+}
+
+#endif
