From 95d8155b37cb7f005f9c6228e5d51022abc884f8 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Wed, 1 Apr 2015 20:57:01 +0000 Subject: [PATCH] Add the option -objc-meta-data to llvm-objdump used with -macho to print the Objective-C runtime meta data for Mach-O files. There are three types of Objective-C runtime meta data, Objc2 64-bit, Objc2 32-bit and Objc1 32-bit. This prints the first of these types. The changes to print the others will follow next. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233840 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../X86/Inputs/Objc2.64bit.exe.macho-x86_64 | Bin 0 -> 22688 bytes .../X86/Inputs/Objc2.64bit.obj.macho-x86_64 | Bin 0 -> 13580 bytes .../X86/macho-objc-meta-data.test | 206 +++ tools/llvm-objdump/MachODump.cpp | 1239 ++++++++++++++++- tools/llvm-objdump/llvm-objdump.cpp | 1 + tools/llvm-objdump/llvm-objdump.h | 2 +- 6 files changed, 1436 insertions(+), 12 deletions(-) create mode 100755 test/tools/llvm-objdump/X86/Inputs/Objc2.64bit.exe.macho-x86_64 create mode 100644 test/tools/llvm-objdump/X86/Inputs/Objc2.64bit.obj.macho-x86_64 create mode 100644 test/tools/llvm-objdump/X86/macho-objc-meta-data.test diff --git a/test/tools/llvm-objdump/X86/Inputs/Objc2.64bit.exe.macho-x86_64 b/test/tools/llvm-objdump/X86/Inputs/Objc2.64bit.exe.macho-x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..5cee0773604a49c1d68ed68f08c526e02783fae9 GIT binary patch literal 22688 zcmeHO3v3+486HDJoDjf}6jGj7htPxu+i@He9gp1k?DS|}j_;iCN;d1ev2VkA_qx01 z#6Zf?ls2v#WVNEARRy8Xv_&oAA*fW^sHCKkD78>kr4(qW0&>)c%tH`TLi+!^|D1Q{ zZk<%B`anC;diMY3|G)X?pU3XaY<_#}Zy!u&tnPHi%BL~LJ_^?(GZ?#v#o&&ykHM9O zOHsO#pX$81vwJO~!BiI%Yf8v77b;PdZ0C*Hpo(iB3u06~1K-#*xWFYhDT>3lIV3

LfOBwFY?+O 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 literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/Inputs/Objc2.64bit.obj.macho-x86_64 b/test/tools/llvm-objdump/X86/Inputs/Objc2.64bit.obj.macho-x86_64 new file mode 100644 index 0000000000000000000000000000000000000000..5734780a1643af14c2444a66d288590ba556da5d GIT binary patch literal 13580 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 cl::desc("Print the info for Mach-O objects in " "non-verbose or numeric form (requires -macho)")); +cl::opt + llvm::ObjcMetaData("objc-meta-data", + cl::desc("Print the Objective-C runtime meta data for " + "Mach-O files (requires -macho)")); + cl::opt llvm::DisSymName( "dis-symname", cl::desc("disassemble just this symbol's instructions (requires -macho")); @@ -1099,8 +1104,8 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr); break; case MachO::S_16BYTE_LITERALS: - DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr); - break; + DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr); + break; case MachO::S_LITERAL_POINTERS: DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr, !NoLeadingAddr); @@ -1179,6 +1184,8 @@ static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { return true; } +static void printObjcMetaData(MachOObjectFile *O, bool verbose); + // ProcessMachO() is passed a single opened Mach-O file, which may be an // archive member and or in a slice of a universal file. It prints the // the file name and header info and then processes it according to the @@ -1191,7 +1198,8 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, // UniversalHeaders or ArchiveHeaders. if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || - DylibsUsed || DylibId || (DumpSections.size() != 0 && !Raw)) { + DylibsUsed || DylibId || ObjcMetaData || + (DumpSections.size() != 0 && !Raw)) { outs() << Filename; if (!ArchiveMemberName.empty()) outs() << '(' << ArchiveMemberName << ')'; @@ -1228,6 +1236,8 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, printMachOUnwindInfo(MachOOF); if (PrivateHeaders) printMachOFileHeader(MachOOF); + if (ObjcMetaData) + printObjcMetaData(MachOOF, !NonVerbose); if (ExportsTrie) printExportsTrie(MachOOF); if (Rebase) @@ -2417,8 +2427,11 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset, // get_symbol_64() returns the name of a symbol (or nullptr) and the address of // the symbol indirectly through n_value. Based on the relocation information // for the specified section offset in the specified section reference. +// If no relocation information is found and a non-zero ReferenceValue for the +// symbol is passed, look up that address in the info's AddrMap. static const char *get_symbol_64(uint32_t sect_offset, SectionRef S, - DisassembleInfo *info, uint64_t &n_value) { + DisassembleInfo *info, uint64_t &n_value, + uint64_t ReferenceValue = 0) { n_value = 0; if (!info->verbose) return nullptr; @@ -2452,6 +2465,8 @@ static const char *get_symbol_64(uint32_t sect_offset, SectionRef S, const char *SymbolName = nullptr; if (reloc_found && isExtern) { Symbol.getAddress(n_value); + if (n_value == UnknownAddressOrSize) + n_value = 0; StringRef name; Symbol.getName(name); if (!name.empty()) { @@ -2469,13 +2484,10 @@ static const char *get_symbol_64(uint32_t sect_offset, SectionRef S, // // NOTE: need add passing the database_offset to this routine. - // TODO: We did not find an external relocation entry so look up the - // ReferenceValue as an address of a symbol and if found return that symbol's - // name. - // - // NOTE: need add passing the ReferenceValue to this routine. Then that code - // would simply be this: - // SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap); + // We did not find an external relocation entry so look up the ReferenceValue + // as an address of a symbol and if found return that symbol's name. + if (ReferenceValue != 0) + SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap); return SymbolName; } @@ -2515,6 +2527,89 @@ struct class_ro64_t { uint64_t baseProperties; // const struct objc_property_list (64-bit pointer) }; +/* Values for class_ro64_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 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 protocol_list64_t { + uint64_t count; /* uintptr_t (a 64-bit value) */ + /* struct protocol64_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 ivar_list64_t { + uint32_t entsize; + uint32_t count; + /* struct ivar_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 objc_property_list64 { + uint32_t entsize; + uint32_t count; + /* struct objc_property 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 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 objc_image_info64 { + 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) */ +}; + inline void swapStruct(struct cfstring64_t &cfs) { sys::swapByteOrder(cfs.isa); sys::swapByteOrder(cfs.flags); @@ -2544,6 +2639,74 @@ inline void swapStruct(struct class_ro64_t &cro) { sys::swapByteOrder(cro.baseProperties); } +inline void swapStruct(struct method_list64_t &ml) { + sys::swapByteOrder(ml.entsize); + sys::swapByteOrder(ml.count); +} + +inline void swapStruct(struct method64_t &m) { + sys::swapByteOrder(m.name); + sys::swapByteOrder(m.types); + sys::swapByteOrder(m.imp); +} + +inline void swapStruct(struct protocol_list64_t &pl) { + sys::swapByteOrder(pl.count); +} + +inline void swapStruct(struct protocol64_t &p) { + sys::swapByteOrder(p.isa); + sys::swapByteOrder(p.name); + sys::swapByteOrder(p.protocols); + sys::swapByteOrder(p.instanceMethods); + sys::swapByteOrder(p.classMethods); + sys::swapByteOrder(p.optionalInstanceMethods); + sys::swapByteOrder(p.optionalClassMethods); + sys::swapByteOrder(p.instanceProperties); +} + +inline void swapStruct(struct ivar_list64_t &il) { + sys::swapByteOrder(il.entsize); + sys::swapByteOrder(il.count); +} + +inline void swapStruct(struct ivar64_t &i) { + sys::swapByteOrder(i.offset); + sys::swapByteOrder(i.name); + sys::swapByteOrder(i.type); + sys::swapByteOrder(i.alignment); + sys::swapByteOrder(i.size); +} + +inline void swapStruct(struct objc_property_list64 &pl) { + sys::swapByteOrder(pl.entsize); + sys::swapByteOrder(pl.count); +} + +inline void swapStruct(struct objc_property64 &op) { + sys::swapByteOrder(op.name); + sys::swapByteOrder(op.attributes); +} + +inline void swapStruct(struct category64_t &c) { + sys::swapByteOrder(c.name); + sys::swapByteOrder(c.cls); + sys::swapByteOrder(c.instanceMethods); + sys::swapByteOrder(c.classMethods); + sys::swapByteOrder(c.protocols); + sys::swapByteOrder(c.instanceProperties); +} + +inline void swapStruct(struct objc_image_info64 &o) { + sys::swapByteOrder(o.version); + sys::swapByteOrder(o.flags); +} + +inline void swapStruct(struct message_ref64 &mr) { + sys::swapByteOrder(mr.imp); + sys::swapByteOrder(mr.sel); +} + static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue, struct DisassembleInfo *info); @@ -2652,6 +2815,1060 @@ static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue, return n_value; } +static const SectionRef get_section(MachOObjectFile *O, const char *segname, + const char *sectname) { + for (const SectionRef &Section : O->sections()) { + StringRef SectName; + Section.getName(SectName); + DataRefImpl Ref = Section.getRawDataRefImpl(); + StringRef SegName = O->getSectionFinalSegmentName(Ref); + if (SegName == segname && SectName == sectname) + return Section; + } + return SectionRef(); +} + +static void +walk_pointer_list_64(const char *listname, const SectionRef S, + MachOObjectFile *O, struct DisassembleInfo *info, + void (*func)(uint64_t, struct DisassembleInfo *info)) { + if (S == SectionRef()) + return; + + StringRef SectName; + S.getName(SectName); + DataRefImpl Ref = S.getRawDataRefImpl(); + StringRef SegName = O->getSectionFinalSegmentName(Ref); + outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; + + StringRef BytesStr; + S.getContents(BytesStr); + const char *Contents = reinterpret_cast(BytesStr.data()); + + for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) { + uint32_t left = S.getSize() - i; + uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t); + uint64_t p = 0; + memcpy(&p, Contents + i, size); + if (i + sizeof(uint64_t) > S.getSize()) + outs() << listname << " list pointer extends past end of (" << SegName + << "," << SectName << ") section\n"; + outs() << format("%016" PRIx64, S.getAddress() + i) << " "; + + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(p); + + uint64_t n_value = 0; + const char *name = get_symbol_64(i, S, info, n_value, p); + if (name == nullptr) + name = get_dyld_bind_info_symbolname(S.getAddress() + i, info); + + if (n_value != 0) { + outs() << format("0x%" PRIx64, n_value); + if (p != 0) + outs() << " + " << format("0x%" PRIx64, p); + } else + outs() << format("0x%" PRIx64, p); + if (name != nullptr) + outs() << " " << name; + outs() << "\n"; + + p += n_value; + if (func) + func(p, info); + } +} + +static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) { + uint32_t offset, left; + SectionRef S; + const char *layout_map; + + if (p == 0) + return; + layout_map = get_pointer_64(p, offset, left, S, info); + if (layout_map != nullptr) { + outs() << " layout map: "; + do { + outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " "; + left--; + layout_map++; + } while (*layout_map != '\0' && left != 0); + outs() << "\n"; + } +} + +static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info, + const char *indent) { + struct method_list64_t ml; + struct method64_t m; + const char *r; + uint32_t offset, xoffset, left, i; + SectionRef S, xS; + const char *name, *sym_name; + uint64_t n_value; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&ml, '\0', sizeof(struct method_list64_t)); + if (left < sizeof(struct method_list64_t)) { + memcpy(&ml, r, left); + outs() << " (method_list_t entends past the end of the section)\n"; + } else + memcpy(&ml, r, sizeof(struct method_list64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(ml); + outs() << indent << "\t\t entsize " << ml.entsize << "\n"; + outs() << indent << "\t\t count " << ml.count << "\n"; + + p += sizeof(struct method_list64_t); + offset += sizeof(struct method_list64_t); + for (i = 0; i < ml.count; i++) { + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&m, '\0', sizeof(struct method64_t)); + if (left < sizeof(struct method64_t)) { + memcpy(&ml, r, left); + outs() << indent << " (method_t entends past the end of the section)\n"; + } else + memcpy(&m, r, sizeof(struct method64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(m); + + outs() << indent << "\t\t name "; + sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S, + info, n_value, m.name); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (m.name != 0) + outs() << " + " << format("0x%" PRIx64, m.name); + } else + outs() << format("0x%" PRIx64, m.name); + name = get_pointer_64(m.name + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << indent << "\t\t types "; + sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S, + info, n_value, m.types); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (m.types != 0) + outs() << " + " << format("0x%" PRIx64, m.types); + } else + outs() << format("0x%" PRIx64, m.types); + name = get_pointer_64(m.types + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << indent << "\t\t imp "; + name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info, + n_value, m.imp); + if (info->verbose && name == nullptr) { + if (n_value != 0) { + outs() << format("0x%" PRIx64, n_value) << " "; + if (m.imp != 0) + outs() << "+ " << format("0x%" PRIx64, m.imp) << " "; + } else + outs() << format("0x%" PRIx64, m.imp) << " "; + } + if (name != nullptr) + outs() << name; + outs() << "\n"; + + p += sizeof(struct method64_t); + offset += sizeof(struct method64_t); + } +} + +static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) { + struct protocol_list64_t pl; + uint64_t q, n_value; + struct protocol64_t pc; + const char *r; + uint32_t offset, xoffset, left, i; + SectionRef S, xS; + const char *name, *sym_name; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&pl, '\0', sizeof(struct protocol_list64_t)); + if (left < sizeof(struct protocol_list64_t)) { + memcpy(&pl, r, left); + outs() << " (protocol_list_t entends past the end of the section)\n"; + } else + memcpy(&pl, r, sizeof(struct protocol_list64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(pl); + outs() << " count " << pl.count << "\n"; + + p += sizeof(struct protocol_list64_t); + offset += sizeof(struct protocol_list64_t); + for (i = 0; i < pl.count; i++) { + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + q = 0; + if (left < sizeof(uint64_t)) { + memcpy(&q, r, left); + outs() << " (protocol_t * entends past the end of the section)\n"; + } else + memcpy(&q, r, sizeof(uint64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(q); + + outs() << "\t\t list[" << i << "] "; + sym_name = get_symbol_64(offset, S, info, n_value, q); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (q != 0) + outs() << " + " << format("0x%" PRIx64, q); + } else + outs() << format("0x%" PRIx64, q); + outs() << " (struct protocol_t *)\n"; + + r = get_pointer_64(q + n_value, offset, left, S, info); + if (r == nullptr) + return; + memset(&pc, '\0', sizeof(struct protocol64_t)); + if (left < sizeof(struct protocol64_t)) { + memcpy(&pc, r, left); + outs() << " (protocol_t entends past the end of the section)\n"; + } else + memcpy(&pc, r, sizeof(struct protocol64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(pc); + + outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n"; + + outs() << "\t\t\t name "; + sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S, + info, n_value, pc.name); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (pc.name != 0) + outs() << " + " << format("0x%" PRIx64, pc.name); + } else + outs() << format("0x%" PRIx64, pc.name); + name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n"; + + outs() << "\t\t instanceMethods "; + sym_name = + get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods), + S, info, n_value, pc.instanceMethods); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (pc.instanceMethods != 0) + outs() << " + " << format("0x%" PRIx64, pc.instanceMethods); + } else + outs() << format("0x%" PRIx64, pc.instanceMethods); + outs() << " (struct method_list_t *)\n"; + if (pc.instanceMethods + n_value != 0) + print_method_list64_t(pc.instanceMethods + n_value, info, "\t"); + + outs() << "\t\t classMethods "; + sym_name = + get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S, + info, n_value, pc.classMethods); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (pc.classMethods != 0) + outs() << " + " << format("0x%" PRIx64, pc.classMethods); + } else + outs() << format("0x%" PRIx64, pc.classMethods); + outs() << " (struct method_list_t *)\n"; + if (pc.classMethods + n_value != 0) + print_method_list64_t(pc.classMethods + n_value, info, "\t"); + + outs() << "\t optionalInstanceMethods " + << format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n"; + outs() << "\t optionalClassMethods " + << format("0x%" PRIx64, pc.optionalClassMethods) << "\n"; + outs() << "\t instanceProperties " + << format("0x%" PRIx64, pc.instanceProperties) << "\n"; + + p += sizeof(uint64_t); + offset += sizeof(uint64_t); + } +} + +static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) { + struct ivar_list64_t il; + struct ivar64_t i; + const char *r; + uint32_t offset, xoffset, left, j; + SectionRef S, xS; + const char *name, *sym_name, *ivar_offset_p; + uint64_t ivar_offset, n_value; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&il, '\0', sizeof(struct ivar_list64_t)); + if (left < sizeof(struct ivar_list64_t)) { + memcpy(&il, r, left); + outs() << " (ivar_list_t entends past the end of the section)\n"; + } else + memcpy(&il, r, sizeof(struct ivar_list64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(il); + outs() << " entsize " << il.entsize << "\n"; + outs() << " count " << il.count << "\n"; + + p += sizeof(struct ivar_list64_t); + offset += sizeof(struct ivar_list64_t); + for (j = 0; j < il.count; j++) { + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&i, '\0', sizeof(struct ivar64_t)); + if (left < sizeof(struct ivar64_t)) { + memcpy(&i, r, left); + outs() << " (ivar_t entends past the end of the section)\n"; + } else + memcpy(&i, r, sizeof(struct ivar64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(i); + + outs() << "\t\t\t offset "; + sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S, + info, n_value, i.offset); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (i.offset != 0) + outs() << " + " << format("0x%" PRIx64, i.offset); + } else + outs() << format("0x%" PRIx64, i.offset); + ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info); + if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) { + memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(ivar_offset); + outs() << " " << ivar_offset << "\n"; + } else + outs() << "\n"; + + outs() << "\t\t\t name "; + sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info, + n_value, i.name); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (i.name != 0) + outs() << " + " << format("0x%" PRIx64, i.name); + } else + outs() << format("0x%" PRIx64, i.name); + name = get_pointer_64(i.name + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << "\t\t\t type "; + sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info, + n_value, i.name); + name = get_pointer_64(i.type + n_value, xoffset, left, xS, info); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (i.type != 0) + outs() << " + " << format("0x%" PRIx64, i.type); + } else + outs() << format("0x%" PRIx64, i.type); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << "\t\t\talignment " << i.alignment << "\n"; + outs() << "\t\t\t size " << i.size << "\n"; + + p += sizeof(struct ivar64_t); + offset += sizeof(struct ivar64_t); + } +} + +static void print_objc_property_list64(uint64_t p, + struct DisassembleInfo *info) { + struct objc_property_list64 opl; + struct objc_property64 op; + const char *r; + uint32_t offset, xoffset, left, j; + SectionRef S, xS; + const char *name, *sym_name; + uint64_t n_value; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&opl, '\0', sizeof(struct objc_property_list64)); + if (left < sizeof(struct objc_property_list64)) { + memcpy(&opl, r, left); + outs() << " (objc_property_list entends past the end of the section)\n"; + } else + memcpy(&opl, r, sizeof(struct objc_property_list64)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(opl); + outs() << " entsize " << opl.entsize << "\n"; + outs() << " count " << opl.count << "\n"; + + p += sizeof(struct objc_property_list64); + offset += sizeof(struct objc_property_list64); + for (j = 0; j < opl.count; j++) { + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&op, '\0', sizeof(struct objc_property64)); + if (left < sizeof(struct objc_property64)) { + memcpy(&op, r, left); + outs() << " (objc_property entends past the end of the section)\n"; + } else + memcpy(&op, r, sizeof(struct objc_property64)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(op); + + outs() << "\t\t\t name "; + sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S, + info, n_value, op.name); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (op.name != 0) + outs() << " + " << format("0x%" PRIx64, op.name); + } else + outs() << format("0x%" PRIx64, op.name); + name = get_pointer_64(op.name + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << "\t\t\tattributes "; + sym_name = + get_symbol_64(offset + offsetof(struct objc_property64, attributes), S, + info, n_value, op.attributes); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (op.attributes != 0) + outs() << " + " << format("0x%" PRIx64, op.attributes); + } else + outs() << format("0x%" PRIx64, op.attributes); + name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + p += sizeof(struct objc_property64); + offset += sizeof(struct objc_property64); + } +} + +static void print_class_ro64_t(uint64_t p, struct DisassembleInfo *info, + bool &is_meta_class) { + struct class_ro64_t cro; + const char *r; + uint32_t offset, xoffset, left; + SectionRef S, xS; + const char *name, *sym_name; + uint64_t n_value; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr || left < sizeof(struct class_ro64_t)) + return; + memset(&cro, '\0', sizeof(struct class_ro64_t)); + if (left < sizeof(struct class_ro64_t)) { + memcpy(&cro, r, left); + outs() << " (class_ro_t entends past the end of the section)\n"; + } else + memcpy(&cro, r, sizeof(struct class_ro64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(cro); + outs() << " flags " << format("0x%" PRIx32, cro.flags); + if (cro.flags & RO_META) + outs() << " RO_META"; + if (cro.flags & RO_ROOT) + outs() << " RO_ROOT"; + if (cro.flags & RO_HAS_CXX_STRUCTORS) + outs() << " RO_HAS_CXX_STRUCTORS"; + outs() << "\n"; + outs() << " instanceStart " << cro.instanceStart << "\n"; + outs() << " instanceSize " << cro.instanceSize << "\n"; + outs() << " reserved " << format("0x%" PRIx32, cro.reserved) + << "\n"; + outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout) + << "\n"; + print_layout_map64(cro.ivarLayout, info); + + outs() << " name "; + sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S, + info, n_value, cro.name); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (cro.name != 0) + outs() << " + " << format("0x%" PRIx64, cro.name); + } else + outs() << format("0x%" PRIx64, cro.name); + name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << " baseMethods "; + sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods), + S, info, n_value, cro.baseMethods); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (cro.baseMethods != 0) + outs() << " + " << format("0x%" PRIx64, cro.baseMethods); + } else + outs() << format("0x%" PRIx64, cro.baseMethods); + outs() << " (struct method_list_t *)\n"; + if (cro.baseMethods + n_value != 0) + print_method_list64_t(cro.baseMethods + n_value, info, ""); + + outs() << " baseProtocols "; + sym_name = + get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S, + info, n_value, cro.baseProtocols); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (cro.baseProtocols != 0) + outs() << " + " << format("0x%" PRIx64, cro.baseProtocols); + } else + outs() << format("0x%" PRIx64, cro.baseProtocols); + outs() << "\n"; + if (cro.baseProtocols + n_value != 0) + print_protocol_list64_t(cro.baseProtocols + n_value, info); + + outs() << " ivars "; + sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S, + info, n_value, cro.baseProtocols); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (cro.ivars != 0) + outs() << " + " << format("0x%" PRIx64, cro.ivars); + } else + outs() << format("0x%" PRIx64, cro.ivars); + outs() << "\n"; + if (cro.ivars + n_value != 0) + print_ivar_list64_t(cro.ivars + n_value, info); + + outs() << " weakIvarLayout "; + sym_name = + get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S, + info, n_value, cro.weakIvarLayout); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (cro.weakIvarLayout != 0) + outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout); + } else + outs() << format("0x%" PRIx64, cro.weakIvarLayout); + outs() << "\n"; + print_layout_map64(cro.weakIvarLayout + n_value, info); + + outs() << " baseProperties "; + sym_name = + get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S, + info, n_value, cro.baseProperties); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (cro.baseProperties != 0) + outs() << " + " << format("0x%" PRIx64, cro.baseProperties); + } else + outs() << format("0x%" PRIx64, cro.baseProperties); + outs() << "\n"; + if (cro.baseProperties + n_value != 0) + print_objc_property_list64(cro.baseProperties + n_value, info); + + is_meta_class = (cro.flags & RO_META) ? true : false; +} + +static void print_class64_t(uint64_t p, struct DisassembleInfo *info) { + struct class64_t c; + const char *r; + uint32_t offset, left; + SectionRef S; + const char *name; + uint64_t isa_n_value, n_value; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr || left < sizeof(struct class64_t)) + return; + memset(&c, '\0', sizeof(struct class64_t)); + if (left < sizeof(struct class64_t)) { + memcpy(&c, r, left); + outs() << " (class_t entends past the end of the section)\n"; + } else + memcpy(&c, r, sizeof(struct class64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(c); + + outs() << " isa " << format("0x%" PRIx64, c.isa); + name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info, + isa_n_value, c.isa); + if (name != nullptr) + outs() << " " << name; + outs() << "\n"; + + outs() << " superclass " << format("0x%" PRIx64, c.superclass); + name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info, + n_value, c.superclass); + if (name != nullptr) + outs() << " " << name; + outs() << "\n"; + + outs() << " cache " << format("0x%" PRIx64, c.cache); + name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info, + n_value, c.cache); + if (name != nullptr) + outs() << " " << name; + outs() << "\n"; + + outs() << " vtable " << format("0x%" PRIx64, c.vtable); + name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info, + n_value, c.vtable); + if (name != nullptr) + outs() << " " << name; + outs() << "\n"; + + name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info, + n_value, c.data); + outs() << " data "; + if (n_value != 0) { + if (info->verbose && name != nullptr) + outs() << name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.data != 0) + outs() << " + " << format("0x%" PRIx64, c.data); + } else + outs() << format("0x%" PRIx64, c.data); + outs() << " (struct class_ro_t *)"; + + // This is a Swift class if some of the low bits of the pointer are set. + if ((c.data + n_value) & 0x7) + outs() << " Swift class"; + outs() << "\n"; + bool is_meta_class = true; + print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class); + + if (is_meta_class == false) { + outs() << "Meta Class\n"; + print_class64_t(c.isa + isa_n_value, info); + } +} + +static void print_category64_t(uint64_t p, struct DisassembleInfo *info) { + struct category64_t c; + const char *r; + uint32_t offset, xoffset, left; + SectionRef S, xS; + const char *name, *sym_name; + uint64_t n_value; + + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&c, '\0', sizeof(struct category64_t)); + if (left < sizeof(struct category64_t)) { + memcpy(&c, r, left); + outs() << " (category_t entends past the end of the section)\n"; + } else + memcpy(&c, r, sizeof(struct category64_t)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(c); + + outs() << " name "; + sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S, + info, n_value, c.name); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.name != 0) + outs() << " + " << format("0x%" PRIx64, c.name); + } else + outs() << format("0x%" PRIx64, c.name); + name = get_pointer_64(c.name + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + outs() << " cls "; + sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info, + n_value, c.cls); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.cls != 0) + outs() << " + " << format("0x%" PRIx64, c.cls); + } else + outs() << format("0x%" PRIx64, c.cls); + outs() << "\n"; + if (c.cls + n_value != 0) + print_class64_t(c.cls + n_value, info); + + outs() << " instanceMethods "; + sym_name = + get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S, + info, n_value, c.instanceMethods); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.instanceMethods != 0) + outs() << " + " << format("0x%" PRIx64, c.instanceMethods); + } else + outs() << format("0x%" PRIx64, c.instanceMethods); + outs() << "\n"; + if (c.instanceMethods + n_value != 0) + print_method_list64_t(c.instanceMethods + n_value, info, ""); + + outs() << " classMethods "; + sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods), + S, info, n_value, c.classMethods); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.classMethods != 0) + outs() << " + " << format("0x%" PRIx64, c.classMethods); + } else + outs() << format("0x%" PRIx64, c.classMethods); + outs() << "\n"; + if (c.classMethods + n_value != 0) + print_method_list64_t(c.classMethods + n_value, info, ""); + + outs() << " protocols "; + sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S, + info, n_value, c.protocols); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.protocols != 0) + outs() << " + " << format("0x%" PRIx64, c.protocols); + } else + outs() << format("0x%" PRIx64, c.protocols); + outs() << "\n"; + if (c.protocols + n_value != 0) + print_protocol_list64_t(c.protocols + n_value, info); + + outs() << "instanceProperties "; + sym_name = + get_symbol_64(offset + offsetof(struct category64_t, instanceProperties), + S, info, n_value, c.instanceProperties); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (c.instanceProperties != 0) + outs() << " + " << format("0x%" PRIx64, c.instanceProperties); + } else + outs() << format("0x%" PRIx64, c.instanceProperties); + outs() << "\n"; + if (c.instanceProperties + n_value != 0) + print_objc_property_list64(c.instanceProperties + n_value, info); +} + +static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) { + uint32_t i, left, offset, xoffset; + uint64_t p, n_value; + struct message_ref64 mr; + const char *name, *sym_name; + const char *r; + SectionRef xS; + + if (S == SectionRef()) + return; + + StringRef SectName; + S.getName(SectName); + DataRefImpl Ref = S.getRawDataRefImpl(); + StringRef SegName = info->O->getSectionFinalSegmentName(Ref); + outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; + offset = 0; + for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) { + p = S.getAddress() + i; + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&mr, '\0', sizeof(struct message_ref64)); + if (left < sizeof(struct message_ref64)) { + memcpy(&mr, r, left); + outs() << " (message_ref entends past the end of the section)\n"; + } else + memcpy(&mr, r, sizeof(struct message_ref64)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(mr); + + outs() << " imp "; + name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info, + n_value, mr.imp); + if (n_value != 0) { + outs() << format("0x%" PRIx64, n_value) << " "; + if (mr.imp != 0) + outs() << "+ " << format("0x%" PRIx64, mr.imp) << " "; + } else + outs() << format("0x%" PRIx64, mr.imp) << " "; + if (name != nullptr) + outs() << " " << name; + outs() << "\n"; + + outs() << " sel "; + sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S, + info, n_value, mr.sel); + if (n_value != 0) { + if (info->verbose && sym_name != nullptr) + outs() << sym_name; + else + outs() << format("0x%" PRIx64, n_value); + if (mr.sel != 0) + outs() << " + " << format("0x%" PRIx64, mr.sel); + } else + outs() << format("0x%" PRIx64, mr.sel); + name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info); + if (name != nullptr) + outs() << format(" %.*s", left, name); + outs() << "\n"; + + offset += sizeof(struct message_ref64); + } +} + +static void print_image_info64(SectionRef S, struct DisassembleInfo *info) { + uint32_t left, offset, swift_version; + uint64_t p; + struct objc_image_info64 o; + const char *r; + + StringRef SectName; + S.getName(SectName); + DataRefImpl Ref = S.getRawDataRefImpl(); + StringRef SegName = info->O->getSectionFinalSegmentName(Ref); + outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; + p = S.getAddress(); + r = get_pointer_64(p, offset, left, S, info); + if (r == nullptr) + return; + memset(&o, '\0', sizeof(struct objc_image_info64)); + if (left < sizeof(struct objc_image_info64)) { + memcpy(&o, r, left); + outs() << " (objc_image_info entends past the end of the section)\n"; + } else + memcpy(&o, r, sizeof(struct objc_image_info64)); + if (info->O->isLittleEndian() != sys::IsLittleEndianHost) + swapStruct(o); + outs() << " version " << o.version << "\n"; + outs() << " flags " << format("0x%" PRIx32, o.flags); + if (o.flags & OBJC_IMAGE_IS_REPLACEMENT) + outs() << " OBJC_IMAGE_IS_REPLACEMENT"; + if (o.flags & OBJC_IMAGE_SUPPORTS_GC) + outs() << " OBJC_IMAGE_SUPPORTS_GC"; + swift_version = (o.flags >> 8) & 0xff; + if (swift_version != 0) { + if (swift_version == 1) + outs() << " Swift 1.0"; + else if (swift_version == 2) + outs() << " Swift 1.1"; + else + outs() << " unknown future Swift version (" << swift_version << ")"; + } + outs() << "\n"; +} + +static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) { + SymbolAddressMap AddrMap; + if (verbose) + CreateSymbolAddressMap(O, &AddrMap); + + std::vector Sections; + for (const SectionRef &Section : O->sections()) { + StringRef SectName; + Section.getName(SectName); + Sections.push_back(Section); + } + + struct DisassembleInfo info; + // Set up the block of info used by the Symbolizer call backs. + info.verbose = verbose; + info.O = O; + info.AddrMap = &AddrMap; + info.Sections = &Sections; + info.class_name = nullptr; + info.selector_name = nullptr; + info.method = nullptr; + info.demangled_name = nullptr; + info.bindtable = nullptr; + info.adrp_addr = 0; + info.adrp_inst = 0; + + const SectionRef CL = get_section(O, "__OBJC2", "__class_list"); + if (CL != SectionRef()) { + info.S = CL; + walk_pointer_list_64("class", CL, O, &info, print_class64_t); + } else { + const SectionRef CL = get_section(O, "__DATA", "__objc_classlist"); + info.S = CL; + walk_pointer_list_64("class", CL, O, &info, print_class64_t); + } + + const SectionRef CR = get_section(O, "__OBJC2", "__class_refs"); + if (CR != SectionRef()) { + info.S = CR; + walk_pointer_list_64("class refs", CR, O, &info, nullptr); + } else { + const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs"); + info.S = CR; + walk_pointer_list_64("class refs", CR, O, &info, nullptr); + } + + const SectionRef SR = get_section(O, "__OBJC2", "__super_refs"); + if (SR != SectionRef()) { + info.S = SR; + walk_pointer_list_64("super refs", SR, O, &info, nullptr); + } else { + const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs"); + info.S = SR; + walk_pointer_list_64("super refs", SR, O, &info, nullptr); + } + + const SectionRef CA = get_section(O, "__OBJC2", "__category_list"); + if (CA != SectionRef()) { + info.S = CA; + walk_pointer_list_64("category", CA, O, &info, print_category64_t); + } else { + const SectionRef CA = get_section(O, "__DATA", "__objc_catlist"); + info.S = CA; + walk_pointer_list_64("category", CA, O, &info, print_category64_t); + } + + const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list"); + if (PL != SectionRef()) { + info.S = PL; + walk_pointer_list_64("protocol", PL, O, &info, nullptr); + } else { + const SectionRef PL = get_section(O, "__DATA", "__objc_protolist"); + info.S = PL; + walk_pointer_list_64("protocol", PL, O, &info, nullptr); + } + + const SectionRef MR = get_section(O, "__OBJC2", "__message_refs"); + if (MR != SectionRef()) { + info.S = MR; + print_message_refs64(MR, &info); + } else { + const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs"); + info.S = MR; + print_message_refs64(MR, &info); + } + + const SectionRef II = get_section(O, "__OBJC2", "__image_info"); + if (II != SectionRef()) { + info.S = II; + print_image_info64(II, &info); + } else { + const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo"); + info.S = II; + print_image_info64(II, &info); + } +} + +static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) { + outs() << "Printing Objc2 32-bit MetaData not yet supported\n"; +} + +static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) { + const SectionRef S = get_section(O, "__OBJC", "__module_info"); + if (S != SectionRef()) { + outs() << "Printing Objc1 32-bit MetaData not yet supported\n"; + return true; + } + return false; +} + +static void printObjcMetaData(MachOObjectFile *O, bool verbose) { + if (O->is64Bit()) + printObjc2_64bit_MetaData(O, verbose); + else { + MachO::mach_header H; + H = O->getHeader(); + if (H.cputype == MachO::CPU_TYPE_ARM) + printObjc2_32bit_MetaData(O, verbose); + else { + // This is the 32-bit non-arm cputype case. Which is normally + // the first Objective-C ABI. But it may be the case of a + // binary for the iOS simulator which is the second Objective-C + // ABI. In that case printObjc1_32bit_MetaData() will determine that + // and return false. + if (printObjc1_32bit_MetaData(O, verbose) == false) + printObjc2_32bit_MetaData(O, verbose); + } + } +} + // GuessLiteralPointer returns a string which for the item in the Mach-O file // for the address passed in as ReferenceValue for printing as a comment with // the instruction and also returns the corresponding type of that item diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 83f135bca1a..71de8adca70 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -896,6 +896,7 @@ int main(int argc, char **argv) { && !(InfoPlist && MachOOpt) && !(DylibsUsed && MachOOpt) && !(DylibId && MachOOpt) + && !(ObjcMetaData && MachOOpt) && !(DumpSections.size() != 0 && MachOOpt)) { cl::PrintHelpMessage(); return 2; diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index 5d0099b18b0..bde72e004a1 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -1,4 +1,3 @@ -//===-- llvm-objdump.h ----------------------------------------------------===// // // The LLVM Compiler Infrastructure // @@ -44,6 +43,7 @@ extern cl::opt LinkOptHints; extern cl::opt InfoPlist; extern cl::opt DylibsUsed; extern cl::opt DylibId; +extern cl::opt ObjcMetaData; extern cl::opt DisSymName; extern cl::opt NonVerbose; extern cl::opt Relocations;